Elasticsearch 搜索
prefix
前缀查询:以xx开头的搜索,不计算相关度评分,和filter比,没有bitcache。前缀搜索,尽量把前缀长度设置的更长,性能差,因为它会扫描倒排索引整张表,匹配每个term是否包含xx。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| 语法: GET index/_search { "query": { "prefix": { "title": { "value": "text" } } } }
参数: index_prefixes: 默认 "min_chars" : 2, "max_chars" : 5
|
1 2 3 4 5 6 7 8 9 10 11
| GET my_index/_search { "query": { "prefix": { "text": { "value": "myword" } } } }
|
使用index_prefixes
映射,ES会额外建立一个长度在2和5之间索引,在进行前缀匹配的时候效率会有很大的提高
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| PUT my_index { "mappings": { "properties": { "text": { "type": "text", "index_prefixes": { "min_chars":2, "max_chars":4 } } } } }
|
wildcard
通配符:通配符运算符是匹配一个或多个字符的占位符。例如,*通配符运算符匹配零个或多个字符。可以将通配符运算符与其他字符结合使用以创建通配符模式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
GET product/_search { "query": { "wildcard": { "name": { "value": "xia?mi" } } } }
输出结果: 能查出 "name" : "xiaomi nfc phone" 的数据
|
1 2 3 4 5 6 7 8 9 10 11 12 13
| GET product/_search { "query": { "wildcard": { "name.keyword": { "value": "xia?mi" } } } }
输出结果: 不能查出数据
|
regexp
正则:regexp查询的性能可以根据提供的正则表达式而有所不同。为了提高性能,应避免使用通配符模式,如.或 .?+未经前缀或后缀
1 2 3 4 5 6 7 8 9 10 11 12
| GET product/_search { "query": { "regexp": { "name": { "value": "[\\s\\S]*nfc[\\s\\S]*", "flags": "ALL" } } } }
|
1 2 3 4 5 6 7 8 9 10 11 12
| GET product/_search { "query": { "regexp": { "desc": { "value": ".*2020-05-20.*", "flags": "ALL" } } } }
|
无法匹配到上文中的注释数据,原因在于默认使用了standard
,会将日期拆成【2020】、【05】、【20】三个词汇,如果想要匹配,需要使用desc.keyword
进行全文匹配,但是这样性能十分低下。
而IK分词器很好的对日期进行了分词词项【2020-05-20】,对该索引指定IK分词器(需重建索引),即可查询到结果。
1 2 3 4 5 6 7 8 9 10 11 12
| PUT product { "mappings": { "properties": { "desc": { "type": "text", "analyzer": "ik_max_word", "search_analyzer": "ik_max_word" } } } }
|
fuzzy
混淆字符 (box → fox) 缺少字符 (black → lack)
多出字符 (sic → sick) 颠倒次序 (act → cat)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| 语法: GET /_search { "query": { "fuzzy": { "desc": { "value": "keyword" } } } }
参数: value:(必需,字符串) fuzziness:(可选,字符串)最大误差(距离) 并非越大越好, 召回率高 但是结果不准确
|
距离:两段文本之间的Damerau-Levenshtein距离是指一个字符串需要经过多少次操作之后才能变成另一个字符串。
距离公式:Levenshtein是lucene的,es改进版:Damerau-Levenshtein,axe=>aex Levenshtein=2
,而Damerau-Levenshtein=1
1 2 3 4 5 6 7 8 9 10 11 12
| GET /product/_search { "query": { "fuzzy": { "desc": { "value": "xioami", "fuzziness": 5 } } } }
|
1 2 3 4 5 6 7 8 9 10 11 12
| GET /product/_search { "query": { "match": { "desc": { "query": "quangengneng nfc", "fuzziness": "AUTO" } } } }
|
match_phrase_prefix
match_phrase_prefix与match_phrase相同,但是它多了一个特性,就是它允许在文本的最后一个词项(term)上的前缀匹配。
如果 是一个单词,比如a,它会匹配文档字段所有以a开头的文档,如果是一个短语,比如 “this is ma” ,他会先在倒排索引中做以ma做前缀搜索,然后在匹配到的doc中做match_phrase查询。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| 语法: GET /index/_search { "query": { "match_phrase_prefix": { "fieldName": { "query": "text" } } } }
参数 analyzer 指定何种分析器来对该短语进行分词处理 max_expansions 限制匹配到的最大词项,每个分片中匹配的结果达到max_expansions值后停止遍历倒排索引表 boost 用于设置该查询的权重 slop:允许短语间的词项(term)间隔,指为了让查询和文档匹配需要移动term多少(slop)次
|
1 2 3 4 5 6 7 8 9 10 11
| GET /product/_search { "query": { "match_phrase_prefix": { "desc": { "query": "zhichi nf", } } } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| GET /product/_search { "query": { "match_phrase_prefix": { "desc": { "query": "zhichi nf", "analyzer": "whitespace", "max_expansions": 1, "slop": 1, "boost": 1 } } } }
|
N-gram:token filter
1 2 3 4 5 6
| edge_ngram:是从第一个字符开始,按照步长,进行分词,适合前缀匹配场景,比如:订单号,手机号,邮政编码的检索 ngram:是从每一个字符开始,按照步长,进行分词,适合前缀中缀检索
参数: min_gram =1 最小步长 默认值 1 max_gram =1 最大步长 默认值 1
|
1 2 3 4 5 6 7 8 9 10 11
| 【edge_ngram】 拆词: "reba always loves me" min_gram =1 max_gram =1 #r a l m
min_gram =1 max_gram =2 #r a l m #re al lo me
min_gram =2 max_gram =3 #re al lo me #reb alw lov me
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| PUT my_index { "settings": { "analysis": { "filter": { "2_3_edge_ngram": { "type": "edge_ngram", "min_gram": 2, "max_gram": 3 } }, "analyzer": { "my_edge_ngram": { "type":"custom", "tokenizer": "standard", "filter": [ "2_3_edge_ngram" ] } } } }, "mappings": { "properties": { "text": { "type": "text", "analyzer":"my_edge_ngram", "search_analyzer": "standard" } } } }
|
1 2 3 4 5 6 7 8 9 10 11
| GET /my_index/_analyze { "analyzer": "my_edge_ngram" , "text": ["my english"] }
输出结果: my、en、eng
如果分词器把edge_ngram换成ngram,则输出结果如下: my、en、ng、gl、li、is、sh、eng、ngl、gli、lis、ish
|
1 2 3 4 5 6 7 8 9
| GET /my_index/_search { "query": { "match_phrase": { "text": "my eng is goo" } } }
|