ES第十三天 您所在的位置:网站首页 电脑如何使用相机镜头功能 ES第十三天

ES第十三天

2024-01-25 19:14| 来源: 网络整理| 查看: 265

前言

ES的无论什么搜索,对于text类型字段其实都是基于倒排索引去进行搜索的,也就是进行分词后的,因此如果想像传统数据库一样的模糊匹配,一般可以使用它的keyword进行搜索。(keyword不会被分词) 以下的搜索在大型生产环境都不推荐使用。

前缀索引查询

以xx开头的搜索,不计算相关度评分,和filter比,没有bitcache。前缀搜索,尽量把前缀长度设置的更长,性能差,一般大规模产品不使用。(是去倒排索引中去匹配前缀,需要遍历每一个倒排索引才能找到所有匹配的)

语法 GET index/_search { "query": { "prefix": { "title": { "value": "text" } } } }

为了加快前缀搜索速度,可以设置默认的 前缀索引 (空间换时间)

PUT my_index { "mappings": { "properties": { "text": { "type": "text", "index_prefixes": { "min_chars":2, "max_chars":4 } } } } }

上面这个设置的意思是,把分词后的每个词项的2-4个字符额外进行建立前缀倒排索引,从而提高后续前缀匹配的速度,但是占用空间也是相对变大。 index_prefixes: 默认 “min_chars” : 2, “max_chars” : 5 。

通配符查询

通配符查询类似于正则,但没正则强大,允许对匹配表达式进行通配符占位。

表示匹配任意长度的任意字符 ? 表示匹配一个任意字符 […]则表示匹配括号中列出的字符中的任意一个 [!..]表示不匹配括号中列出的字符中的任意一个 语法 { "query": { "wildcard": { "text": { "value": "eng?ish" } } } } 正则查询

regexp查询的性能可以根据提供的正则表达式而有所不同。为了提高性能,应避免使用通配符模式,如.或 .?+未经前缀或后缀

语法 { "query": { "regexp": { "name": { "value": "[\\s\\S]*nfc[\\s\\S]*", "flags": "ALL", "max_determinized_states": 10000, #防止正则内存过大的保护措施 "rewrite": "constant_score" } } } }

关于参数flags,有几个配置可选:

ALL (Default)

启用所有可选操作符。

COMPLEMENT

启用操作符。可以使用对下面最短的模式进行否定。例如 a~bc # matches ‘adc’ and ‘aec’ but not ‘abc’ INTERVAL 启用操作符。可以使用匹配数值范围。例如 foo # matches ‘foo1’, ‘foo2’ … ‘foo99’, ‘foo100’ foo # matches ‘foo01’, ‘foo02’ … ‘foo99’, ‘foo100’

INTERSECTION

启用&操作符,它充当AND操作符。如果左边和右边的模式都匹配,则匹配成功。例如: aaa.+&.+bbb # matches ‘aaabbb’

ANYSTRING

启用@操作符。您可以使用@来匹配任何整个字符串。 您可以将@操作符与&和~操作符组合起来,创建一个“everything except”逻辑。例如: @&~(abc.+) # matches everything except terms beginning with ‘abc’

Fuzzy模糊(容错)匹配 场景

1、混淆字符 (box → fox) 2、缺少字符 (black → lack) 3、多出字符 (sic → sick) 4、颠倒次序 (act → cat)

在出现上面情况的时候,我们也希望用户可以搜索到想要的内容,那么这个时候可以使用fuzzy。

语法

以下两种都可以:

1、第一种-手动档 可以手动多指定一些参数,但一般也不建议改动

{ "query": { "fuzzy": { "desc": { "value": "quangemneng", "fuzziness": 5 } } } }

① value:(必需,字符串) ② fuzziness:(可选,字符串)最大误差 并非越大越好, 因为大了虽然召回率高 但是结果不准确 1) 两段文本之间的Damerau-Levenshtein距离是使一个字符串与另一个字符串匹配所需的插入、删除、替换和调换的数量 2) 距离公式:Levenshtein是lucene的,es改进版:Damerau-Levenshtein 3) axe=>aex Levenshtein=2 Damerau-Levenshtein=1

③ max_expansions:可选,整数)匹配的最大词项数量。默认为50。 ④ prefix_length:创建扩展时保留不变的开始字符数。默认为0 1)避免在max_expansions参数中使用较高的值,尤其是当prefix_length参数值为时0。max_expansions由于检查的变量数量过多,参数中的高值 可能导致性能不佳。

⑤ transpositions:(可选,布尔值)指示编辑是否包括两个相邻字符的变位(ab→ba)。默认为true。 ⑥ rewrite:(可选,字符串)用于重写查询的方法 https://www.elastic.co/cn/blog/found-fuzzy-search#performance-considerations

2、第二种,"自动挡"时代

{ "query": { "match": { "desc": { "query": "quangengneng nfc", "fuzziness": "AUTO" } } } } match_phrase_prefix(最简陋的Suggest)

match_phrase_prefix与match_phrase相同,但是它多了一个特性,就是它允许在文本的最后一个词项(term)上的前缀匹配,如果 是一个单词,比如a,它会匹配文档字段所有以a开头的文档,如果是一个短语,比如 “this is ma” ,他会先在倒排索引中做以ma做前缀搜索,然后在匹配到的doc中做match_phrase查询,(网上有的说是先match_phrase,然后再进行前缀搜索, 是不对的)

语法 { "query": { "match_phrase_prefix": { "desc": { "query": "zhichi quangongneng nf", "analyzer": "whitespace", "max_expansions": 1, "slop": 2, "boost": 1 } } } } 参数 analyzer

指定何种分析器来对该短语进行分词处理

max_expansions

限制匹配的最大term数。

一般来讲,前缀匹配是会全索引进行扫描匹配的,为了提高效率,可以进行限制它可以进行扫描的索引的个数,但即使设置为1,也不意味着返回的doc结果只有一个,主要有2点: 1、一个索引可能有多个doc 2、这个限制扫描个数是针对每个分片来说的(每个分片都可以扫描1个),因此也就是说该索引的每个分片扫描的第一个term都可能被匹配上。 boost

用于设置该查询的权重

slop

允许短语间的词项(term)间隔

slop 参数告诉 match_phrase 查询词条相隔多远时仍然能将文档视为匹配, 什么是相隔多远? 意思是说为了让查询和文档匹配你需要移动词条多少次?举个例子:

如果我们输入的是:de zhong shouji hongzhaji 而期望匹配的句子是:shouji zhong de hongzhaji 那么要怎么移动呢? 1、首先要把“shouji”词条向左移动2个词条: shouji/de zhong shouji hongzhaji 2、接下来在把de向右移动2个词条: shouji zhong de shouji hongzhaji

这样下来,共需要4次移动,因此slop需要设置为4的时候,输入的才能匹配上。

N-gram-tokenFilter

上面的前缀匹配还是存在性能问题,那有没有相对好一点的方法呢? 我们可以从分词角度出发。 在设置索引的时候,可以进行指定分词器的相关属性,其中有一项是指定fliter,可以通过指定ngram:

{ "settings": { "analysis": { "filter": { "2_3_grams": { "type": "ngram", "min_gram": 1, "max_gram": 2 } }, "analyzer": { "my_ngram": { "type":"custom", "tokenizer": "standard", "filter": [ "2_3_grams" ] } } } }, "mappings": { "properties": { "text": { "type": "text", "analyzer":"my_ngram", "search_analyzer": "standard" } } } }

经过ngram设置的min_gram:1和"max_gram": 3,分析以下语句:

GET _analyze { "tokenizer": "ik_max_word", "filter": [ "edge_ngram" ], "text": "reba always" }

会先按最小粒度1进行拆分,也就是拆分出“r”,“e”,“b”,“a”,“a”,“l”,“w”,“a”,“y”,“s” 然后按粒度2拆分,拆分成:“re”,“eb”,“ba”,“al”,“lw”,“wa”,“ay”,“ys” 然后按最大粒度3进行拆分,拆分成:“reb”,“eba”,“alw”,“lwa”,“way”,“ays”

Edge-N-gram-tokenFilter

另外一个filter,根据min_gram和max_gram对分词的开头部分进行拆分。 这个可能更常用一些,因为更多的我们的搜索是从一个词的开头进行部分搜索,而不是中间进行搜索。

GET _analyze { "tokenizer": "ik_max_word", "filter": [ "edge_ngram" ], "text": "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



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有