SpringBoot 基于向量搜索引擎及虹软人脸识别SDK的大规模人脸搜索

这篇具有很好参考价值的文章主要介绍了SpringBoot 基于向量搜索引擎及虹软人脸识别SDK的大规模人脸搜索。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

SpringBoot 基于向量搜索引擎及虹软人脸识别SDK的大规模向量数据搜索

在线环境demo

为了方便大家测试效果,开放了一个在线环境供大家测试并降低了识别门槛和难度,使得照片也可以通过筛选,大家使用前无比观看视频,按照视频方式操作。由于服务器昂贵,资源有限,生产环境的配置为2C 8G,所以服务比较慢用户体验一般,若想测试性能,请在本地部署

视频地址:https://www.bilibili.com/video/BV1YY4y147jz?spm_id_from=333.999.0.0

在线环境(演示):http://120.48.10.164:9528/ admin 123456

联系我:ycdtbs@163.com

Github: https://github.com/ycdtbs/massive_faceSearch/tree/main

在线环境说明

在线环境会收集大家数据,请勿上传敏感照片,项目测试数据集均来源于网络公开照片,利用Python脚本爬取,脚本存放于目录中

在线环境仅用于演示 请勿上传自己数据

在线环境仅用于演示 请勿上传自己数据

在线环境仅用于演示 请勿上传自己数据

在线环境仅用于演示 请勿上传自己数据

前言

​ 大四毕业时做毕业设计,用到了百度云人脸识别的API,当时制作了一个demo发到Bilibli上,之后不少同学来问我,于是制作了一个利用虹软SDK的人脸识别的包含人脸库管理的一套服务,一年半来有不少朋友前来咨询人脸识别相关的问题,由于博主本人工作业务不涉及这部分,所以一直无心研究。最近北京疫情在家有了一些时间,利用了几天时间完善了基于虹软的代码。

​ 首先说明一下上个版本的缺陷是什么,首先之前的人脸数据缓存在了Redis当中,当我们解析出特征值时,将数据缓存到redis中,进行逐个必对和判断,**优化的方式也只是单纯的利用多线程和虹软的人基本特征(性别、年龄)**等进行分库,几百个人脸时还好,在上千个人脸时就会出现非常明显的延迟,用户体验效率非常低,因此基于上个版本只满足部分同学的毕业设计、小组作业的场景。偶然在工作中了解到了向量搜索引擎,于是考虑是否可以结合虹软的人脸识别SDK提取特征向量,然后进行分析处理。由于这个demo主要是搭建一个大规模人脸搜索和识别服务的demo,因此没有工程化,系统设计的也比较冗余,没有详细的功能设计,基本是博主想到什么做什么。最后跪求一个 STAR 重要的事情说三遍 STAR STAR STAR

系统架构

SpringBoot 基于向量搜索引擎及虹软人脸识别SDK的大规模人脸搜索

功能设计

​ 系统功能模块较为简单,主要功能就是新增人脸人脸搜索两个功能,其中新增人脸使用页面上传和压缩包批量上传两个方式,压缩包上传时文件名称为用户名,下面主要说明人脸搜索的功能流程

Milvues

​ 在介绍前需要说明一下Mulvus

​ Milvus 向量数据库能够帮助用户轻松应对海量非结构化数据(图片 / 视频 / 语音 / 文本)检索。单节点 Milvus 可以在秒内完成十亿级的向量搜索

​ 因此虹软的SDK只能提取向量及对比的功能,在大规模人脸识别中,需要搜索引擎对于人脸数据进行初步筛选到一个较小的范围后在利用虹软的SDK进行测试,值得一提的是,博主多次测试后Milvues返回的匹配率足以满足人脸匹配的要求,Milvus的安装部署和使用文档参考 https://milvus.io/cn/docs/v2.0.x

特别说明的是虹软提取的数组是一个经过归一后的1032长度的byte数组,我们需要对数组进行转换,去除前8位的版本号,并将1024长度的byte转为256长度的float向量,这部分可以利用Arrays提供的方法进行转换,代码中也有相应的工具类

人脸上传(单张)

SpringBoot 基于向量搜索引擎及虹软人脸识别SDK的大规模人脸搜索

人脸上传(批量)

​ 批量上传采用本地打包压缩上传到服务器,后台进程进行解压,放到队列中处理,处理结果存储在ES数据库中,实时结果及处理进度通过Websocket发送至前台

SpringBoot 基于向量搜索引擎及虹软人脸识别SDK的大规模人脸搜索

人脸搜索

SpringBoot 基于向量搜索引擎及虹软人脸识别SDK的大规模人脸搜索

技术架构
前端框架

​ 前端使用了Vue admin temlate 及 Element UI

后端框架

​ 后端框架主要是SpringBoot

数据库
  • mysql:存储用户信息,所有的数据以Mysql数据为准
  • Elasticsearch:由于批量上传操作是异步的,用ES来收集日志并分析热点数据、成功数据、失败数据(当前版本未实现)
  • InfluxDB:用于涉及到数据源较多,事务处理过于麻烦,架构设计中以Mysql中的数据为准,以Mysql数据进行数据同步
  • 阿里云OSS:负责存储裁切后的人脸照片,负责前台展示及缓存失效时重新加载
  • Milvues:项目的核心数据库向量搜索引擎
中间件
  • ActiveMq:由于大规模人脸搜索服务需要大量的照片,一个个手动上传不现实,因此开发了批量上传的功能,需要ActiveMq进行异步上传
前后端交互
  • restful:前后端交互主要使用restful接口
  • websocket:负责将后端处理照片的过程及照片实时显示在前端
安装部署
前端
  • .env.development 文件配置后端交互地址,只需要修改所有的IP+端口 其他路径不要改变

    # just a flag
    ENV = 'development'
    # base api
    VUE_APP_BASE_API = 'http://127.0.0.1:8080/' 
    #VUE_APP_BASE_API = 'http://120.48.10.164:8080/'
    
    # uploadFile
    VUE_APP_BASE_API_UPFILE = 'http://127.0.0.1:8080/file/getImageUrl'
    
    VUE_APP_BASE_API_UPFILE_LIST = 'http://127.0.0.1:8080/file/getListImageUrl'
    
    VUE_APP_BASE_API_WEBSOCKET = 'ws://127.0.0.1:8080/api/pushMessage/'
    
    VUE_APP_BASE_API_UPFILE = 'http://120.48.10.164:8080/file/getImageUrl'
    
    #VUE_APP_BASE_API_UPFILE_LIST = 'http://120.48.10.164:8080/file/getListImageUrl'
    
    #VUE_APP_BASE_API_WEBSOCKET = 'ws://120.48.10.164:8080/api/pushMessage/'
    

    VUE_APP_BASE_API:后端服务接口

    VUE_APP_BASE_API_UPFILE:单个文件上传地址

    VUE_APP_BASE_API_UPFILE_LIST:文件列表上传地址

    VUE_APP_BASE_API_WEBSOCKET:Websocket地址

  • 运行

    npm install
    npm run dev
    服务端口:ip:9528
    
后端配置
  • application.yml 主要是服务地址
    • 修改Redis配置
    • 修改Mysql配置
    • 修改ActiveMq配置
    • 修改Milvues配置
    • 修改阿里云对象存储地址
    • uploadFile配置本地缓存路径,主要是压缩包上传时需要用到
  • FaceEngineConfig 类
    • 配置虹软SDK的APID、SK,引擎地址
服务
  • mysql
  • redis
  • activeMq
  • Elasticsearch(此版本不用安装)
  • InfluxDB(此版本不用安装)
  • Milvus
数据库
  • 执行face.sql
人脸数据
  • 利用python脚本自行爬取
核心方法
FaceEngineConfig 类

类的主要功能是配置faceEngine的认证配置信息

public  class FaceEngineConfig {
    public static final String APPID = "";
    public static final String SDKKEY = "";
    //public static final String SDKKEY = "";//linux
    public static final String LIB = "D:\\face_web\\ArcSoft_ArcFace_Java_Windows_x64_V3.0\\libs\\WIN64";
    //public static final String LIB = ""; // linux
    
}
FaceEnginePoolFactory 引擎对象工厂类

引擎对象工厂类,负责维护一个对象池

@Log4j2
@Component
public class FaceEnginePoolFactory extends BasePooledObjectFactory<FaceEngine> {
    /**
     * 在对象池中创建对象
     * @return
     * @throws Exception
     */
    @Override
    public FaceEngine create() throws Exception {
        FaceEngine faceEngine = new FaceEngine(FaceEngineConfig.LIB);
        //激活引擎
        int errorCode = faceEngine.activeOnline(FaceEngineConfig.APPID, FaceEngineConfig.SDKKEY);
        if (errorCode != ErrorInfo.MOK.getValue() && errorCode != ErrorInfo.MERR_ASF_ALREADY_ACTIVATED.getValue()) {
            System.out.println("引擎激活失败");
        }
        ActiveFileInfo activeFileInfo=new ActiveFileInfo();
        errorCode = faceEngine.getActiveFileInfo(activeFileInfo);
        if (errorCode != ErrorInfo.MOK.getValue() && errorCode != ErrorInfo.MERR_ASF_ALREADY_ACTIVATED.getValue()) {
            System.out.println("获取激活文件信息失败");
        }
        //引擎配置
        EngineConfiguration engineConfiguration = new EngineConfiguration();
        engineConfiguration.setDetectMode(DetectMode.ASF_DETECT_MODE_IMAGE);
        engineConfiguration.setDetectFaceOrientPriority(DetectOrient.ASF_OP_ALL_OUT);
        engineConfiguration.setDetectFaceMaxNum(10);
        engineConfiguration.setDetectFaceScaleVal(16);
        //功能配置
        FunctionConfiguration functionConfiguration = new FunctionConfiguration();
        functionConfiguration.setSupportAge(true);
        functionConfiguration.setSupportFace3dAngle(true);
        functionConfiguration.setSupportFaceDetect(true);
        functionConfiguration.setSupportFaceRecognition(true);
        functionConfiguration.setSupportGender(true);
        functionConfiguration.setSupportLiveness(true);
        functionConfiguration.setSupportIRLiveness(true);
        engineConfiguration.setFunctionConfiguration(functionConfiguration);
        //初始化引擎
        errorCode = faceEngine.init(engineConfiguration);

        if (errorCode != ErrorInfo.MOK.getValue()) {
            log.error("初始化引擎失败");
        }
        return faceEngine;

    }

    /**
     * 包装对象
     * @param faceEngine
     * @return
     */
    @Override
    public PooledObject<FaceEngine> wrap(FaceEngine faceEngine) {
        return new DefaultPooledObject<>(faceEngine);
    }
    /**
     * 销毁对象
     * @param faceEngine 对象池
     * @throws Exception 异常
     */
    @Override
    public void destroyObject(PooledObject<FaceEngine> faceEngine) throws Exception {
        super.destroyObject(faceEngine);
    }

    /**
     * 校验对象是否可用
     * @param faceEngine 对象池
     * @return 对象是否可用结果,boolean
     */
    @Override
    public boolean validateObject(PooledObject<FaceEngine> faceEngine) {
        return super.validateObject(faceEngine);
    }

    /**
     * 激活钝化的对象系列操作
     * @param faceEngine 对象池
     * @throws Exception 异常信息
     */
    @Override
    public void activateObject(PooledObject<FaceEngine> faceEngine) throws Exception {
        super.activateObject(faceEngine);
    }

    /**
     * 钝化未使用的对象
     * @param faceEngine 对象池
     * @throws Exception 异常信息
     */
    @Override
    public void passivateObject(PooledObject<FaceEngine> faceEngine) throws Exception {
        super.passivateObject(faceEngine);
    }

}

faceUtils 人脸识别工具类

核心的人脸识别类,负责提取特征值、截取人脸、特征值对比

public class faceUtils {
    private GenericObjectPool<FaceEngine> faceEngineGenericObjectPool;
    faceUtils(){
        // 对象池工厂
        FaceEnginePoolFactory personPoolFactory = new FaceEnginePoolFactory();
        // 对象池配置
        GenericObjectPoolConfig<FaceEngine> objectPoolConfig = new GenericObjectPoolConfig<>();
        objectPoolConfig.setMaxTotal(5);
        AbandonedConfig abandonedConfig = new AbandonedConfig();

        abandonedConfig.setRemoveAbandonedOnMaintenance(true); //在Maintenance的时候检查是否有泄漏

        abandonedConfig.setRemoveAbandonedOnBorrow(true); //borrow 的时候检查泄漏

        abandonedConfig.setRemoveAbandonedTimeout(10); //如果一个对象borrow之后10秒还没有返还给pool,认为是泄漏的对象

        // 对象池
        faceEngineGenericObjectPool = new GenericObjectPool<>(personPoolFactory, objectPoolConfig);
        faceEngineGenericObjectPool.setAbandonedConfig(abandonedConfig);
        faceEngineGenericObjectPool.setTimeBetweenEvictionRunsMillis(5000); //5秒运行一次维护任务
        log.info("引擎池开启成功");
    }
    /**
     * 人脸检测
     *
     * @param fileInputStream
     * @return
     */
    public  List<FaceInfo> faceFind(InputStream fileInputStream) throws IOException {
        FaceEngine faceEngine = null;
        try {
            faceEngine = faceEngineGenericObjectPool.borrowObject();
            ImageInfo imageInfo = getRGBData(fileInputStream);
            List<FaceInfo> faceInfoList = new ArrayList<FaceInfo>();
            int errorCode = faceEngine.detectFaces(imageInfo.getImageData(), imageInfo.getWidth(), imageInfo.getHeight(), imageInfo.getImageFormat(), faceInfoList);
            return faceInfoList;
        } catch (Exception e) {
            log.error("出现了异常");
            e.printStackTrace();
            return new ArrayList<FaceInfo>();
        } finally {
            fileInputStream.close();
            // 回收对象到对象池
            if (faceEngine != null) {
                faceEngineGenericObjectPool.returnObject(faceEngine);
            }
        }

    }

    /**
     * 人脸截取
     *
     * @param fileInputStream
     * @param rect
     * @return
     */
    public  String faceCrop(InputStream fileInputStream, Rect rect) {
        try {
            ByteArrayOutputStream stream = new ByteArrayOutputStream();
            BufferedImage bufImage = ImageIO.read(fileInputStream);
            int height = bufImage.getHeight();
            int width = bufImage.getWidth();
            int top = rect.getTop();
            int bottom = rect.getBottom();
            int left = rect.getLeft();
            int right = rect.getRight();
            //System.out.println(top + "-" + bottom + "-" + left + "-" + right);
            try {
                BufferedImage subimage = bufImage.getSubimage(left, top, right - left, bottom - left);
                ImageIO.write(subimage, "png", stream);
                String base64 = Base64.encode(stream.toByteArray());
                return base64;
            }catch (Exception e){
                return null;
            }finally {
                stream.close();
                fileInputStream.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {

        }
        return null;
    }

    /**
     * 人脸特征值提取
     */
    public byte[] faceFeature(InputStream fileInputStream,FaceInfo faceInfo) throws IOException {
        FaceEngine faceEngine = null;
        FaceFeature faceFeature = new FaceFeature();
        try {
            faceEngine = faceEngineGenericObjectPool.borrowObject();
            ImageInfo imageInfo = getRGBData(fileInputStream);
            int errorCode = faceEngine.extractFaceFeature(imageInfo.getImageData(), imageInfo.getWidth(), imageInfo.getHeight(), imageInfo.getImageFormat(), faceInfo, faceFeature);
            byte[] featureData = faceFeature.getFeatureData();
            return featureData;

        } catch (Exception e) {
            log.error("出现了异常");
            e.printStackTrace();
            return new byte[0];
        } finally {
            fileInputStream.close();
            // 回收对象到对象池
            if (faceEngine != null) {
                faceEngineGenericObjectPool.returnObject(faceEngine);
            }
        }
    }

    /**
     * 人脸对比
     */
    public float faceCompared(byte [] source,byte [] des) throws IOException {
        FaceEngine faceEngine = null;
        try {
            faceEngine = faceEngineGenericObjectPool.borrowObject();
            FaceFeature targetFaceFeature = new FaceFeature();
            targetFaceFeature.setFeatureData(source);
            FaceFeature sourceFaceFeature = new FaceFeature();
            sourceFaceFeature.setFeatureData(des);
            FaceSimilar faceSimilar = new FaceSimilar();
            faceEngine.compareFaceFeature(targetFaceFeature, sourceFaceFeature, faceSimilar);
            float score = faceSimilar.getScore();
            return score;
        } catch (Exception e) {
            log.error("出现了异常");
            e.printStackTrace();
            return 0;
        } finally {
            // 回收对象到对象池
            if (faceEngine != null) {
                faceEngineGenericObjectPool.returnObject(faceEngine);
            }
        }
    }
milvusOperateUtils Milvues工具类
public class milvusOperateUtils {
    private GenericObjectPool<MilvusServiceClient> milvusServiceClientGenericObjectPool;  // 管理链接对象的池子
    // https://milvus.io/cn/docs/v2.0.x/load_collection.md
    private final int MAX_POOL_SIZE = 5;

    private milvusOperateUtils() {
        // 私有构造方法创建一个池
        // 对象池工厂
        MilvusPoolFactory milvusPoolFactory = new MilvusPoolFactory();
        // 对象池配置
        GenericObjectPoolConfig<FaceEngine> objectPoolConfig = new GenericObjectPoolConfig<>();
        objectPoolConfig.setMaxTotal(8);
        AbandonedConfig abandonedConfig = new AbandonedConfig();

        abandonedConfig.setRemoveAbandonedOnMaintenance(true); //在Maintenance的时候检查是否有泄漏

        abandonedConfig.setRemoveAbandonedOnBorrow(true); //borrow 的时候检查泄漏

        abandonedConfig.setRemoveAbandonedTimeout(MAX_POOL_SIZE); //如果一个对象borrow之后10秒还没有返还给pool,认为是泄漏的对象

        // 对象池
        milvusServiceClientGenericObjectPool = new GenericObjectPool(milvusPoolFactory, objectPoolConfig);
        milvusServiceClientGenericObjectPool.setAbandonedConfig(abandonedConfig);
        milvusServiceClientGenericObjectPool.setTimeBetweenEvictionRunsMillis(5000); //5秒运行一次维护任务
        log.info("milvus 对象池创建成功 维护了" + MAX_POOL_SIZE + "个对象");
    }

    // 创建一个Collection 类似于创建关系型数据库中的一张表
    private void createCollection(String collection) {
        MilvusServiceClient milvusServiceClient = null;
        try {
            // 通过对象池管理对象
            milvusServiceClient = milvusServiceClientGenericObjectPool.borrowObject();
            FieldType fieldType1 = FieldType.newBuilder()
                    .withName(faceMilvus.Field.USER_NAME)
                    .withDescription("用户名")
                    .withDataType(DataType.Int64)
                    .build();
            FieldType fieldType2 = FieldType.newBuilder()
                    .withName(faceMilvus.Field.USER_CODE)
                    .withDescription("编号")
                    .withDataType(DataType.Int64)
                    .withPrimaryKey(true)
                    .withAutoID(false)
                    .build();
            FieldType fieldType3 = FieldType.newBuilder()
                    .withName(faceMilvus.Field.FEATURE)
                    .withDescription("特征向量")
                    .withDataType(DataType.FloatVector)
                    .withDimension(faceMilvus.FEATURE_DIM)
                    .build();
            CreateCollectionParam createCollectionReq = CreateCollectionParam.newBuilder()
                    .withCollectionName(collection)
                    .withDescription("人脸特征向量库")
                    .withShardsNum(2)
                    .addFieldType(fieldType2)
                    .addFieldType(fieldType1)
                    .addFieldType(fieldType3)
                    .build();
            R<RpcStatus> result = milvusServiceClient.createCollection(createCollectionReq);
            log.info("创建结果" + result.getStatus() + "0 为成功");

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 回收对象到对象池
            if (milvusServiceClient != null) {
                milvusServiceClientGenericObjectPool.returnObject(milvusServiceClient);
            }
        }


    }
    public void loadingLocation(String collection) {
        MilvusServiceClient milvusServiceClient = null;
        try {
            // 通过对象池管理对象
            milvusServiceClient = milvusServiceClientGenericObjectPool.borrowObject();
            R<RpcStatus> rpcStatusR = milvusServiceClient.loadCollection(
                    LoadCollectionParam.newBuilder()
                            .withCollectionName(collection)
                            .build());
            log.info("加载结果" + rpcStatusR);

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 回收对象到对象池
            if (milvusServiceClient != null) {
                milvusServiceClientGenericObjectPool.returnObject(milvusServiceClient);
            }
        }


    }
    public void freedLoaction(String collection) {
        MilvusServiceClient milvusServiceClient = null;
        try {
            // 通过对象池管理对象
            milvusServiceClient = milvusServiceClientGenericObjectPool.borrowObject();
            R<RpcStatus> rpcStatusR = milvusServiceClient.releaseCollection(
                    ReleaseCollectionParam.newBuilder()
                            .withCollectionName(collection)
                            .build());
            log.info("加载结果" + rpcStatusR);

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 回收对象到对象池
            if (milvusServiceClient != null) {
                milvusServiceClientGenericObjectPool.returnObject(milvusServiceClient);
            }
        }


    }

    // 删除一个Collection
    private void delCollection(String collection) {
        MilvusServiceClient milvusServiceClient = null;
        try {
            // 通过对象池管理对象
            milvusServiceClient = milvusServiceClientGenericObjectPool.borrowObject();
            R<RpcStatus> book = milvusServiceClient.dropCollection(
                    DropCollectionParam.newBuilder()
                            .withCollectionName(collection)
                            .build());
            log.info("删除" + book.getStatus() + " 0 为成功");

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 回收对象到对象池
            if (milvusServiceClient != null) {
                milvusServiceClientGenericObjectPool.returnObject(milvusServiceClient);
            }
        }


    }

    // 插入数据 和对应的字段相同
    public long insert(String collectionName, String partitionName, List<Long> userName, List<Long> userCode, List<List<Float>> feature) {
        MilvusServiceClient milvusServiceClient = null;
        try {
            // 通过对象池管理对象
            milvusServiceClient = milvusServiceClientGenericObjectPool.borrowObject();
            List<InsertParam.Field> fields = new ArrayList<>();
            fields.add(new InsertParam.Field(faceMilvus.Field.USER_NAME, DataType.Int64, userName));
            fields.add(new InsertParam.Field(faceMilvus.Field.USER_CODE, DataType.Int64, userCode));
            fields.add(new InsertParam.Field(faceMilvus.Field.FEATURE, DataType.FloatVector, feature));
            InsertParam insertParam = InsertParam.newBuilder()
                    .withCollectionName(collectionName)
                    .withPartitionName(partitionName)
                    .withFields(fields)
                    .build();
            R<MutationResult> insertResult = milvusServiceClient.insert(insertParam);
            if (insertResult.getStatus() == 0) {
                return insertResult.getData().getIDs().getIntId().getData(0);
            } else {
                log.error("特征值上传失败 加入失败队列稍后重试");
            }
        } catch (Exception e) {
            e.printStackTrace();
            return 0;

        } finally {
            // 回收对象到对象池
            if (milvusServiceClient != null) {
                milvusServiceClientGenericObjectPool.returnObject(milvusServiceClient);
            }
        }
        return 0;
    }

    // 根据向量搜索数据
    public List<?> searchByFeature(String collection,List<List<Float>> search_vectors) {
        MilvusServiceClient milvusServiceClient = null;
        try {
            // 通过对象池管理对象
            milvusServiceClient = milvusServiceClientGenericObjectPool.borrowObject();
            List<String> search_output_fields = Arrays.asList(faceMilvus.Field.USER_CODE);
            SearchParam searchParam = SearchParam.newBuilder()
                    .withCollectionName(collection)
                    .withPartitionNames(Arrays.asList("one"))
                    .withMetricType(MetricType.L2)
                    .withOutFields(search_output_fields)
                    .withTopK(faceMilvus.SEARCH_K)
                    .withVectors(search_vectors)
                    .withVectorFieldName(faceMilvus.Field.FEATURE)
                    .withParams(faceMilvus.SEARCH_PARAM)
                    .build();
            R<SearchResults> respSearch = milvusServiceClient.search(searchParam);
            if (respSearch.getStatus() == 0){
                SearchResultsWrapper wrapperSearch = new SearchResultsWrapper(respSearch.getData().getResults());
                List<?> fieldData = wrapperSearch.getFieldData(faceMilvus.Field.USER_CODE, 0);
                return fieldData;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return new ArrayList<>();

        } finally {
            // 回收对象到对象池
            if (milvusServiceClient != null) {
                milvusServiceClientGenericObjectPool.returnObject(milvusServiceClient);
            }
        }
        return new ArrayList<>();
    }

    public static void main(String[] args) {
        milvusOperateUtils milvusOperateUtils = new milvusOperateUtils();
        milvusOperateUtils.createCollection("face_home");
        //milvusOperateUtils.delCollection("");
    }
}
相关文档
虹软

https://ai.arcsoft.com.cn/

Milvus

https://milvus.io/cn/docs/v2.0.x/create_collection.md文章来源地址https://www.toymoban.com/news/detail-411217.html

到了这里,关于SpringBoot 基于向量搜索引擎及虹软人脸识别SDK的大规模人脸搜索的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • SpringBoot 使用 Elasticsearch 搜索引擎

    作者:禅与计算机程序设计艺术 Spring Boot 是由 Pivotal 团队提供的一套用于开发基于 Spring 框架的应用的工具包。其主要目标是通过提供简单易用的starter包来简化开发流程。Spring Boot 极大的地方在于其依赖自动配置,可以很好的满足开发人员的开发需求。Spring Boot 提供了数据访

    2024年02月09日
    浏览(49)
  • SpringBoot集成Elasticsearch搜索引擎

    Elasticsearch是一个基于Lucene的搜索引擎,它提供了实时、可扩展和可伸缩的搜索功能。Spring Boot是一个用于构建新Spring应用的起点,它旨在简化开发人员的工作,使其能够快速地构建可扩展的、可维护的应用程序。 在现代应用程序中,搜索功能是非常重要的。它可以帮助用户快

    2024年02月19日
    浏览(49)
  • 火山引擎云搜索服务升级云原生新架构;提供数十亿级分布式向量数据库能力

    从互联网发展伊始,搜索技术就绽放出了惊人的社会和经济价值。随着信息社会快速发展,数据呈爆炸式增长,搜索技术通过数据收集与处理,满足信息共享与快速检索的需求。 云搜索服务 ESCloud 是火山引擎提供的 完全托管在线分布式搜索服务 ,兼容 Elasticsearch、Kibana 等软

    2024年02月16日
    浏览(43)
  • springboot整合MeiliSearch轻量级搜索引擎

    一、Meilisearch与Easy Search点击进入官网了解,本文主要从小微型公司业务出发,选择meilisearch来作为项目的全文搜索引擎,还可以当成来mongodb来使用。 二、starter封装 1、项目结构展示 2、引入依赖包(我是有包统一管理的fastjson用的1.2.83,gson用的2.8.6) 3、yml参数读取代码参考

    2024年02月08日
    浏览(54)
  • SpringBoot封装Elasticsearch搜索引擎实现全文检索

    注:本文实现了Java对Elasticseach的分页检索/不分页检索的封装 ES就不用过多介绍了,直接上代码: 创建Store类(与ES字段对应,用于接收ES数据) Elasticsearch全文检索接口:不分页检索 Elasticsearch全文检索接口:分页检索 本文实现了Java对Elasticsearch搜索引擎全文检索的封装 传入

    2024年02月04日
    浏览(44)
  • 基于Boost的搜索引擎

    搜索引擎是指根据一定的策略、运用特定的计算机程序从互联网上采集信息,在对信息进行组织和处理后,为用户提供检索服务,将检索的相关信息展示给用户的系统。 国内有许多做搜索的公司:百度、搜狗、360搜索等等。 这些大型公司做的搜索引擎是全网搜索,背后也是

    2023年04月10日
    浏览(40)
  • 基于Hbase的搜索引擎

    实验 项目名称 基于Hbase的搜索引擎 实验方法与步骤 实验方法与步骤

    2024年02月07日
    浏览(29)
  • 基于AI的搜索引擎汇总

    目录 1.Consensus 2.SCOUT SEARCH 3.YOU.com 4.Perplexity Al 5.Phind 6.Opera One Search - Consensus - Evidence-Based Answers, Faster Consensus is a search engine that uses AI to find answers in scientific research. 一款基于AI的搜索引擎,助力科研的工具,搜索的时候建议使用英文搜索会更加准确,当然也可以使用中文,有时

    2024年02月05日
    浏览(44)
  • ES数据存储搜索引擎入门到整合Springboot一章直达

    前言 学习一门语言,我们从熟悉其语法开始,慢慢深入动手实践,并开始将其使用到对应的场景上,当我们遇到相应的问题,能够联想到使用该技术,并能够信手拈来的时候,才是我们真正掌握了一门技术或者语言的时候。学习的时候可以和其他学过的知识点相关联,如ES可

    2024年02月02日
    浏览(43)
  • 基于boost库的搜索引擎项目

    boost库是指一些为C++标准库提供扩展的程序库总称,但是boost网站中并没有为我们提供站内搜索功能,因此我们要想找到某一个类的用法还要一个个去找,因此我们这次的目的就是实现一个搜索引擎功能,提高我们获取知识的效率 比如百度,谷歌,360等,这些都是大型的搜索

    2024年03月14日
    浏览(90)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包