模糊查询
前缀搜索:prefix
概念:以xx开头的搜索,不计算相关度评分。
注意:
-
前缀搜索匹配的是term,而不是field。
-
前缀搜索的性能很差
-
前缀搜索没有缓存
-
前缀搜索尽可能把前缀长度设置的更长
语法:
jsonGET <index>/_search { "query": { "prefix": { "<field>": { "value": "<word_prefix>" } } } } index_prefixes: 默认 "min_chars" : 2, "max_chars" : 5
bash
PUT my_index
{
"mappings": {
"properties": {
"text": {
"analyzer": "ik_max_word",
"type": "text",
"index_prefixes":{
"min_chars":2,
"max_chars":4
},
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}
}
}
}
PUT my_index的含义是向Elasticsearch发送一个PUT请求来创建一个名为"my_index"的索引。
在Elasticsearch中,索引是用于存储和检索数据的容器。每个索引都有一个或多个映射(mapping),这些映射定义了索引中字段的类型、分析器、字段属性等。在提供的JSON中,"mappings"字段的作用是指定索引的映射定义。它定义了索引中包含的字段及其属性。
在"properties"字段下,定义了一个名为"text"的字段。该字段的配置如下:
"analyzer": "ik_max_word":指定使用"ik_max_word"分析器,这是一个用于中文分词的分析器。
"type": "text":字段类型设置为"text",表示这是一个文本字段,可以用于全文搜索。
"index_prefixes":定义了前缀搜索的参数,其中"min_chars"和"max_chars"分别表示最小和最大前缀长度。
"fields":定义了多重字段(multi-fields),即一个字段可以有多个不同的表示。在这里,定义了一个名为"keyword"的子字段,其类型为"keyword",表示这是一个不分析的字段,通常用于精确匹配和排序。
"ik_max_word"是IK分词器的一个变种,用于中文分词。它试图将文本尽可能细粒度地分割成单词,以提供更好的全文搜索效果。
"index_prefixes"和"fields"的用途是提供对文本字段的额外索引方式。例如,"index_prefixes"使得可以使用前缀搜索,而"fields"中的"keyword"子字段使得可以进行精确匹配和排序,而不是基于分析器的全文搜索。
综合上述配置,这个映射定义了一个名为"text"的文本字段,该字段使用"ik_max_word"分析器进行中文分词,并提供了前缀搜索和精确匹配的不同索引方式。
bash
GET my_index/_mapping
POST /my_index/_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_index/_search
GET my_index/_mapping
GET _analyze
{
"analyzer": "ik_max_word",
"text": ["城管打电话喊商贩去摆摊摊"]
}
GET my_index/_search
{
"query": {
"prefix": {
"text": {
"value": "摊摊"
}
}
}
}
通配符:wildcard
概念:通配符运算符是匹配一个或多个字符的占位符。例如,*通配符运算符匹配零个或多个字符。您可以将通配符运算符与其他字符结合使用以创建通配符模式。
注意:
-
通配符匹配的也是term,而不是field
语法:
jsonGET <index>/_search { "query": { "wildcard": { "<field>": { "value": "<word_with_wildcard>" } } } }
bash
# 通配符
DELETE my_index
POST /my_index/_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 product_en
POST /product_en/_bulk
{ "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 my_index/_search
GET product_en/_search
GET my_index/_mapping
GET product_en/_mapping
GET my_index/_search
{
"query": {
"wildcard": {
"text.keyword": {
"value": "my eng*ish"
}
}
}
}
GET my_index/_search 是一个Elasticsearch的HTTP请求,用于查询名为my_index的索引库中的所有文档。其中,_search是Elasticsearch的API端点,用于执行搜索查询。
wildcard查询用于模糊匹配,支持通配符。*代表任意多个字符,?代表单个字符。
在wildcard查询中,text.keyword字段表示要在text字段的keyword子字段中执行通配符查询。value属性是查询模式,用于匹配文档中的字段值。
"value": "my eng*ish"表示查询text.keyword字段中包含"my"开头,以"ish"结尾,中间任意字符的字符串。例如,它会匹配"my english"、"my english speaking"等。
整个查询请求的含义是:在my_index索引库中,查找text.keyword字段值匹配"my eng*ish"模式的所有文档。
需要注意的是,wildcard查询可能不如其他类型的查询(如match、term)高效,因为它需要对索引进行全扫描,以找到匹配模式的文档。因此,在需要高效查询的场景中,可能需要选择其他类型的查询。
GET product_en/_mapping
#exact value
GET product_en/_search
{
"query": {
"wildcard": {
"tags.keyword": {
"value": "men*inka"
}
}
}
}
正则:regexp
概念:regexp查询的性能可以根据提供的正则表达式而有所不同。为了提高性能,应避免使用通配符模式,如.或 .?+未经前缀或后缀
语法:
json
GET <index>/_search
{
"query": {
"regexp": {
"<field>": {
"value": "<regex>",
"flags": "ALL",
}
}
}
}
flags
-
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'
bash
GET product_en/_search
{
"query": {
"regexp": {
"title": "[\\s\\S]*nfc[\\s\\S]*"
}
}
}
该查询请求的含义是:在product_en索引中,通过正则表达式搜索title字段,查找包含nfc子串的文档。
解释如下:
GET product_en/_search:这是Elasticsearch的HTTP GET请求的基本结构,用于从product_en索引中检索数据。_search端点用于执行搜索查询。
"query"字段:在Elasticsearch查询中,query字段用于定义搜索条件。在此查询中,使用了regexp查询,它是基于正则表达式的查询。
"regexp"查询:regexp查询允许用户通过正则表达式模式来匹配文档中的字段值。在此查询中,它被用于匹配title字段。
正则表达式"[\s\S]nfc[\s\S]":这个正则表达式的匹配规则如下:
[\s\S]:匹配任何字符,包括空格和非空格字符。
:匹配前面的字符零次或多次。
nfc:匹配字面字符串"nfc"。
再次使用[\s\S] ,表示"nfc"前后可以有任何字符(包括空格和非空格字符)。因此,该正则表达式匹配title字段中包含"nfc"的文档,且"nfc"前后可以有任何字符。
综合以上信息,该查询请求在product_en索引中查找title字段中包含"nfc"的文档,且"nfc"前后可以有任何字符。
bash
GET product_en/_search
{
"query": {
"regexp": {
"desc": {
"value": "zh~dng",
"flags": "COMPLEMENT"
}
}
}
}
GET product_en/_search 是一个Elasticsearch的HTTP请求,用于查询名为product_en的索引库中的所有文档。_search是Elasticsearch的API端点,用于执行搜索查询。
在这个查询中,使用了正则表达式查询(regexp),用于匹配符合特定正则表达式的字段值。具体来说,它试图匹配desc字段中包含正则表达式zh~dng的文档。
"value": "zh~dng"表示要匹配的正则表达式。在正则表达式中,~通常表示匹配一个单词的边界。但在这个例子中,zh~dng可能并不是一个有效的正则表达式,因为~通常用于单词边界,而zh~dng更像是字符z、h、~、d和n的序列,并没有明确的单词边界含义。
"flags": "COMPLEMENT"表示使用的正则表达式标志。COMPLEMENT标志表示取反,即匹配所有不符合正则表达式的文档。
然而,zh~dng可能并不是一个合适的正则表达式,因为它并不符合常见的正则表达式语法和用途。通常,在Elasticsearch中使用正则表达式查询时,我们会期望value参数中的表达式是一个有效的正则表达式,用于匹配特定的字符串模式。
因此,这个查询可能并不会按照预期工作,除非desc字段中的文档确实包含zh~dng这个字符串,或者这个查询是用于测试某种特定的正则表达式行为。
需要注意的是,Elasticsearch的正则表达式查询是基于Apache Lucene的正则表达式引擎,所以正则表达式的语法和标志可能与其他语言或工具中的有所不同。
另外,使用COMPLEMENT标志时,请确保您的查询是清晰的,并且了解它将返回不符合正则表达式的文档。在实际应用中,确保您的正则表达式是有效的,并且与您的查询意图相匹配。
bash
GET product_en/_search
{
"query": {
"regexp": {
"tags.keyword": {
"value": ".*<2-3>.*",
"flags": "INTERVAL"
}
}
}
}
查询包含2-3的数据
这是一个Elasticsearch查询语句,用于在product_en索引中搜索数据。这个查询语句使用了正则表达式查询(regexp),它允许用户通过正则表达式模式来匹配文档中的字段值。
GET product_en/_search:
这部分是Elasticsearch的HTTP GET请求的基本结构,用于从product_en索引中检索数据。_search端点用于执行搜索查询。regexp查询:
regexp查询是Elasticsearch中的一种查询类型,它使用正则表达式来匹配文档中的字段值。这种查询类型特别适用于需要基于模式匹配的场景。
"tags.keyword":
这表示查询的是tags.keyword字段。tags可能是一个包含多个标签的字段,而keyword通常表示该字段的值是精确匹配的,不会被分词。
"value": ".<2-3>.":
这是正则表达式的模式。这里的模式尝试匹配任何包含<2-3>字符串的文本。但是,.*<2-3>.*并不是一个有效的正则表达式,因为它没有定义<2-3>应该匹配的具体内容。通常,<2-3>会被当作字面量而不是正则表达式的一部分,这意味着它会尝试匹配包含这个字符串的文档。
"flags": "INTERVAL":
flags参数用于指定正则表达式的匹配选项。然而,INTERVAL并不是Elasticsearch中regexp查询的有效标志。标准的regexp标志包括ALL、ANYSTRING、COMPLEMENT、EMPTY、INTERSECTION、INTERVAL、NONE、NOTEMPTY和NOTNONE。其中,INTERVAL标志用于定义重复数量的区间,但它通常与{}一起使用,例如{2,3}表示匹配2到3次重复。在这里,flags的INTERVAL值可能是错误的,或者该查询可能尝试使用一个特定于应用程序或自定义的正则表达式标志。
这个查询整体上试图找到tags.keyword字段中包含<2-3>字符串的文档,但由于正则表达式模式不正确,以及flags参数中可能存在的错误,这个查询可能不会返回预期的结果。正确的正则表达式模式取决于<2-3>应如何解释,以及是否应该使用特定的标志来影响匹配过程。
这个查询可能适用于需要基于标签中的特定模式或特定值进行搜索的场景,例如,如果<2-3>是一个特定的标签值,并且你想找到所有包含这个标签的文档。然而,由于正则表达式和标志的错误,这个查询可能需要进行修正才能正常工作。
模糊查询:fuzzy
混淆字符 (b ox → fox) 缺少字符 (black → lack)
多出字符 (sic → sick ) 颠倒次序 (ac t → cat)
语法
json
GET <index>/_search
{
"query": {
"fuzzy": {
"<field>": {
"value": "<keyword>"
}
}
}
}
参数:
-
value:(必须,关键词)
-
fuzziness:编辑距离,(0,1,2)并非越大越好,召回率高但结果不准确
-
两段文本之间的Damerau-Levenshtein距离是使一个字符串与另一个字符串匹配所需的插入、删除、替换和调换的数量
-
距离公式:Levenshtein是lucene的,es改进版:Damerau-Levenshtein,
axe=>aex Levenshtein=2 Damerau-Levenshtein=1
-
-
transpositions:(可选,布尔值)指示编辑是否包括两个相邻字符的变位(ab→ba)。默认为true。
bash
GET product_en/_search
{
"query": {
"fuzzy": {
"desc": {
"value": "zhandou",
"fuzziness": "2"
}
}
}
}
该查询请求的含义是:在product_en索引中,使用模糊查询(fuzzy query)在desc字段中查找包含与"quangongneng nfc"相似词项的文档。
解释如下:
GET product_en/_search:这是Elasticsearch的HTTP GET请求的基本结构,用于从product_en索引中检索数据。_search端点用于执行搜索查询。
"query"字段:在Elasticsearch查询中,query字段用于定义搜索条件。在此查询中,使用了fuzzy查询,它是基于模糊匹配的查询,用于查找与指定词项相似的词项。
"fuzzy"查询:fuzzy查询在Elasticsearch中允许用户通过编辑距离(fuzziness)来匹配与指定词项相似的词项。它基于Levenshtein距离(也称为编辑距离)来度量两个词项之间的相似性。
"value"字段:value参数定义了要搜索的原始词项,即"quangongneng nfc"。
"fuzziness"字段:fuzziness参数定义了最大的编辑距离,用于确定与原始词项相似的词项。在这里,fuzziness设置为"2",意味着查询将匹配与"quangongneng nfc"在最多两个字符内相似的词项。
综合以上信息:整个查询请求在product_en索引中查找desc字段中包含与"quangongneng nfc"相似的词项的文档,其中相似度由最多两个字符的编辑距离确定。
此查询将返回与"quangongneng nfc"在最多两个字符内相似的所有词项所在的文档。
短语前缀:match_phrase_prefix
match_phrase:
-
match_phrase会分词
-
被检索字段必须包含match_phrase中的所有词项并且顺序必须是相同的
-
被检索字段包含的match_phrase中的词项之间不能有其他词项
概念:
match_phrase_prefix与match_phrase相同,但是它多了一个特性,就是它允许在文本的最后一个词项(term)上的前缀匹配,如果 是一个单词,比如a,它会匹配文档字段所有以a开头的文档,如果是一个短语,比如 "this is ma" ,他会先在倒排索引中做以ma做前缀搜索,然后在匹配到的doc中做match_phrase查询,(网上有的说是先match_phrase,然后再进行前缀搜索, 是不对的)
参数
-
analyzer 指定何种分析器来对该短语进行分词处理
-
max_expansions 限制匹配的最大词项
-
boost 用于设置该查询的权重
-
slop 允许短语间的词项(term)间隔:slop 参数告诉 match_phrase 查询词条相隔多远时仍然能将文档视为匹配 什么是相隔多远? 意思是说为了让查询和文档匹配你需要移动词条多少次?
原理解析:https://www.elastic.co/cn/blog/found-fuzzy-search#performance-considerations
bash
GET product_en/_search
{
"query": {
"match_phrase_prefix": {
"desc": {
"query": "zhong hongzhaji",
"max_expansions": 50,
"slop": 3
}
}
}
}
这个查询请求的含义是:在product_en索引中,使用match_phrase_prefix查询在desc字段中查找与"zhong hongzhaji"相似词项的文档。
解释如下:
GET product_en/_search:这是一个Elasticsearch的HTTP GET请求,用于从product_en索引中检索数据。_search端点用于执行搜索查询。
match_phrase_prefix查询:这是一个特定类型的查询,它用于查找与指定词项在特定字段中相似(但不一定完全匹配)的词项。与match_phrase查询相比,match_phrase_prefix允许在最后一个词项上只匹配前缀,从而可以捕获更多与查询词项相似的词项。
"zhong hongzhaji":这是搜索的查询词项,表示用户想要查找与"zhong hongzhaji"相关的内容。
max_expansions: 50:这个参数定义了最后一个词项可以被重写(扩展)成多少个前缀。这里设置为50,意味着将尝试生成最多50个前缀来匹配文档中的词项。
slop: 3:这个参数用于定义在匹配词项时,允许词项之间的最大位移量。这里的值为3,表示在匹配过程中,词项之间的最大距离为3个词项。
整个查询语句的意图:这个查询请求的目的是在product_en索引中查找与"zhong hongzhaji"相关的文档,通过扩展前缀和允许一定的词项位移量,以捕获更多相似但不完全匹配的文档。
应用场景:这个查询可能用于类似搜索引擎的场景,当用户输入部分搜索词时,系统能够自动补全或推荐与用户输入相似的完整词项,以提供更精确的搜索结果。例如,在电商网站中,用户可能输入"zhong"作为商品名称的一部分,系统可以推荐完整的商品名称,如"zhong xiao mi"或"zhong xing"等。
这个查询使用了Elasticsearch的match_phrase_prefix查询类型,它允许用户输入部分搜索词,并自动补全或推荐与用户输入相似的完整词项,从而提供更精确和相关的搜索结果。
N-gram和edge ngram
tokenizer
json
GET _analyze
{
"tokenizer": "ngram",
"text": "reba always loves me"
}
token filter
json
GET _analyze
{
"tokenizer": "ik_max_word",
"filter": [ "ngram" ],
"text": "reba always loves me"
}
min_gram:创建索引所拆分字符的最小阈值
max_gram:创建索引所拆分字符的最大阈值
ngram:从每一个字符开始,按照步长,进行分词,适合前缀中缀检索
edge_ngram:从第一个字符开始,按照步长,进行分词,适合前缀匹配场景
bash
GET _analyze
{
"tokenizer": "ik_max_word",
"filter": [ "edge_ngram" ],
"text": "reba always loves me"
}
bash
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"
}
}
}
}
GET /my_index/_mapping
POST /my_index/_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" }
GET /my_index/_search
GET /my_index/_mapping
GET /my_index/_search
{
"query": {
"match_phrase": {
"text": "my eng is goo"
}
}
}
PUT my_index2
{
"settings": {
"analysis": {
"filter": {
"2_3_grams": {
"type": "edge_ngram",
"min_gram": 2,
"max_gram": 3
}
},
"analyzer": {
"my_edge_ngram": {
"type":"custom",
"tokenizer": "standard",
"filter": [ "2_3_grams" ]
}
}
}
},
"mappings": {
"properties": {
"text": {
"type": "text",
"analyzer":"my_edge_ngram",
"search_analyzer": "standard"
}
}
}
}
GET /my_index2/_mapping
POST /my_index2/_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" }
GET /my_index2/_search
{
"query": {
"match_phrase": {
"text": "my eng is goo"
}
}
}
GET _analyze
{
"tokenizer": "ik_max_word",
"filter": [ "ngram" ],
"text": "用心做皮肤,用脚做游戏"
}