cover_image

Elasticsearch8实践: 新功能和特性解析

技术研发中心 众安技术团队
2024年06月04日 07:00


图片


    作者 |  李其霖


   前言  

目前,Elasticsearch最新的版本为8.13,而众安还在大量使用5.x版本。根据官方文档,ES8.x相对5.x查询和聚合分析的性能有了较大的提升,存储成本也可以降低约30%左右。除此之外,Elasticsearch8增加了向量KNN检索与RRF混排,Elasticsearch相关性引擎(ESRE), 快照(snapshot)检索,时序数据库(TSDB)等新特性。


另外,为降本增效,充分释放技术升级的红利,便利业务线快速升级。中间件搜索团队升级了二向箔(XSearch)搜索引擎服务平台,支持了ES8.x集群的接入和托管,以及低版本向ES8一键无感升级的功能。


一、背景介绍  

目前,公司主要使用的Elasticsearch的版本为5.x,还有少量的2.x版本的ES,而Elasticsearch最新的版本为8.12, 公司使用的主流Elasticsearch版本落后了最新技术三代以上。随着公司业务增长,老版本Elasticsearch集群中数据不断膨胀,导致查询变慢,超时现象不断增多。由于老版本集群的性能瓶颈,只能通过不断扩容应对数据增长,导致集群成本不断上升。


另外,随着大语言模型的发展,对于向量存储和向量检索能力的需求也在不断增长。 企业内部的知识库内容需要经过向量化和检索召回后,才能通过提示词工程集成大语言模型的语义理解和推理能力。


而Elasticsearch8(以下简写为ES8可以很好的满足公司业务对应检索性能,存储成本,向量存储和向量检索方面的需求。ES8相比老版本,显著地提升了检索的性能,降低了存储成本,并支持了向量存储,KNN检索和混合排序等新的功能特性。

 

二、性能提升 

Elasticsearch最新的版本为8.12,相比ES5.x版本,性价比有了很大的提升。


  •  搜索性能:提高30-50%的搜索性能。

  •  聚合性能:平均提高60-90%的聚合性能,部分聚合查询性能提升2~10倍。

  •  写入性能:提高20-30%的写入性能。

  •  存储成本:降低约20%左右的存储成本。

 

| 2.1 Range查询性能提升

官方压测ES8的Range查询响应时间相比ES7提升20%。

图片


ES8的Range query相比ES5的提升更明显。通过esrally压测工具的标准数据集压测结果显示,ES8相比ES5延迟降低约30%。

图片

 

| 2.2 Wildcard查询性能提升

ES7.9开始,加入了对 wildcard 类型的支持,旨在改善模糊匹配的查询效率和性能,特别是在处理大量文本数据时。这一新特性主要针对了之前版本中 wildcard 查询的性能问题,提供了更高效的方式来处理通配符和正则表达式的搜索需求。


我们来看下 wildcard 类型怎么使用:

首先定义一个 wildcard 类型的字段:

PUT my-index-000001{  "mappings": {    "properties": {      "my_wildcard": {        "type""wildcard"      }    }  }}



使用 wildcard 查询如下所示:

GET my-index-000001/_search{  "query": {    "wildcard": {      "my_wildcard""*quite*lengthy"    }  }}



查询效率

图片

注:这里省却了索引详细信息,只需知道是同一个索引的比对测试。 


综上所述,在模糊搜索字段字符串区分度很低的情况下 如:模糊查询单个数字,此时优化效率rt大概是之前的1/3左右,字段字符串区分度高的场景rt大概是之前的1/15左右,有明显效果。

 

| 2.3 聚合查询性能提升

ES8对于聚合查询性能有非常大的优化,很多metrics统计类型的聚合查询的相比ES5有10倍甚至百倍的提升。通过esrally压测工具的标准数据集压测结果显示,ES8相比ES5的聚合查询从原来的秒级响应提升到毫秒级,原来ES5需要用10多秒才能完成的聚合查询,ES8只需要10几毫秒就能完成。

图片

 


三、成本降低 

| 3.1 索引压缩

ES8使用了Lucene 9,Lucene9优化了压缩算法,降低了索引的大小,减少了磁盘IO,提升了索引和检索的性能:

图片


● match_only_text 类型字段存储下降~15%

● text 类型字段存储下降

● 应用日志测试有3.4% 大小的下降

● geo_point 索引速度提升10%-15%

 


| 3.2 合成文档内容(Synthetic _source)

老版本的ES需要保存用户原始的文档内容,这占用了大量的磁盘资源,在访问大量数据时产生的IO会往往会导致响应变慢,甚至超时。ES8支持从索引的字段值中(doc_values)合成原始文档的数据,从而显著的减少存储资源的占用,大概可以减少30%左右的存储成本。由于减少了写入的数据量,也可以显著提升数据写入的吞吐率。


目前支持Synthetic _source的字段包括:

boolean, byte, double, float, geo_point, half_float, integer, ip, keyword, long, scaled_float, short, text

 

不过,由于需要通过计算合成原始文档内容,因此会增加一些cpu的消耗,轻微的影响到查询的性能。同时合成出来的文档的字段顺序会和写入时不一样。但这点限制相对于带来的成本的降低是可以忽略的。

 

| 3.3 降低节点堆内存消耗

ES8显著降低了索引元数据的内存消耗,相同内存可以容纳的分片数量是老版本ES的10倍。将可以显著降低索引数量大,查询量少的ES集群的成本,如日志类的ES集群。

图片

 

四、功能特性 

| 4.1 向量KNN检索

使用AIGC大语言模型回答本地知识库问题时,往往需要通过向量KNN检索召回相关的知识库内容。众安目前使用ES8作为向量检索引擎。ES8使用HNSW算法实现近似的向量K近邻(KNN)检索。HNSW是一种基于层次方法,它通过建立多层的图结构来实现对向量的快速检索。每层都根据欧几里得距离计算节点之间的距离,并选择合适的节点进行连接。HNSW的构建速度较慢,但其查询速度非常快,且能够处理高维数据。HNSW适用于高维数据和高数据量的情况。

 

如下图所示,每一层的入口节点连接了(红色虚线)下一层的节点集合,从L(=2)层开始寻找红点的K(=1)邻近节点,通过L2的邻近节点导航到L1层,找到L1的邻近节点,如此迭代,最终找到L0层的绿色节点为红色节点的最终邻近节点。

图片

 

由于HNSW的分层实现了类似跳表索引的机制,可以大幅减少计算量,提升查询性能。


使用ES Query实现向量KNN检索的样例如下:

POST image-index/_search{  "knn": {    "field": "image-vector",    "query_vector": [-5, 9, -12],    "k": 10,"num_candidates": 100  }}
其中field:向量字段;query_vector: 查询向量; k:返回k个结果;num_candidates: 候选集数量。


除了应用于大语言模型的检索增强生成(RAG)应用的开发,其它类型的数据经过向量化后还可以应用于聚类分析和异常点分析。例如,金融信贷可以将用户的还款计划和实际还款数据向量化,分析有异常放款行为的用户。

 

| 4.2 Elastic Learned Sparse EncodeR

ELSER 是一种域外(out-of-domain)稀疏向量(Sparse Vector)预训练模型,这意味着它不需要对你自己的数据进行微调,可以开箱即用。相比TF-IDF或BM25等稀疏向量,ELSER提供了基于上下文含义和用户意图的搜索结果,而不是精确的关键字匹配。ELSER将索引和检索的文本扩展为词集合,这些词在不同的训练数据集中经常同时出现。这些词不一定是同义词,而是基于机器学习获得的关联词。不过ELSER目前还只支持英文,未来会推出支持中文的版本。


相比与大语言模型的密集向量(Dense Vector),ELSER稀疏向量检索速度更快,且在语义检索上也具备较好的性能。


使用ES Query实现ELSER稀疏向量检索的样例如下:

GET my_index/_search{  "query": {    "text_expansion": {      "ml.tokens": {        "model_id": ".elser_model_1",        "model_text": "Sample"      }    }  }}

 ELSER稀疏向量模型可以与大语言向量Embedding模型结合,用户提升知识库内容召回的准确率。

 

| 4.3 机器学习模型和自然语言理解(NLP)

ES8可以内置一些机器学习或者自然语言理解的NLP模型,在索引和检索的时候使用指定的模型进行分析,并可以通过混合排序参与Ranking打分。例如下图所示,ES8可以使用文本和图片的向量模型,生成对应的词向量或者图片的特征向量。由于是本地部署的模型,具有较好的性能,适合一些数据量大,对向量化性能要求高的场景。

图片

 

ES8还通过 HuggingFace 提供开箱即用型模型,提供一个可以快速启动的选项;此模型依靠的是一个不断壮大的领先语言模型社区。ES8可以从huggingface导入一些在ES集群中本地化部署的算法模型,然后在检索或者查询中可以指定模型进行计算。

图片


下面是一个使用导入的向量化模型对查询文本进行KNN检索的查询样例:

POST /docs_index/_search{   "knn": {    "field": "doc_part_vector",    "k": 5,    "num_candidates": 20,    "query_vector_builder": {      "text_embedding": {         "model_id": "<text-embedding-model-id>",         "model_text": "<query_string>"       }    }  }}

ES8集成的模型目前可以支持以下 NLP 任务:

1. 模型填空 Fill-mask

这是一种语言模型的任务,模型需要根据给定的上下文和一个被遮挡的词,来预测这个遮挡的词是什么。例如,给定句子 "I want to buy a [MASK] of milk.",模型需要预测遮挡的词是什么,比如 "bottle"。这项任务通常涉及对上下文进行理解和生成可能的词。

 

2. 命名实体识别 (NER)

用于从文本中识别出具有特定含义的实体,例如人名、地名、组织名、日期、货币等。NER任务通常涉及识别和分类文本中的实体,并对它们进行标记。

 

3.文本分类 (二分类和多分类)

文本分类旨在将文本分为不同的类别或标签。二分类是将文本分为两个类别,如正面和负面;而多分类是将文本分为多个类别,如将新闻文章分类为政治、经济、体育等不同的类别。

 

4. 生成词向量

词向量是一种将词语表示为连续向量的技术,通过学习词语之间的语义和关联关系。生成词向量的任务通常涉及使用诸如Word2Vec、GloVe、FastText等模型,将词语映射到高维空间中的向量表示。

 

5. Zero-shot 分类

Zero-shot分类是指在没有事先见过的类别或标签的情况下对文本进行分类。通常使用零样本学习或迁移学习的技术来解决这个问题,这种任务要求模型在没有特定类别的训练数据的情况下进行分类。

 

| 4.4 混合排序 

基于向量KNN的相似度排序在长文本和大数据量下准确率和性能不高,可以结合BM25的文本相关性排序与KNN的相似度排序来优化排序结果,同时可以通过关键词过滤来减少召回的文档数量,通过减少向量的计算量来提升检索性能。文本相关性排序和向量相似度排序的融合目前主要有两种:一种是线性融合,还有一种是倒数排序融合(RRF)。

 

1.线性融合

线性融合较为简单,将文本查询的score与KNN查询的相似度score通过boost加权后累加作为最终的排序score。下面是一个图片搜索的案例,通过图片的标题(title)和描述(description)的文本搜索flower,同时指定一个图片的向量,通过KNN相似检索图片。文本检索和向量KNN检索的权重分别为0.6和0.4。

POST image-index/_search{  "query": {"multi_match": {"query": "flower",       "fields": ["title", "description"],"boost": 0.6}  },  "knn": {    "field": "image-vector",    "query_vector": [-5, 9, -12],    "k": 5,"num_candidates": 100,"boost": 0.4  }}


2. 倒数排序融合(Reciprocal Rank Fusion)

线性融合需要根据文本相似度和向量KNN相似度的score分布,调节权重,有一定的调优成本。倒数排序融合(RRF)无需调优,不同的相关性指标也不必相互关联即可获得高质量的结果。该方法的优势在于不利用相关分数,而仅靠排名计算。

 

以下图为例,向量模型ELSER和文本相关性模型BM25分别对ABCDEFGH等8个文档进行排序分别得到每个文档的排名r(d), 再通过RRF算法融合计算出各个文档的RRF打分,从而得到最终的排序。

图片


图片



Elastic 8 支持具有多个密集向量查询和在倒排索引上运行的单个查询的 RRF。以下是RRF的查询示例:

GET example-index/_search{    "query": {        "term": {            "text": "shoes"        }    },    "knn": {        "field": "vector",        "query_vector": [1.25, 2, 3.5],        "k": 50,        "num_candidates": 100    },    "rank": {        "rrf": {            "window_size": 50,            "rank_constant": 20        }    }}



| 4.5 时序数据库(TSDS)

ES8中增加了分布式时序数据库TSDS(Time series data stream)的支持,TSDS的目标并不是替换传统的时序数据库,如influxdb,prometheus,opentsdb,而是为了满足已经使用ES的应用存储时序数据的需求,TSDS可以降低引入其它技术栈带来的开发和维护成本,同时能使用ES强大的查询和聚合功能。

 

如下图所示,TSDS的数据按照时间字段(@timestamp)进行分区,同时会记录每个分区的start_time和end_time, 并按一定数据间隔进行滚动。这样的好处是,在查询时只要读取时间间隔内的分区数据进行计算。与ES的普通索引相比,TSDS的存储经过特别的优化,存储成本降低约70%。

图片


与传统的时序数据库类似,用户需要定义TSDS的维度字段(time_series_dimension)和指标字段(time_series_metric)。同时可以通过对维度字段做路由(routing_path)的方式让相同维度的数据落到相同的分片,提升查询和聚合的性能。下面是一个定义TSDS的索引模板:

{  "index_patterns": [    "metrics-weather_sensors-*"  ],  "data_stream": {},  "template": {    "settings": {      "index.mode": "time_series",      "index.routing_path": [        "sensor_id",        "location"      ]    },    "mappings": {      "properties": {        "sensor_id": {          "type": "keyword",          "time_series_dimension": true        },        "location": {          "type": "keyword",          "time_series_dimension": true        },        "temperature": {          "type": "half_float",          "time_series_metric": "gauge"        },        "humidity": {          "type": "half_float",          "time_series_metric": "gauge"        }      }    }  }}


| 4.6 快照搜索(Searchable snapshots)

快照是用于备份和恢复数据的机制。它允许用户创建集群级别的快照,包括索引和对应的数据,然后在需要时将这些快照用于数据的恢复和迁移。快照搜索允许用户直接查询已经归档的索引数据,而不需要先从快照恢复到ES集群,然后再查询数据。考虑到很多归档的索引非常大,这个功能可以提升归档数据检索的效率。Elasticsearch从7.11版就开始支持快照搜索,在ES8中优化了快照的本地缓存功能,提升了快照搜索的查询性能。

 

| 4.7 数据探索和分析(OLAP)

1. ES|QL

ES8.11开始支持Elasticsearch 查询语言 (ES|QL) ,ESQL是一种支持迭代探索数据的查询语言。


ES|QL 查询由一系列由管道分隔的命令组成。每个查询都以源命令(FROM, ROW, SHOW)开始。源命令会生成一个表,通常包含来自 Elasticsearch 的数据。源命令后面可以跟一个或多个处理命令。处理命令通过添加、删除或更改行和列来更改输入表。你可以链接处理命令,并用竖线字符分隔:|。每个处理命令都作用于前一个命令的输出表。查询的结果是最终处理命令生成的表。

图片



下面是一个ESQL的查询样例:

POST /_query{  "query": """    FROM library    | EVAL year = DATE_TRUNC(1 YEARS, release_date)    | STATS MAX(page_count) BY year    | SORT year    | LIMIT 5  """}


2. 异步检索(Async Search)

当某些索引的数据量大或者查询比较复杂,导致查询的响应时间比较长时,可以试用异步检索,发起一个异步检索的任务,可以通过返回的任务的id监控异步检索任务的状态;并在需要的时候终止任务的执行。

例如,执行一个异步检索的查询。

POST /sales*/_async_search?size=0{  "sort": [    { "date": { "order": "asc" } }  ],  "aggs": {    "sale_date": {      "date_histogram": {        "field": "date",        "calendar_interval": "1d"      }    }  }}


通过任务id获取异常检索的状态:

GET /_async_search/FmRldE8zREVEUzA2ZVpUeGs2ejJFUFEaMkZ5QTVrSTZSaVN3WlNFVmtlWHJsdzoxMDc=

 

异步检索可以和ESQL结合用于海量数据的OLAP分析,或者与快照搜索结合用户归档数据的查询。异步检索适用于实时性要求不高的一些查询场景。

 

| 4.8 安全认证

ES8开源版开放了安全认证的特性,无需第三方插件即可使用Elastic原厂的安全认证功能。更好地保障Elasticsearch集群的数据安全性。

图片

 

五、应用场景 

当前已经在使用ES8的场景主要有AIGC和知识库服务,保险核心保单搜索和车险核心搜索。

 

| 5.1 AIGC和知识库服务

AIGC和知识库服务主要是使用了ES8的向量KNN检索,多路召回和混合排序的能力。

 

ES8中,存储向量非常简单,只需要定义一个dense_vector类型字段,当然用户需要在中间件管理申请一个ES8版本的XSearch实例,然后,通过AIGC网关API写入向量数据,执行向量KNN检索。

图片

 

| 5.2 保险保单核心搜索

保险保单核心承接了众安保险百亿级的核心保单数据,随着业务的增长,老的保单核心使用的ES5的集群已经接近性能瓶颈,升级到ES8可以明显提升性能和服务稳定性。

 

| 5.3 车险核心搜索

由于历史原因,车险核心搜索一直使用非常老的ES2.x版本,性能较差,而且使用直连的方式连ES,容易出错且不方便管理和升级。为方便管理和避免每次升级都需要修改代码,车险核心搜索接入二向箔(XSearch)搜索平台服务,并使用搜索平台的数据无感迁移服务升级到ES8。

图片

 

六、未来规划 

| 6.1 全司推广ES8

目前全司生产环境有三十多个ES集群,几百台ECS,存储了几百T的数据。很多ES集群使用了ES5版本,还有个别的ES2版本。全司全面推广使用ES8之后预计可以每年为公司节省30%左右的ECS,百万级的资源成本。并且可以给各业务线带来更快更好的数据检索体验。

 

| 6.2 搜索平台服务升级

ES8带来了一些比较好的功能特性和能力,例如时序数据库(TSDS),快照搜索(Searchable snapshots),数据探索和分析(OLAP),机器学习模型和自然语言理解的模型(NLP)以及安全认证。这些能力需要通过升级众安的搜索平台服务,向业务线输出,以方便业务线的接入和使用。

 

----------  END  ----------



推荐阅读






| 众安开源AIGC工具代码助手DevPilot,让AI赋能每个开发者

|测量用户行为反馈的方法 —— INP (Interaction to Next Paint)

科技驱动金融,极客挑战极限!——众安1024程序员节:48-Hour Hackathon精彩回顾

关注公众号

了解更多技术前沿资讯

继续滑动看下一个
众安技术团队
向上滑动看下一个