提高性能

短语和邻近度查询比简单的match查询在性能上更昂贵。match查询只是查看词条是否存在于倒排索引(Inverted Index)中,而match_phrase查询则需要计算和比较多个可能重复词条(Multiple possibly repeated)的位置。

在Lucene Nightly Benchmarks中,显示了一个简单的term查询比一个短语查询快大概10倍,比一个邻近度查询(一个拥有slop的短语查询)快大概20倍。当然,这个代价是在搜索期间而不是索引期间付出的。

TIP

通常,短语查询的额外代价并不像这些数字说的那么吓人。实际上,性能上的差异只是说明了一个简单的term查询时多么的快。在标准全文数据上进行的短语查询通常能够在数毫秒内完成,因此它们在实际生产环境下是完全能够使用的,即使在一个繁忙的集群中。

在某些特定的场景下,短语查询可能会很耗费资源,但是这种情况时不常有的。一个典型的例子是DNA序列,此时会在很多位置上出现非常之多的相同重复词条。使用高slop值会使位置计算发生大幅度的增长。

因此,如何能够限制短语和邻近度查询的性能消耗呢?一个有用的方法是减少需要使用短语查询进行检查的文档总数。

结果的分值重计算(Rescoring Results)

在上一节中,我们讨论了使用邻近度查询来调整相关度,而不是使用它来将文档从结果列表中添加或者排除。一个查询可能会匹配百万计的结果,但是我们的用户很可能只对前面几页结果有兴趣。

一个简单的match查询已经通过排序将含有所有搜索词条的文档放在结果列表的前面了。而我们只想对这些前面的结果进行重新排序来给予那些同时匹配了短语查询的文档额外的相关度。

search API通过分值重计算(Rescoring)来支持这一行为。在分值重计算阶段,你能够使用一个更加昂贵的分值计算算法 - 比如一个短语查询 - 来为每个分片的前K个结果重新计算其分值。紧接着这些结果就会按其新的分值重新排序。

该请求如下所示:

GET /my_index/my_type/_search
{"query": {"match": {  "title": {"query":                "quick brown fox","minimum_should_match": "30%"}}},"rescore": {"window_size": 50, "query": {         "rescore_query": {"match_phrase": {"title": {"query": "quick brown fox","slop":  50}}}}}
}

match查询用来决定哪些文档会被包含在最终的结果集合中,结果通过TF/IDF进行排序。 window_size是每个分片上需要重新计算分值的数量。

寻找关联的单词(Finding Associated Words)

尽管短语和邻近度查询很管用,它们还是有一个缺点。它们过于严格了:所有的在短语查询中的词条都必须出现在文档中,即使使用了slop。

通过slop获得的能够调整单词顺序的灵活性也是有代价的,因为你失去了单词之间的关联。尽管你能够识别文档中的sue,alligator和ate出现在一块,但是你不能判断是Sue ate还是alligator ate。

当单词结合在一起使用时,它们表达的意思比单独使用时要丰富。"I’m not happy I’m working"和"I’m happy I’m not working"含有相同的单词,也拥有相近的邻近度,但是它们的意思大相径庭。

如果我们索引单词对,而不是索引独立的单词,那么我们就能够保留更多关于单词使用的上下文信息。

对于句子"Sue ate the alligator",我们不仅索引每个单词(或者Unigram)为一个词条:

["sue", "ate", "the", "alligator"]

我们同时会将每个单词和它的邻近单词一起索引成一个词条:

["sue ate", "ate the", "the alligator"]

这些单词对(也叫做Bigram)就是所谓的Shingle。

TIP

Shingle不限于只是单词对;你也可以索引三个单词(Word Triplet,也被称为Trigram)作为一个词条:

["sue ate the", "ate the alligator"]

Trigram能够给你更高的精度,但是也大大地增加了索引的不同词条的数量。在多数情况下,Bigram就足够了。

当然,只有当用户输入查询的顺序和原始文档的顺序一致,Shingle才能够起作用;一个针对sue alligator的查询会匹配单独的单词,但是不会匹配任何Shingle。

幸运的是,用户会倾向于使用和他们正在搜索的数据中相似的结构来表达查询。但是这是很重要的一点:仅使用Bigram是不够的;我们仍然需要Unigram,我们可以将匹配Bigram作为信号(Signal)来增加相关度分值。

产生Shingle

Shingle需要在索引期间,作为分析过程的一部分被创建。我们可以将Unigram和Bigram都索引到一个字段中,但是将它们放在不同的字段中会更加清晰,也能够让它们能够被独立地查询。Unigram字段形成了我们搜索的基础部分,而Bigram字段则用来提升相关度。

首先,我们需要使用shingle词条过滤器来创建解析器:

DELETE /my_indexPUT /my_index
{"settings": {"number_of_shards": 1,  "analysis": {"filter": {"my_shingle_filter": {"type":             "shingle","min_shingle_size": 2, "max_shingle_size": 2, "output_unigrams":  false   }},"analyzer": {"my_shingle_analyzer": {"type":             "custom","tokenizer":        "standard","filter": ["lowercase","my_shingle_filter" ]}}}}
}

默认Shingle的min/max值就是2,因此我们也可以不显式地指定它们。 output_unigrams被设置为false,用来避免将Unigram和Bigram索引到相同字段中。

让我们使用analyze API来测试该解析器:

GET /my_index/_analyze?analyzer=my_shingle_analyzer
Sue ate the alligator

不出所料,我们得到了3个词条:

  • sue ate
  • ate the
  • the alligator

现在我们就可以创建一个使用新解析器的字段了。

多字段(Multifields)

将Unigram和Bigram分开索引会更加清晰,因此我们将title字段创建成一个多字段(Multifield)(参见字符串排序和多字段(String Sorting and Multifields)):

PUT /my_index/_mapping/my_type
{"my_type": {"properties": {"title": {"type": "string","fields": {"shingles": {"type":     "string","analyzer": "my_shingle_analyzer"}}}}}
}

有了上述映射,JSON文档中的title字段会以Unigram(title字段)和Bigram(title.shingles字段)的方式索引,从而让我们可以独立地对这两个字段进行查询。

最后,我们可以索引示例文档:

POST /my_index/my_type/_bulk
{ "index": { "_id": 1 }}
{ "title": "Sue ate the alligator" }
{ "index": { "_id": 2 }}
{ "title": "The alligator ate Sue" }
{ "index": { "_id": 3 }}
{ "title": "Sue never goes anywhere without her alligator skin purse" }

搜索Shingles

为了理解添加的shingles字段的好处,让我们首先看看一个针对"The hungry alligator ate Sue"的简单match查询的返回结果:

GET /my_index/my_type/_search
{"query": {"match": {"title": "the hungry alligator ate sue"}}
}

该查询会返回所有的3份文档,但是注意文档1和文档2拥有相同的相关度分值,因为它们含有相同的单词:

{"hits": [{"_id": "1","_score": 0.44273707, "_source": {"title": "Sue ate the alligator"}},{"_id": "2","_score": 0.44273707, "_source": {"title": "The alligator ate Sue"}},{"_id": "3", "_score": 0.046571054,"_source": {"title": "Sue never goes anywhere without her alligator skin purse"}}]
}

现在让我们将shingles字段也添加到查询中。记住我们会将shingle字段作为信号 - 以增加相关度分值 - 我们仍然需要将主要的title字段包含到查询中:

GET /my_index/my_type/_search
{"query": {"bool": {"must": {"match": {"title": "the hungry alligator ate sue"}},"should": {"match": {"title.shingles": "the hungry alligator ate sue"}}}}
}

我们仍然匹配了3分文档,但是文档2现在排在了第一位,因为它匹配了Shingle词条"ate sue":

{"hits": [{"_id": "2","_score": 0.4883322,"_source": {"title": "The alligator ate Sue"}},{"_id": "1","_score": 0.13422975,"_source": {"title": "Sue ate the alligator"}},{"_id": "3","_score": 0.014119488,"_source": {"title": "Sue never goes anywhere without her alligator skin purse"}}]
}

即使在查询中包含了没有在任何文档中出现的单词hungry,我们仍然通过使用单词邻近度得到了最相关的文档。

性能

Shingle不仅比短语查询更灵活,它们的性能也更好。相比每次搜索需要为短语查询付出的代价,对Shingle的查询和简单match查询一样的高效。只是在索引期间会付出一点小代价,因为更多的词条需要被索引,意味着使用了Shingle的字段也会占用更多的磁盘空间。但是,多数应用是写入一次读取多次的,因此在索引期间花费一点代价来让查询更迅速是有意义的。

这是一个你在ES中经常会碰到的主题:让你在搜索期间能够做很多事情,而不需要任何预先的设置。一旦更好地了解了你的需求,就能够通过在索引期间正确地建模来得到更好的结果和更好的性能。

[Elasticsearch] 邻近匹配 (三) - 性能,关联单词查询以及Shingles相关推荐

  1. [Elasticsearch] 部分匹配 (三) - 查询期间的即时搜索

    本章翻译自Elasticsearch官方指南的Partial Matching一章. 查询期间的即时搜索(Query-time Search-as-you-type) 如今让我们来看看前缀匹配可以怎样 ...

  2. [Elasticsearch] 邻近匹配 (二) - 多值字段,邻近程度与相关度

    多值字段(Multivalue Fields) 在多值字段上使用短语匹配会产生古怪的行为: PUT /my_index/groups/1 {"names": [ "Joh ...

  3. 49.(leaflet篇)leaflet实现反向匹配查询(ElasticSearch技术实现)(输入坐标查询距离最近的地址信息)

    地图之家总目录(订阅之前请先查看该博客) 地图之家:cesium+leaflet+echart+地图数据+地图工具等相关内容的介绍 关联博客: 4.(后端技术篇java)ElasticSearch实现 ...

  4. MySQL 三种关联查询的方式: ON vs USING vs 传统风格

    看看下面三个关联查询的 SQL 语句有何区别? 1SELECT * FROM film JOIN film_actor ON (film.film_id = film_actor.film_id) 2 ...

  5. 【Elasticsearch】十九种Elasticsearch字符串搜索方式终极介绍 各种 查询

    本文为博主九师兄(QQ:541711153 欢迎来探讨技术)原创文章,未经允许博主不允许转载. 可以加我问问题,免费解答,有问题可以先私聊我,本人每天都在线,会帮助需要的人. 但是本博主因为某些原因, ...

  6. Elasticsearch Search API之(Request Body Search 查询主体)

    作者介绍:<RocketMQ技术内幕>作者,中间件兴趣圈微信公众号维护者,文末有对应的二维码,关注后可以与作者更好的互动. 本文有点长,看完可能需要点耐心,本文详细介绍了es三种分页方式. ...

  7. mysql查一个表3到5行的数据类型_MySQL入门(三) 数据库表的查询操作【重要】

    序言 本节比较重要,对数据表数据进行查询操作,其中可能大家不熟悉的就对于INNER JOIN(内连接).LEFT JOIN(左连接).RIGHT JOIN(右连接)等一些复杂查询. 通过本节的学习,可 ...

  8. ElasticSearch权威指南学习(结构化查询)

    请求体查询 简单查询语句(lite)是一种有效的命令行adhoc查询.但是,如果你想要善用搜索,你必须使用请求体查询(request body search)API. 空查询 我们以最简单的 sear ...

  9. 微服务03 分布式搜索引擎 elasticsearch ELK kibana RestAPI 索引库 DSL查询 RestClient 黑马旅游

    分布式搜索引擎01 -- elasticsearch基础 0.学习目标 1.初识elasticsearch 1.1.了解ES 1.1.1.elasticsearch的作用 elasticsearch是 ...

最新文章

  1. 零基础搭建个性化精准营销 AI 应用,这次手把手教你!
  2. 选择存储服务器硬盘并解决一些疑问
  3. 计算最长公共数字串个数
  4. 【SNN脉冲神经网络】SNN脉冲神经网络的工作原理演示MATLAB仿真带GUI界面
  5. SQL Server数据库表锁定原理以及如何解除表的锁定转
  6. Python中九种格式化输出方法,你都知道吗?
  7. 【数据结构与算法】之深入解析“省份数量”的求解思路与算法示例
  8. 【Elasticsearch】 Elasticsearch对外提供分词服务实践
  9. python字典包含指定键_python-字典中所有值的总和,其中包含键中的项
  10. python生成自己想要的KML文件
  11. 【车型识别】基于小波和盒维数实现车型识别含Matlab源码
  12. 中图分类法----T-0
  13. 51单片机8位数码管时钟c语言,基于c51单片机8位数码管显示电子时钟程序
  14. Sap S/4 Hana 和Sap ERP有什么不同
  15. [我叫以赏]Python获取B站UP主粉丝数
  16. 【Python】详解 collections.Counter
  17. 机器学习 深度学习 EM算法 深度解析
  18. 【android】高仿京东商城App,集成react-native热更功能
  19. LaTex论文排版 | (23) LaTex中的正上、正下标记以及各种箭头符号总结
  20. HMailServer 5.6版本完整版汉化包

热门文章

  1. 第十章:Java之接口基本概念、接口实现多继承、Object类
  2. 落单的数IV --- lintcode 824
  3. openstack(pike) dvr 中南北数据流向分析
  4. CSS奇思妙想 -- 使用 background 创造各种美妙的背景
  5. SAP中文语言包安装配置
  6. 什么是Iot?什么是AIot?
  7. 京东健康和药明康德入股卫宁软件,分别持有7.7%股权
  8. kali(linux)配置apt国内源+全流程采坑
  9. 贾扬清从阿里毕业了!
  10. 《男女诗篇》 - 肖复兴