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

多值字段(Multivalue Fields)

在多值字段上使用短语匹配会产生古怪的行为:html

PUT /my_index/groups/1
{
    "names": [ "John Abraham", "Lincoln Smith"] }

运行一个针对Abraham Lincoln的短语查询:json

GET /my_index/groups/_search
{
    "query": { "match_phrase": { "names": "Abraham Lincoln" } } }

使人诧异的是,以上的这份文档匹配了查询。即便Abraham以及Lincoln分属于name数组的两我的名中。发生这个现象的缘由在于数组在ES中的索引方式。数组

当John Abraham被解析时,它产生以下信息:app

  • 位置1:john
  • 位置2:abraham

而后当Lincoln Smith被解析时,它产生了:elasticsearch

  • 位置3:lincoln
  • 位置4:smith

换言之,ES对以上数组分析产生的词条列表和解析单一字符串John Abraham Lincoln Smith时产生的结果是同样的。在咱们的查询中,咱们查询邻接的abraham和lincoln,而这两个词条在索引中确实存在而且邻接,所以查询匹配了。ide

幸运的是,有一个简单的方法来避免这种状况,经过position_offset_gap参数,它在字段映射中进行配置:ui

DELETE /my_index/groups/ 

PUT /my_index/_mapping/groups 
{
    "properties": { "names": { "type": "string", "position_offset_gap": 100 } } }

position_offset_gap设置告诉ES须要为数组中的每一个新元素设置一个误差值。所以,当咱们再索引以上的人名数组时,会产生以下的结果:spa

  • 位置1:john
  • 位置2:abraham
  • 位置103:lincoln
  • 位置104:smith

如今咱们的短语匹配就没法匹配该文档了,由于abraham和lincoln之间的距离为100。你必需要添加一个值为100的slop的值才能匹配。htm



 

越近越好(Closer is better)

短语查询(Phrase Query)只是简单地将不含有精确查询短语的文档排除在外,而邻近查询(Proximity Query) - 一个slop值大于0的短语查询 - 会将查询词条的邻近度也考虑到最终的相关度_score中。经过设置一个像50或100这样的高slop值,你能够排除那些单词过远的文档,可是也给予了那些单词邻近的文档一个更高的分值。索引

下面针对quick dog的邻近查询匹配了含有quick和dog的两份文档,可是给与了quick和dog更加邻近的文档一个更高的分值:

POST /my_index/my_type/_search
{
   "query": { "match_phrase": { "title": { "query": "quick dog", "slop": 50 } } } }
{
  "hits": [ { "_id": "3", "_score": 0.75, "_source": { "title": "The quick brown fox jumps over the quick dog" } }, { "_id": "2", "_score": 0.28347334, "_source": { "title": "The quick brown fox jumps over the lazy dog" } } ] }

 


 

使用邻近度来提升相关度

尽管邻近度查询(Proximity Query)管用,可是全部的词条都必须出如今文档的这一要求显的过于严格了。这个问题和咱们在全文搜索(Full-Text Search)一章的精度控制(Controlling Precision)一节中讨论过的相似:若是7个词条中有6个匹配了,那么该文档也许对于用户而言已经足够相关了,可是match_phrase查询会将它排除在外。

相比将邻近度匹配做为一个绝对的要求,咱们能够将它当作一个信号(Signal) - 做为众多潜在匹配中的一员,会对每份文档的最终分值做出贡献(参考多数字段(Most Fields))。

咱们须要将多个查询的分值累加这一事实表示咱们应该使用bool查询将它们合并。

咱们可使用一个简单的match查询做为一个must子句。该查询用于决定哪些文档须要被包含到结果集中。能够经过minimum_should_match参数来去除长尾(Long tail)。而后咱们以should子句的形式添加更多特定查询。每一个匹配了should子句的文档都会增长其相关度。

GET /my_index/my_type/_search
{
  "query": { "bool": { "must": { "match": { "title": { "query": "quick brown fox", "minimum_should_match": "30%" } } }, "should": { "match_phrase": { "title": { "query": "quick brown fox", "slop": 50 } } } } } }

毫无疑问咱们能够向should子句中添加其它的查询,每一个查询都用来增长特定类型的相关度。

相关文章
相关标签/搜索