Proximity Matching

近似匹配

使用TF/IDF的标准全文检索是检索字段中是否包含某些词语,而无法得知词语之间的关系。
理解分词之间的关系是一个复杂的难题,我们无法通过换一种查询方式去解决。但我们至少可以通过出现在彼此附近或者仅仅是彼此相邻的分词来判断一些似乎相关的分词。
短语匹配或者近似匹配。

短语匹配

保留那些包含全部搜索词项,且位置与搜索词项相同的文档

GET /my_index/my_type/_search
{
    "query": {
        "match_phrase": {
            "title": "quick brown fox"
        }
    }
}

也可以写成

"match": {
    "title": {
        "query": "quick brown fox",
        "type":  "phrase"
    }
}

词项的位置

当一个字符串被分词后,不但会返回一个词项列表,还会返回各词在原始字符串中的 位置或者顺序关系
被认定和短语quick brown fox匹配的文档,应该满足下列要求
1、三个词项全部出现在域中
2、brown位置比quick大1
3、fox位置比quick大2

GET /my_index/my_type/_search
{
    "query": {
        "match_phrase": {
            "title": {
                "query": "quick fox",
                "slop":  1
            }
        }
    }
}

slop参数使得查询词条相隔多远时仍然被视为匹配,上文查询quick brown fox,会被匹配

多值字段

由于es的索引方式导致多值字段的索引位置如下

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

会被索引成

Position 1: john
Position 2: abraham
Position 3: lincoln
Position 4: smith

于是查询abraham lincoln就会被匹配到
解决方式,设置position_increment_gap,相当于增加距离,这样子就不容易被匹配到了

PUT /my_index/_mapping/groups (2)
{
    "properties": {
        "names": {
            "type":                "string",
            "position_increment_gap": 100
        }
    }
}

此时映射为

Position 1: john
Position 2: abraham
Position 103: lincoln
Position 104: smith

此时如果还想要被匹配,需要设置slop为100

越近越好

邻近查询,当slop大于0的时候,会将邻近度考虑到_score中

使用邻近度提高相关度

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

性能优化

短语查询和邻近查询都比简单的query查询代价更高。
有效的方法时减少需要通过短语查询检查的文档总数。
我们只想对顶部文档重新排序,比如phrase查询只是为了从每个分片中获取前k个结果

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

1、match查询决定哪些文档将包含在最终结果集中,并通过TF/IDF排序。
2、window_size是每一分片进行重新评分的顶部文档数量。
3、目前唯一支持的重新打分算法就是另一个查询。(旧)

需找相关词

短语查询和邻近查询的一个缺点:过于严格。
即使使用了slop,得到的单词顺序的灵活性也需要付出代价,失去了单词对之间的联系。
可以识别sue、alligator、ate相邻出现的文档,但无法分辨是Sue ate还是alligator ate
索引单词对,能对这些单词的上下文尽可能多的保留。
Sue ate the alligator
不仅将每一个单词(或者unigram)作为词项索引["sue", "ate", "the", "alligator"]
也将每个单词以及它的邻近词作为单个词项索引["sue ate", "ate the", "the alligator"]
这些单词对(或者biggrams)被成为shingles.
shingles不限于单词对,也可以索引三个单词(trigrams)
trigrams提供了更高的精度,但是也大大增加了索引中唯一词项的数量。
只有在用户输入的查询内容在原始文档中顺序相同时,shingles才是有用的。
生成及使用shingles:https://github.com/elasticsearch-cn/elasticsearch-definitive-guide/blob/cn/120_Proximity_Matching/35_Shingles.asciidoc
性能相关:
shingles不仅比短语查询更灵活,而且性能也更好。shingles查询跟一个简单的match查询一样搞笑,而不用每次搜索花费短语查询的代价。索引时会付出一些小的代价。

你可能感兴趣的:(Proximity Matching)