首先还是说一下背景,工作中用到了 elasticsearch 的检索以及高亮展示,但是索引中的content
字段是读取的大文本内容,所以后果就是索引的单个字段很大,造成单独检索请求的时候速度还可以,但是加入高亮之后检索请求的耗时就非常的慢了。所以本文从更换高亮器类型的角度来解决因为高亮造成的检索请求缓慢的问题。
ES的抵消策略
在文章开始前先简单介绍一个elasticsearch的策略,为了在检索的字段中创建出一个有意义的高亮片段,高亮器会使用原始文本的开始和结束字符串的偏移量,偏移量的获取可以从一下方式获得
postings list
:如果在mapping
中index_options
设置为offsets
,unified
高亮器使用此信息高亮显示文档而不用再次分析文本。term vectors
:如果我们在mapping
中设置term_vector
为with_positions_offsets
,则unified
高亮器会自动使用term_vector
来高亮显示,对于大于1M
的大字段,使用term_vector
速度会很快,fvh
高亮器就是使用的term_vector
。plain highlighting
:当unified
没有其他的选择的时候会使用plain
模式,它会创建了一个微小的内存索引,并通过Lucene的查询执行计划器重新运行原始查询条件。plain
高亮器默认使用的就是此模式
大文本的纯高亮展示可能需要大量的时间和内存,为了防止这种情况,es默认将大文本的字符数量限制为
1000000
,可以使用index.highlight.max_analyzed_offset
修改此默认设置
一、FVH高亮器简介
FVH(Fast Vector Highlighter)是Elasticsearch高亮器中的一种算法,使用的是Lucene Fast Vector highlighter,它能够快速而准确地在文本中找到匹配的关键词,并将其标记为高亮。相比于其他高亮器算法,FVH在性能上有着显著的优势,特别适用于大规模数据集和高并发的场景。
二、FVH高亮器的使用方法
安装
首先,确保已经正确安装了 Elasticsearch
version: '3.8' services: cerebro: image: lmenezes/cerebro:0.8.3 container_name: cerebro ports: - "9000:9000" command: - -Dhosts.0.host=http://eshot:9200 networks: - elastic kibana: image: docker.elastic.co/kibana/kibana:8.1.3 container_name: kibana environment: - I18N_LOCALE=zh-CN - XPACK_GRAPH_ENABLED=true - TIMELION_ENABLED=true - XPACK_MONITORING_COLLECTION_ENABLED="true" - ELASTICSEARCH_HOSTS=http://eshot:9200 - server.publicBaseUrl=http://192.168.160.234:5601 ports: - "5601:5601" networks: - elastic eshot: image: elasticsearch:8.1.3 container_name: eshot environment: - node.name=eshot - cluster.name=es-docker-cluster - discovery.seed_hosts=eshot,eswarm,escold - cluster.initial_master_nodes=eshot,eswarm,escold - bootstrap.memory_lock=true - "ES_JAVA_OPTS=-Xms512m -Xmx512m" - xpack.security.enabled=false - node.attr.node_type=hot ulimits: memlock: soft: -1 hard: -1 volumes: - D:\zuiyuftp\docker\es8.1\eshot\data:/usr/share/elasticsearch/data - D:\zuiyuftp\docker\es8.1\eshot\logs:/usr/share/elasticsearch/logs - D:\zuiyuftp\docker\es8.1\eshot\plugins:/usr/share/elasticsearch/plugins ports: - 9200:9200 networks: - elastic eswarm: image: elasticsearch:8.1.3 container_name: eswarm environment: - node.name=eswarm - cluster.name=es-docker-cluster - discovery.seed_hosts=eshot,eswarm,escold - cluster.initial_master_nodes=eshot,eswarm,escold - bootstrap.memory_lock=true - "ES_JAVA_OPTS=-Xms512m -Xmx512m" - xpack.security.enabled=false - node.attr.node_type=warm ulimits: memlock: soft: -1 hard: -1 volumes: - D:\zuiyuftp\docker\es8.1\eswarm\data:/usr/share/elasticsearch/data - D:\zuiyuftp\docker\es8.1\eswarm\logs:/usr/share/elasticsearch/logs - D:\zuiyuftp\docker\es8.1\eshot\plugins:/usr/share/elasticsearch/plugins networks: - elastic escold: image: elasticsearch:8.1.3 container_name: escold environment: - node.name=escold - cluster.name=es-docker-cluster - discovery.seed_hosts=eshot,eswarm,escold - cluster.initial_master_nodes=eshot,eswarm,escold - bootstrap.memory_lock=true - "ES_JAVA_OPTS=-Xms512m -Xmx512m" - xpack.security.enabled=false - node.attr.node_type=cold ulimits: memlock: soft: -1 hard: -1 volumes: - D:\zuiyuftp\docker\es8.1\escold\data:/usr/share/elasticsearch/data - D:\zuiyuftp\docker\es8.1\escold\logs:/usr/share/elasticsearch/logs - D:\zuiyuftp\docker\es8.1\eshot\plugins:/usr/share/elasticsearch/plugins networks: - elastic # volumes: # eshotdata: # driver: local # eswarmdata: # driver: local # escolddata: # driver: local networks: elastic: driver: bridge
创建索引
在使用FVH高亮器之前,需要先创建一个索引,并将需要高亮的字段进行映射。例如,我们要在content
字段中进行高亮,可以使用以下代码:
PUT /example_target { "mappings": { "properties": { "content": { "type": "text", "analyzer": "ik_max_word", "term_vector": "with_positions_offsets" }, "title": { "type": "text", "analyzer": "ik_max_word", "term_vector": "with_positions_offsets" } } } }
添加测试数据
POST example_target/_doc { "content":"中华人民共和国是否考虑是否就爱上速度加快分解ask计算机卡死撒中华上的飞机拉丝机是的地方记录 卡就是开发建设看积分卡说了句 ask就疯狂萨拉丁就发士大 sdf 看得见啊李开复 圣诞节卡了 夫哈数据库中华啊,中华,人民爱上中华", "title":"中华人名共和国" }
查询并高亮
使用FVH高亮器进行查询和高亮的过程如下所示:
GET example_target/_search { "query": { "match": { "content": "中华 爱上" } }, "highlight": { "pre_tags": "<em>", "post_tags": "</em>", "require_field_match": "false", "fields": { "content": { "type": "fvh", "fragment_size": 18, "number_of_fragments": 3 } } } }
以上代码中,我们通过match
查询找到了包含关键词的文档,然后在highlight
内容中指定了需要高亮的字段,这里是content
。执行述查询后,Elasticsearch将返回匹配的结果,并在content
字段中添加了高亮标记。
数据量少的时候对比不是特别明显,所以在测试时,可以在索引中添加大量的测试数据进行测试,本人在测试过程中es的索引大小在
500M
左右,单个字段纯文本大小也有1-2M
。此时这种数据规模下使用普通的高亮器在检索请求时就已经非常缓慢了,根据返回的数据量多少来决定,在取10
条数据时已经能达到6
秒了,但是在使用fvh
高亮器之后时间已经进入毫秒级
三、FVH高亮器的参数配置
先看一下返回的数据结果在对照下面参数学习
{ "took" : 4, "timed_out" : false, "_shards" : { "total" : 1, "successful" : 1, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : { "value" : 3, "relation" : "eq" }, "max_score" : 0.41193593, "hits" : [ { "_index" : "example_target", "_id" : "f1rkC4oBCDmhQc2yo6PQ", "_score" : 0.41193593, "_source" : { "content" : "中华人民共和国是否考虑是否就爱上速度加快分解ask计算机卡死撒中华上的飞机拉丝机是的地方记录 卡就是开发建设看积分卡说了句 ask就疯狂萨拉丁就发士大 sdf 看得见啊李开复 圣诞节卡了 夫哈数据库中华啊,中华,人民爱上中华" }, "highlight" : { "content" : [ "<em>中华</em>人民共和国是否考虑是否就<em>爱上</em>速度", "sk计算机卡死撒<em>中华</em>上的飞机拉丝机是的地方记录", "夫哈数据库<em>中华</em>啊,<em>中华</em>,人民<em>爱上</em>中华" ] } }, { "_index" : "example_target", "_id" : "G3Fi44kB4IVEhjafHXOf", "_score" : 0.33311102, "_source" : { "content" : "中华人民共和国是否考虑是否就爱上速度加快分解ask计算机卡死撒中华上的飞机拉丝机是的地方记录卡就是开发建设看积分卡说了句ask就疯狂萨拉丁就发士大夫哈数据库" }, "highlight" : { "content" : [ "<em>中华</em>人民共和国是否考虑是否就<em>爱上</em>速度", "sk计算机卡死撒<em>中华</em>上的飞机拉丝机是" ] } }, { "_index" : "example_target", "_id" : "HHFt44kB4IVEhjafE3Ov", "_score" : 0.31932122, "_source" : { "content" : "中华人民共和国是否考虑是否就爱上速度加快分解ask计算机卡死撒中华上的飞机拉丝机是的地方记录 卡就是开发建设看积分卡说了句 ask就疯狂萨拉丁就发士大 sdf 看得见啊李开复 圣诞节卡了 夫哈数据库" }, "highlight" : { "content" : [ "<em>中华</em>人民共和国是否考虑是否就<em>爱上</em>速度", "sk计算机卡死撒<em>中华</em>上的飞机拉丝机是的地方记录" ] } } ] } }
通过上面的查询请求中高亮参数的指定可以发现,高亮器还是支持其他的参数的,那么我们下面将对几个常用的参数进行说明
fragment_size
:指定每个高亮片段的长度,默认为100
个字符。number_of_fragments
:指定返回的高亮片段数量,默认为5
个。pre_tags
和post_tags
:分别指定高亮标记的前缀和后缀,默认为<em>
和</em>
。require_field_match
:指定是否要求所有字段都匹配关键词才进行高亮,默认为true
。可以开启关闭此参数对上面的title
字段进行校验type
:指定fvh
高亮器,除了fvh
之外还有unified
,plain
。
unified
是默认的高亮器,可以将文本分解为句子,并使用BM25算法对单个句子进行评分,还支持精确的短语高亮显示,支持(fuzzy
,prefix
,regex
)高亮。plain
普通的高亮器,适用与简单的查询或者单个字段的匹配。为了准确的反应查询逻辑,它会在内存中创建一个很小的索引,来对原始的查询语句进行执行,来访问当前更低级别的匹配信息。
在使用FVH
高亮器时,根据实际需求,可以灵活地调整这些参数,以获得最佳的高亮效果。
总结
通过本文的介绍,我们了解了Elasticsearch高亮器中的FVH
算法,并学会了如何使用它为搜索结果增添亮点。FVH
高亮器在性能和功能上都有着明显的优势,对于大规模数据集和高并发的场景尤为适用。希望读者通过本文的指引,能够更好地利用FVH
高亮器来提升搜索结果的可读性和用户体验。
参考链接
https://www.elastic.co/guide/en/elasticsearch/reference/8.1/highlighting.html
如果感觉本文对你有所帮助欢迎点赞评论转发收藏。如果你想了解更多关于ES的骚操作,更多实战经验,欢迎关注。