• [Elasticsearch] 邻近匹配 (二)


    多值字段(Multivalue Fields)

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

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

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

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

    令人诧异的是,以上的这份文档匹配了查询。

    即使Abraham以及Lincoln分属于name数组的两个人名中。

    发生这个现象的原因在于数组在ES中的索引方式。

    当John Abraham被解析时。它产生例如以下信息:

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

    然后当Lincoln Smith被解析时。它产生了:

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

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

    幸运的是,有一个简单的方法来避免这样的情况。通过position_offset_gap參数,它在字段映射中进行配置:

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

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

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

    如今我们的短语匹配就无法匹配该文档了。由于abraham和lincoln之间的距离为100。你必需要加入一个值为100的slop的值才干匹配。



    越近越好(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子句中加入其他的查询,每一个查询都用来添加特定类型的相关度。


  • 相关阅读:
    CentOS+nginx+uwsgi+Python 多站点环境搭建
    nginx实现负载均衡
    高性能Mysql主从架构的复制原理及配置详解
    centos 安装php
    Java知识总结-6
    Java知识总结-5
    Java知识总结-4
    Java知识总结-3
    Java知识总结-2
    java知识总结-1
  • 原文地址:https://www.cnblogs.com/zsychanpin/p/6743593.html
Copyright © 2020-2023  润新知