1. 借鑒
極客時(shí)間 阮一鳴老師的Elasticsearch核心技術(shù)與實(shí)戰(zhàn)
Elasticsearch搜索引擎第十篇-Query DSL詳解
如何使Elasticsearch的前綴查詢(xún)(prefix query)效果同sql的like 'prefix%'
官方文檔 term-level-queries
官方文檔 regexp語(yǔ)法
Elasticsearch:fuzzy 搜索 (模糊搜索)
盤(pán)點(diǎn)Elasticsearch中的查詢(xún)套路
官方文檔 rewrite
2. 開(kāi)始
基于term的查詢(xún)
- term級(jí)別的查詢(xún)有以下幾種:term/terms/terms set,range,exists,prefix,wildcard,regexp,fuzzy,ids。
-
對(duì)輸入不做分詞,這點(diǎn)要注意
-
接下來(lái),我們以下列數(shù)據(jù)為例,來(lái)介紹以下基于term的查詢(xún).
POST /product/_bulk
{"index": { "_id": 1 }}
{"produceId":"HKXL-1234-SKOX", "name": "測(cè)試產(chǎn)品1", "date": "2019-05-20", "price": 10}
{"index": { "_id": 2 }}
{"produceId":"UJSK-1234-BSUA", "name": "測(cè)試產(chǎn)品2", "price": 20, "date": "2020-04-15"}
{"index": { "_id": 3 }}
{"produceId":"HSYA-1234-MLBS", "name": "測(cè)試產(chǎn)品3", "price": 40, "date": "2020-01-20"}
{"index": { "_id": 4 }}
{"produceId":"HSYA-1234-MLBS", "name": "測(cè)試產(chǎn)品4", "price": 40, "date": "2020-01-20", "tag": ["機(jī)械"]}
term
GET /product/_search
{
"query": {
"term": {
"name": {
"value": "測(cè)試產(chǎn)品4"
}
}
}
}
- 查詢(xún)結(jié)果如下:
{
"took" : 0,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 0,
"relation" : "eq"
},
"max_score" : null,
"hits" : [ ]
}
}
- 嗯,啥也沒(méi)有,是不是覺(jué)得很奇怪,不是不對(duì)輸入進(jìn)行分詞嗎?為啥查不到呢?我們前有說(shuō)過(guò)索引,對(duì)text類(lèi)型,es會(huì)進(jìn)行分詞,默認(rèn)使用standard分詞器進(jìn)行分詞,我們來(lái)看一下standard分詞器對(duì)”測(cè)試產(chǎn)品4“的分詞結(jié)果
GET /_analyze
{
"text": "測(cè)試產(chǎn)品4",
"analyzer": "standard"
}
- 分詞結(jié)果
{
"tokens" : [
{
"token" : "測(cè)",
"start_offset" : 0,
"end_offset" : 1,
"type" : "<IDEOGRAPHIC>",
"position" : 0
},
{
"token" : "試",
"start_offset" : 1,
"end_offset" : 2,
"type" : "<IDEOGRAPHIC>",
"position" : 1
},
{
"token" : "產(chǎn)",
"start_offset" : 2,
"end_offset" : 3,
"type" : "<IDEOGRAPHIC>",
"position" : 2
},
{
"token" : "品",
"start_offset" : 3,
"end_offset" : 4,
"type" : "<IDEOGRAPHIC>",
"position" : 3
},
{
"token" : "4",
"start_offset" : 4,
"end_offset" : 5,
"type" : "<NUM>",
"position" : 4
}
]
}
- 可以看到是每個(gè)字是單獨(dú)成詞,term對(duì)輸入不進(jìn)行分詞,索引沒(méi)有匹配上的關(guān)鍵字,自然也就沒(méi)有文檔被檢索出來(lái),那我們?cè)撊绾尾樵?xún)出來(lái)呢?可以使用keyword屬性進(jìn)行查詢(xún),但必須是精確的【啥意思?就是你要搜索”測(cè)試產(chǎn)品4“,必須是”測(cè)試產(chǎn)品4“這5個(gè)字符全部】
GET /product/_search
{
"query": {
"term": {
"name.keyword": {
"value": "測(cè)試產(chǎn)品4"
}
}
}
}
terms
了解了term,我們來(lái)看下terms查詢(xún)。term是單值匹配,terms就是多值。
GET /product/_search
{
"query": {
"terms": {
"name": [
"好優(yōu)肯",
"4"
]
}
}
}
terms set
- 這里直接翻譯官網(wǎng)的話(huà)了,更容易理解
terms_set查詢(xún)與terms查詢(xún)相同,只是您可以定義返回文檔所需的匹配術(shù)語(yǔ)的數(shù)量。例如:
- 字段programming_languages包含一系列已知的編程語(yǔ)言,如c++、java或php,供求職者使用。您可以使用terms_set查詢(xún)來(lái)返回至少匹配這兩種語(yǔ)言的文檔。
- 一個(gè)名為permissions的字段包含應(yīng)用程序的可能用戶(hù)權(quán)限列表。您可以使用terms_set查詢(xún)來(lái)返回匹配這些權(quán)限子集的文檔。
在大多數(shù)情況下,需要在索引中包含一個(gè)數(shù)字字段映射來(lái)使用terms_set查詢(xún)。此數(shù)字字段包含返回文檔所需的匹配項(xiàng)的數(shù)目。
# 創(chuàng)建索引
PUT /job-candidates
{
"mappings": {
"properties": {
"name": {
"type": "keyword"
},
"programming_languages": {
"type": "keyword"
},
"required_matches": {
"type": "long"
}
}
}
}
# 索引兩篇文檔
PUT /job-candidates/_doc/1?refresh
{
"name": "Jane Smith",
"programming_languages": ["c++", "java"],
"required_matches": 2
}
PUT /job-candidates/_doc/2?refresh
{
"name": "Jason Response",
"programming_languages": ["java", "php"],
"required_matches": 2
}
- 可以使用required_matches字段值作為返回terms_set查詢(xún)中的文檔所需的匹配項(xiàng)數(shù)量。
GET /job-candidates/_search
{
"query": {
"terms_set": {
"programming_languages": {
"terms": ["c++", "java", "php"],
"minimum_should_match_field": "required_matches"
}
}
}
}
- 我們也可以使用script腳本來(lái)查詢(xún)
GET /job-candidates/_search
{
"query": {
"terms_set": {
"programming_languages": {
"terms": ["c++", "java", "php"],
"minimum_should_match_script": {
"source": "Math.min(params.num_terms, doc['required_matches'].value)"
}
}
}
}
}
range
# 對(duì)數(shù)字進(jìn)行區(qū)間查詢(xún)
GET /product/_search
{
"query": {
"range": {
"price": {
"gte": 10,
"lte": 20
}
}
}
}
# 對(duì)時(shí)間進(jìn)行區(qū)間查詢(xún)1
GET /product/_search
{
"query": {
"range": {
"date": {
"lte": "2020-04-20",
"gte": "2019-01-01"
}
}
}
}
#對(duì)時(shí)間進(jìn)行區(qū)間查詢(xún)2
# 查找一年以前的數(shù)據(jù)
GET /product/_search
{
"query": {
"range": {
"date": {
"gte": "now-1y"
}
}
}
}
- 時(shí)間表達(dá)式
| 表達(dá)式 | 釋義 |
|---|---|
| y | 年 |
| M | 月 |
| w | 周 |
| d | 天 |
| H/h | 小時(shí) |
| m | 分鐘 |
| s | 秒 |
- 比較表達(dá)式
| 表達(dá)式 | 釋義 |
|---|---|
| gt | 大于 |
| gte | 大于等于 |
| lt | 小于 |
| lte | 小于等于 |
exists
GET /product/_search
{
"query": {
"exists": {
"field": "tag"
}
}
}
prefix
前綴查詢(xún)
GET /product/_search
{
"query": {
"prefix": {
"name": {
"value": "產(chǎn)"
}
}
}
}
- 查詢(xún)結(jié)果
{
"took" : 0,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 4,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "product",
"_type" : "_doc",
"_id" : "1",
"_score" : 1.0,
"_source" : {
"produceId" : "HKXL-1234-SKOX",
"name" : "測(cè)試產(chǎn)品1",
"date" : "2019-05-20",
"price" : 10
}
},
{
"_index" : "product",
"_type" : "_doc",
"_id" : "2",
"_score" : 1.0,
"_source" : {
"produceId" : "UJSK-1234-BSUA",
"name" : "測(cè)試產(chǎn)品2",
"price" : 20,
"date" : "2020-04-15"
}
},
{
"_index" : "product",
"_type" : "_doc",
"_id" : "3",
"_score" : 1.0,
"_source" : {
"produceId" : "HSYA-1234-MLBS",
"name" : "測(cè)試產(chǎn)品3",
"price" : 40,
"date" : "2020-01-20"
}
},
{
"_index" : "product",
"_type" : "_doc",
"_id" : "4",
"_score" : 1.0,
"_source" : {
"produceId" : "HSYA-1234-MLBS",
"name" : "測(cè)試產(chǎn)品4",
"price" : 40,
"date" : "2020-01-20",
"tag" : [
"機(jī)械"
]
}
}
]
}
}
- 等等,不是說(shuō)前綴查詢(xún)嗎,您這也不是前綴查詢(xún)啊,"測(cè)試產(chǎn)品","產(chǎn)"是第三個(gè)詞啊。
- 嗯,對(duì)于es中的查詢(xún),不能忽略的就是他的分詞結(jié)果,我們?cè)谏厦娲_認(rèn)了它的分詞結(jié)果,是每個(gè)字,單獨(dú)成詞,所以對(duì)于每個(gè)字來(lái)說(shuō),他就是自己的前綴,所以,你搜”測(cè)試產(chǎn)品“中的任意字都是前綴,那如何來(lái)解決呢?大家可以修改分詞器,可以參照我借鑒的文章,有關(guān)分詞器的部分,后續(xù)也會(huì)更新一篇文章// TODO
wildcard
通配符查詢(xún)
- “*”,它匹配任何字符序列(包括空字符)
- “?”,它匹配任何單個(gè)字符。
- 為了防止極慢的通配符查詢(xún),通配符項(xiàng)不應(yīng)以通配符 “*” 或 “?” 開(kāi)頭
GET /product/_search
{
"query": {
"wildcard": {
"name.keyword": {
"value": "測(cè)試產(chǎn)品?"
}
}
}
}
regexp
正則查詢(xún)
GET /product/_search
{
"query": {
"wildcard": {
"name.keyword": {
"value": "測(cè)試產(chǎn)品?"
}
}
}
}
我們來(lái)看下它都有哪些操作符【官方直譯】
| 操作符 | 釋義 | 例子 |
|---|---|---|
| .?????????????????? | 匹配任意字符 | - |
| ? | 重復(fù)0次或1次 | abc? matches 'ab' and 'abc' ??????????????????????????????????????????????????????????????????????????? |
| + | 重復(fù)1次或多次 | ab+ matches 'ab', 'abb', 'abbb', ... |
| * | 重復(fù)0次或多次 | ab* matches 'a', 'ab', 'abb', 'abbb', ... |
| {} | 可重復(fù)的最小,最大次數(shù) | a{2} matches 'aa' a{2,4} matches 'aa', 'aaa', and 'aaaa' a{2,} matches 'a` repeated two or more times |
| | | 如果左邊或右邊最長(zhǎng)的模式匹配,則匹配將成功 | abc|xyz matches 'abc' and 'xyz' |
| ( … ) | 形成一個(gè)組??梢允褂媒M將表達(dá)式的一部分視為單個(gè)字符 | abc(def)? matches 'abc' and 'abcdef' but not 'abcd' |
| [ … ] | 1.匹配括號(hào)中的一個(gè)字符 2.在方括號(hào)內(nèi)—表示一個(gè)范圍,除非—是第一個(gè)字符或轉(zhuǎn)義字符 3.方括號(hào)中的字符前的^將使字符或范圍無(wú)效。 |
1.[abc] matches 'a', 'b', 'c' 2.[a-c] matches 'a', 'b', or 'c' [-abc] '-' is first character. Matches '-', 'a', 'b', or 'c' [abc-] Escapes '-'. Matches 'a', 'b', 'c', or '-' 3.[^abc] matches any character except 'a', 'b', or 'c' [^a-c] matches any character except 'a', 'b', or 'c' [^-abc] matches any character except '-', 'a', 'b', or 'c' [^abc-] matches any character except 'a', 'b', 'c', or '-' |
我們可以使用flags參數(shù)為L(zhǎng)ucene的正則表達(dá)式引擎啟用更多的可選操作符。要啟用多個(gè)操作符,使用|分隔符
GET /product/_search
{
"query": {
"regexp":{
"name.keyword": {
"value": "測(cè).+&.+試.*",
"flags" : "INTERSECTION"
}
}
}
}
我們看下flags都有哪些類(lèi)型
| 操作符 | 釋義 | 例子 |
|---|---|---|
| ALL | 啟用所有可選操作 | - |
| COMPLEMENT | 啟用~操作 | a~bc matches 'adc' and 'aec' but not 'abc' |
| INTERVAL | 啟用<>操作,可以用作匹配一個(gè)數(shù)字的區(qū)間 | foo<1-100> matches 'foo1', 'foo2' ... 'foo99', 'foo100' foo<01-100> matches 'foo01', 'foo02' ... 'foo99', 'foo100' |
| INTERSECTION | 啟用&操作,相當(dāng)于AND | aaa.+&.+bbb matches 'aaabbb' |
| ANYSTRING | 啟用@操作 | @&~(abc.+) matches everything except terms beginning with 'abc' |
fuzzy
模糊查詢(xún)
# 添加三篇測(cè)試文檔
PUT /fuzz/_doc/1
{
"name": "sunruikai 123"
}
PUT /fuzz/_doc/2
{
"name": "gabriella 456"
}
PUT /fuzz/_doc/3
{
"name": "test kak"
}
- 執(zhí)行查詢(xún)
GET /fuzz/_search
{
"query": {
"fuzzy": {
"name": {
"value": "sunruilai"
}
}
}
}
當(dāng)然,除了value它還有其他屬性
| 屬性 | 釋義 |
|---|---|
| fuzziness ??????????????????????????????????????????????????????????????????????? | 允許匹配的最大編輯距離 |
| max_expansions | 查詢(xún)中的詞項(xiàng)可以擴(kuò)展的數(shù)目,默認(rèn)為50【避免在max_expansions參數(shù)中使用高值,特別是當(dāng)prefix_length參數(shù)值為0時(shí)。max_expansions參數(shù)中的高值會(huì)導(dǎo)致性能低下,因?yàn)橐獧z查的變量太多?!?/td> |
| prefix_length | 指明區(qū)分詞項(xiàng)的共同前綴長(zhǎng)度,默認(rèn)是0 |
| transpositions | 表示編輯是否包含兩個(gè)相鄰字符的移位(ab→ba),默認(rèn)為true |
| rewrite | 有6中方式,constant_score(默認(rèn)),constant_score_boolean,scoring_boolean,top_terms_blended_freqs_N,top_terms_boost_N,top_terms_N |
ids
見(jiàn)名知意,就是通過(guò)一堆id進(jìn)行查詢(xún)
GET /product/_search
{
"query": {
"ids": {
"values": [1,2,3]
}
}
}
costanct_score
不計(jì)算得分
GET /product/_search
{
"query": {
"constant_score": {
"filter": {
"term": {
"produceId.keyword": "HKXL-1234-SKOX"
}
}
}
}
}