Elasticsearch学习笔记-部分匹配

1,969 阅读1分钟

1、短语匹配

$ GET /trade/share/_search
{
    "query": {
        "match_phrase": {
            "title": "quick brown fox"
        }
    }
}
match_phrase 查询首先将查询字符串解析成一个词项列表,然后对这些词项进行搜索,但只保留那些
包含 全部 搜索词项,且 位置 与搜索词项相同的文档。

#slop参数
例:包含 “quick brown fox” 的文档也能够匹配 “quick fox”。
$ GET /trade/share/_search
{
    "query": {
        "match_phrase": {
            "title": {
            	"query": "quick fox",
            	"slop":  1
            }
        }
    }
}
slop 参数告诉 match_phrase 查询词条相隔多远时仍然能将文档视为匹配 。 

2、prefix前缀查询

$ GET /trade/address/_search
{
    "query": {
        "prefix": {
            "postcode": "W1" #查找所有以 W1 开始的邮编
        }
    }
}
prefix 不会在搜索之前分析查询字符串,它假定传入前缀就正是要查找的前缀。

3、通配符与正则表达式查询

wildcard 通配符查询与前缀 prefix 查询不同的是它允许指定匹配的正则式。它使用标准的 shell 通配符
查询: ? 匹配任意字符, * 匹配 0 或多个字符。
#例:这个查询会匹配包含 W1F 7HW 和 W2F 8HW 的文档
$ GET /trade/address/_search
{
    "query": {
        "wildcard": {
            "postcode": "W?F*HW" #? 匹配 1 和 2 , * 与空格及 7 和 8 匹配
        }
    }
}
regexp 正则式查询可以写出更复杂的模式
$ GET /trade/address/_search
{
    "query": {
        "regexp": {
            "postcode": "W[0-9].+" #必须以 W 开头,紧跟 0 至 9 之间的任何一个数字,然后接一或多个其他字符
        }
    }
}

#注:
对有很多唯一词的字段执行 wildcard 和 regexp 查询可能会消耗非常多的资源,所以要避免使用左通配这样
的模式匹配(如: *foo 或 .*foo 这样的正则式)


prefix 、 wildcard 和 regexp 查询是基于词操作的,如果用来查询 analyzed 字段,它们会检查字段里面的
每个词,而不是将字段作为整体来处理。

比方说包含 “Quick brown fox” 的 title 字段会生成词: quick 、 brown 和 fox
可以匹配以下这个查询
{ "regexp": { "title": "br.*" }}

但是不会匹配以下两个查询
{ "regexp": { "title": "Qu.*" }} #在索引里的词是 quick 而不是 Quick 
{ "regexp": { "title": "quick br*" }} #quick 和 brown 在词表中是分开的

4、查询时输入即搜索(即时搜索)

在 match_phrase 短语匹配查询中,它匹配相对顺序一致的所有指定词语,对于查询时的输入即搜索,可以使
用 match_phrase 的一种特殊形式, match_phrase_prefix 查询
{
    "match_phrase_prefix" : {
        "brand" : "johnnie walker bl"
    }
}
这种查询的行为与 match_phrase 查询一致,不同的是它将查询字符串的最后一个词作为前缀使用

与 match_phrase 一样,match_phrase_prefix 也可以接受 slop 参数
{
    "match_phrase_prefix" : {
        "brand" : {
            "query": "walker johnnie bl", #设置足够高的 slop 值使匹配时的词序有更大的灵活性
            "slop":  10
        }
    }
}

通过设置 max_expansions 参数来限制前缀扩展的影响,一个合理的值是可能是 50
{
    "match_phrase_prefix" : {
        "brand" : {
            "query":          "johnnie walker bl",
            "max_expansions": 50
        }
    }
}
参数 max_expansions 控制着可以与前缀匹配的词的数量,它会先查找第一个与前缀 bl 匹配的词,然后依次
查找搜集与之匹配的词(按字母顺序),直到没有更多可匹配的词或当数量超过 max_expansions 时结束

5、索引时输入即搜索

n-gram 可以看成一个在词语上 滑动窗口 , n 代表这个 “窗口” 的长度。
长度 1: [ q, u, i, c, k ]
长度 2: [ qu, ui, ic, ck ]
长度 3: [ qui, uic, ick ]
长度 4: [ quic, uick ]
长度 5: [ quick ]

1> 准备索引
配置一个自定义的 edge_ngram token 过滤器,称为 autocomplete_filter
{
    "filter": {
        "autocomplete_filter": {
            "type":     "edge_ngram",
            "min_gram": 1,
            "max_gram": 20
        }
    }
}

2> 在自定义分析器 autocomplete 中使用上面这个 token 过滤器
{
    "analyzer": {
        "autocomplete": {
            "type":      "custom",
            "tokenizer": "standard",
            "filter": [
                "lowercase",
                "autocomplete_filter" #自定义的 edge-ngram token 过滤器
            ]
        }
    }
}
这个分析器使用 standard 分词器将字符串拆分为独立的词,并且将它们都变成小写形式,然后为每个词生成
一个边界 n-gram

3> 完整流程
$ PUT /trade
{
    "settings": {
        "number_of_shards": 1, 
        "analysis": {
            "filter": {
                "autocomplete_filter": { 
                    "type":     "edge_ngram",
                    "min_gram": 1,
                    "max_gram": 20
                }
            },
            "analyzer": {
                "autocomplete": {
                    "type":      "custom",
                    "tokenizer": "standard",
                    "filter": [
                        "lowercase",
                        "autocomplete_filter" 
                    ]
                }
            }
        }
    }
}

4> 将分析器应用到具体字段
$ PUT /trade/_mapping/share
{
    "my_type": {
        "properties": {
            "name": {
                "type":     "string",
                "analyzer": "autocomplete"
            }
        }
    }
}

5> 创建测试文档
$ POST /trade/share/_bulk
{ "index": { "_id": 1 }}
{ "name": "Brown foxes" }
{ "index": { "_id": 2 }}
{ "name": "Yellow furballs" }

6> 查询
$ GET /trade/share/_search
{
    "query": {
        "match": {
            "name": "brown fo"
        }
    }
}
#返回值
{

  "hits": [
     {
        "_id": "1",
        "_score": 1.5753809,
        "_source": {
           "name": "Brown foxes"
        }
     },
     {
        "_id": "2",
        "_score": 0.012520773,
        "_source": {
           "name": "Yellow furballs"
        }
     }
  ]
}
满足第二个文档,因为 furballs 是以 f 、 fu 、 fur 形式索引的

如果需要保证倒排索引表中包含边界 n-grams 的每个词,但是只想匹配用户输入的完整词组
( brown 和 fo ),可以通过在索引时使用 autocomplete 分析器,并在搜索时使用 standard 标准分析器来
实现这种想法,只要改变查询使用的搜索分析器 analyzer 参数即可
$ GET /trade/share/_search
{
    "query": {
        "match": {
            "name": {
                "query":    "brown fo",
                "analyzer": "standard" #覆盖了 name 字段 analyzer 的设置
            }
        }
    }
}
也可以在映射中,为 name 字段分别指定 index_analyzer 和 search_analyzer
$ PUT /trade/share/_mapping
{
    "my_type": {
        "properties": {
            "name": {
                "type":            "string",
                "index_analyzer":  "autocomplete", #在索引时,使用 autocomplete 分析器生成边界 n-grams 的每个词
                "search_analyzer": "standard" #在搜索时,使用 standard 分析器只搜索用户输入的词
            }
        }
    }
}