背景
作为一家搜索引擎公司,我们会很倚赖 ES
帮忙处理包括文章召回,数据源划分,实体、标签管理等任务,而且都收到了不错的结果。
最近我们需要对行业知识库进行建模,其中可能会涉及到实体匹配、模糊搜索、向量搜索等多种召回和算分方式,最终我们选择了通过 ES 7.X
(最终选择 7.10)里的新功能,Dense vector 帮忙一起完成这部分的需求。
技术选型
解决方案需求
- 支持向量搜索
- 支持多维度筛选、过滤
- 吞吐速率
- 学习、使用成本
- 运维成本
使用场景设计
- 离线数据准备
- 在离线数据构建完成后,存入该引擎
- 引擎对数据中各字段进行索引
- 在线数据召回
- 根据
query
理解结果构建的query
语句进行数据召回 - 对结果进行一定的筛选
- 对结果进行一定的打分排序
- 根据
数据结构设计
在确定了数据的使用场景我们确定了数据结构中,大致会包含以下一些字段
- 唯一 id:用以做知识的去重和快速获取
- 实体、属性、取值:用来描述知识的具体内容
- 置信度:用来描述知识的可信度
- 分类 flag:知识主要分类及推荐 category 等
- 向量表示:作为知识相似性、相关性召回、打分的依据
- ref 信息:用来回溯解析/获取该知识的源信息
- 其他属性:包括生效、删除、修改时间等支持性的通用属性
解决方案对比
为了能支持上述的使用需求,我们对比了包括 ES
、Faiss
等多种解决方案。其中,Faiss
和 SPTAG
只是核心算法库,需要进行二次开发包装成服务;Milvus
的 1.x
版本中只能存储 id
和 向量
,不能完整的满足我们的使用需求;基于集群稳定性和可维护性等考虑,相对于后置插件的部署,我们更倾向于使用 ES
的原生功能,所以选择 ES
的原生向量搜索功能作为我们的最终选择。
对比参考:
种类 | 实现语言 | 客户端支持 | 多条件召回 | 学习成本 | 引入成本 | 运维成本 | 分布式 | 性能 | 社区 | 备注 |
---|---|---|---|---|---|---|---|---|---|---|
Elasticsearch | Java | Java/Python | yes | 低 | 低 | 中 | yes | 中 | 活跃 | 原生功能 |
Faiss | Python | Python | no | 中 | 高 | 高 | no | 高 | 一般 | 需要二次开发 |
Milvus | Python + GoLang | Python/Java/GoLang | no | 中 | 中 | 中 | no | 高 | 一般 | 1.x 功能不全 |
OpenDistro Elasticsearch KNN | Java + C++ | Java/Python | yes | 中 | 中 | 中 | yes | 中 | 一般 |