赞
踩
Elasticsearch模糊查询
不计算相关度评分
前缀搜索匹配的是term,而不是field。即搜索倒排索引
前缀搜索的性能很差
前缀搜索没有缓存
前缀搜索尽可能把前缀长度设置的更长命中索引越少,性能会好
要注意分词器,如果分词器分词了会导致前缀匹配失败.尤其是中文要设置中文分词器
// 创建prefix索引; 索引最大最小长度
//含义:对词项继续创建倒排索引. 指的是比如一个词Elasticsearch, el建一个倒排索引,ela再建一个,根据你的min和max; 索引的基础上继续创建索引,浪费空间,提高性能;
前缀索引要注意分词;
##没有分词的前缀索引查询 POST /my_index1/_bulk?filter_path=items.*.error {"index":{"_id":"1"}} {"text":"城管打电话喊商贩去摆摊摊"} {"index":{"_id":"2"}} {"text":"笑果文化回应商贩老农去摆摊"} {"index":{"_id":"3"}} {"text":"老农耗时17年种出椅子树"} {"index":{"_id":"4"}} {"text":"夫妻结婚30多年AA制,被城管抓"} {"index":{"_id":"5"}} {"text":"黑人见义勇为阻止抢劫反被铐住"} GET my_index1/_search { "query": { "prefix": { "text": { "value": "城管" } } } } ##有中文分词的前缀索引 ##filter_path=items.*.error 这个表示只显示错误信息 ##设置mapping 先把mapping模板查出来 DELETE my_index2 GET my_index2/_mapping PUT my_index2 { "mappings": { "properties": { "text": { "type": "text", "analyzer": "ik_max_word", // 创建prefix索引; 索引最大最小长度 //含义:对词项继续创建倒排索引. 指的是比如一个词Elasticsearch, el建一个倒排索引,ela再建一个,根据你的min和max; 索引的基础上继续创建索引,浪费空间,提高性能; "index_prefixes": { "min_chars":2, "max_chars":4 }, "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } } } } } POST /my_index2/_bulk?filter_path=items.*.error {"index":{"_id":"1"}} {"text":"城管打电话喊商贩去摆摊摊"} {"index":{"_id":"2"}} {"text":"笑果文化回应商贩老农去摆摊"} {"index":{"_id":"3"}} {"text":"老农耗时17年种出椅子树"} {"index":{"_id":"4"}} {"text":"夫妻结婚30多年AA制,被城管抓"} {"index":{"_id":"5"}} {"text":"黑人见义勇为阻止抢劫反被铐住"} GET my_index2/_search GET my_index2/_search { "query": { "prefix": { "text": { "value": "城管" } } } }
通配符也匹配的是term
##英文通配符数据 POST /product_en/_bulk?filter_path=iterm.*.error {"index":{"_id":"1"}} {"title":"my english","desc":"shouji zhong de zhandouji","price":3999,"tags":["xingjiabi","fashao","buka","1"]} {"index":{"_id":"2"}} {"title":"xiaomi nfc phone","desc":"zhichi quangongneng nfc,shouji zhong de jianjiji","price":4999,"tags":["xingjiabi","fashao","gongjiaoka","asd2fgas"]} {"index":{"_id":"3"}} {"title":"nfc phone","desc":"shouji zhong de hongzhaji","price":2999,"tags":["xingjiabi","fashao","menjinka","as345"]} {"title":{"_id":"4"}} {"text":"xiaomi erji","desc":"erji zhong de huangmenji","price":999,"tags":["low","bufangshui","yinzhicha","4dsg"]} {"index":{"_id":"5"}} {"title":"hongmi erji","desc":"erji zhong de kendeji","price":399,"tags":["lowbee","xuhangduan","zhiliangx","sdg5"]} GET product_en/_search { "query": { "wildcard": { // 加keyword和不加是有区别 "title.keyword": { "value": "nfc*" } } } }
上边代码加keyword和不加是有区别的, keyword是不会分词的,field是会分词的
指的是允许使用正则表达式中哪些通配符
ALL
启用所有可选操作符。
COMPLEMENT
启用操作符。可以使用对下面最短的模式进行否定。例如
a~bc # matches 'adc' and 'aec' but not 'abc'
INTERVAL
启用<>操作符。可以使用<>匹配数值范围。例如
foo<1-100> # matches 'foo1', 'foo2' ... 'foo99', 'foo100'
foo<01-100> # matches 'foo01', 'foo02' ... 'foo99', 'foo100'
INTERSECTION
启用&操作符,它充当AND操作符。如果左边和右边的模式都匹配,则匹配成功。例如:
aaa.+&.+bbb # matches 'aaabbb'
ANYSTRING
启用@操作符。您可以使用@来匹配任何整个字符串。
您可以将@操作符与&和~操作符组合起来,创建一个“everything except”逻辑。例如:
@&~(abc.+) # matches everything except terms beginning with 'abc'
主要是解决你输入错误能智能纠错的功能,本质也是模糊查询
常见的如:
缺少字符/多字符/混淆字符(输入错了)/顺序颠倒
GET <index>/_search
{
"query": {
"fuzzy": {
"<field>": {
"value": "<keyword>"
}
}
}
}
value必输项
比如你有如下数据:
"hits" : [ { "_index" : "product_en", "_type" : "_doc", "_id" : "2", "_score" : 0.8829135, "_source" : { "title" : "xiaomi nfc phone", "desc" : "zhichi quangongneng nfc,shouji zhong de jianjiji", "price" : 4999, "tags" : [ "xingjiabi", "fashao", "gongjiaoka", "asd2fgas" ] } } ]
以下查询 都可以查出数据
GET product_en/_search
{
"query": {
"fuzzy": {
"title": {
// "value": "xiaoi"
// "value": "mixiao"
// "ixaomi"
"value": "xiaohi"
}
}
}
}
根据以上原理我们知道, 输入错误的数量是有限制的. 那么哪里限制的? 怎么修改? 设置多少合适呢
我们输入错几个字符可以匹配呢?
把错误的字符修正成正确需要的步骤数量,称为编辑距离. 这距离计算跟特定的计算公式有关系:
两段文本之间的Damerau-Levenshtein距离是使一个字符串与另一个字符串匹配所需的插入、删除、替换和调换的数量
距离公式:lucene使用Levenshtein算法,es使用改进版Damerau-Levenshtein,
如axe=>aex不同算法需要步骤: Levenshtein=2 Damerau-Levenshtein=1
这个距离越大允许错的字符就越多.
但是这个距离并非越大越好,越大召回率越高,但是召回率高不代表准确,也许更不准确了.
ES默认的编辑距离编辑距离,(0,1,2)
value: 必须,关键词
fuzziness: 可选,定义编辑距离,es默认(0,1,2);可以设置"AUTO",es会根据字符串长度动态的取值.
transpositions:(可选,布尔值)指示编辑是否包括两个相邻字符的变位(ab→ba)。默认为true。影响某些编辑距离的计算结果.true的话是改进版对换距离为1,如果false就变为2了.
GET product_en/_search
{
"query": {
"fuzzy": {
"title": {
"value": "ixaomi",
//"fuzziness": "AUTO"
"fuzziness": 5
}
}
}
}
性能差
允许搜索词最后一个词项作为前缀再次检索
匹配流程:
最后一个词项作为前缀,匹配所有词->再使用搜索词剩余前缀再次前缀匹配
整个过程比较耗费性能的.
示例
abc cde fg
比如用这个词作为短语匹配的搜索词,它首先找以fg
开头的满足的所有词项,在这些词项中再去匹配abc cde
开头的.
match_phrase_prefix与match_phrase相同,但是它多了一个特性,就是它允许在文本的最后一个词项(term)上的前缀匹配,
如果是一个单词,比如a,它会匹配文档字段所有以a开头的文档;
如果是一个短语,比如 “it is horse” ,他会先在倒排索引中做以horse做前缀搜索,然后在匹配到的doc中做match_phrase查询
如何避免匹配词过多呢?
可以使用max_expentions
.这个参数默认值是50
这里尤其要注意max_expentions=1时并不代表实际返回结果就是1个. 这里的1每个分片限制的数量, 如果有多个分片的话每个分片都可能匹配到一个(如果匹配不到就没办法了)
使用参数slop
GET product_en/_search { "query": { "match_phrase": { "desc": "shouji zhong de" } } } GET product_en/_search ##test expansions ##验证虽然max_expansions=1但是依然返回了多个结果 GET product_en/_search { "query": { "match_phrase_prefix": { "desc": { "query": "shouji zhong", "max_expansions": 1 } } } } ##test slop ## GET product_en/_search { "query": { "match_phrase_prefix": { "desc": { //源数据"shouji zhong de hongzhaji",搜索词:"shouji hongzhaji"时slop=2是可以的slop=1就不行了 //除了上面间隔词项,顺序颠倒也可以的,搜索词:"de zhong hongzhaji" "query": "de zhong shouji hongzhaji", "max_expansions": 50 ,"slop": 5 } } } }
可以用作切词方式
ngram是按照字符进行切词
根据如下代码查看效果:
GET _analyze
{
"tokenizer": "ngram",
"text": ["abc def opq"]
}
具体怎么切词可以通过min_gram max_gram来控制
作为过滤器
##也可以过滤器
GET _analyze
{
"tokenizer": "standard",
"filter": ["ngram"],
"text": ["abc def opq"]
}
一个分析器包含
##test data POST /test_idx_001/_bulk { "index": { "_id": "1"} } { "text": "my english" } { "index": { "_id": "2"} } { "text": "my english is good" } { "index": { "_id": "3"} } { "text": "my chinese is good" } { "index": { "_id": "4"} } { "text": "my japanese is nice" } { "index": { "_id": "5"} } { "text": "my disk is full" } DELETE test_idx_001 PUT test_idx_001 { "settings": { "analysis": { "analyzer": { "my_analyzer":{ "type": "custom", "tokenizer":"standard", "filter": "my_filter_ngram" } }, "tokenizer": {}, "filter": { "my_filter_ngram":{ "type": "ngram", "min_gram":2, "max_gram":3 } }, "char_filter": {} } }, "mappings": { "properties": { "myproperties":{ "type": "text", "analyzer": "my_analyzer", "search_analyzer": "standard" } } } }
测试ngram个数
##test data POST /test_idx_001/_bulk { "index": { "_id": "1"} } { "text": "my english" } { "index": { "_id": "2"} } { "text": "my english is good" } { "index": { "_id": "3"} } { "text": "my chinese is good" } { "index": { "_id": "4"} } { "text": "my japanese is nice" } { "index": { "_id": "5"} } { "text": "my disk is full" } DELETE test_idx_001 PUT test_idx_001 { "settings": { "analysis": { "filter": { "my_filter_ngram": { "type": "edge_ngram", "min_gram": 2, "max_gram": 3 } }, "analyzer": { "my_analyzer": { "type": "custom", "tokenizer": "standard", "filter": "my_filter_ngram" } } } }, "mappings": { "properties": { "text": { "type": "text", "analyzer": "my_analyzer", "search_analyzer": "standard" } } } } GET test_idx_001/_search GET test_idx_001/_search { "query": { "match_phrase": { //这里的每个词项必须在2,3范围内因为分词就是按照这个数量分词的,这数量是在上面定义的 //比如你输入engl就查不到数据了 "text": "my eng is goo" } } }
ngram如果设置的过小会占用大量的磁盘空间,因为它会创建很多倒排索引
edge-ngram会节省空间
edge与ngram的区别在于它只对前N个字母生成索引.具体:
比如my english
我们设置min_gram=2;max_gram=3; 它只会对my eng进行索引;
ngram会对my, my空格, 空格e, 空格en, eng,…等等依次做索引
即ngram不仅前缀,还可以中缀搜索
DELETE test_idx_001 PUT test_idx_001 { "settings": { "analysis": { "analyzer": { "my_analyzer":{ "type": "custom", "tokenizer": "standard", "filter": "myfitler" } }, "filter": { "myfitler":{ "type":"edge_ngram", "min_gram": 2, "max_gram": 3 } }, "tokenizer": {} } }, "mappings": { "properties": { "text":{ "type": "text", "analyzer": "my_analyzer", "search_analyzer": "standard" } } } } GET test_idx_001/_search { "query": { "match_phrase": { "text": "my eng" } } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。