1. ES倒排索引
當(dāng)數(shù)據(jù)寫入ES時,數(shù)據(jù)將會通過“分詞”被切分為不同的term,ES將term與其對應(yīng)的文檔列表建立一種映射關(guān)系,這種結(jié)構(gòu)就是倒排索引。如下圖所示:
為了進(jìn)一步提升索引的效率,ES在term的基礎(chǔ)上利用term的前綴或者后綴構(gòu)建了term index,用于對term本身進(jìn)行索引,ES實(shí)際的索引結(jié)構(gòu)如下圖所示:
這樣當(dāng)我們?nèi)ニ阉髂硞€關(guān)鍵詞時,ES 首先根據(jù)它的前綴或者后綴迅速縮小關(guān)鍵詞的在term dictionary中的范圍,大大減少了磁盤IO的次數(shù)。
- 單詞詞典(Term Dictionary) :記錄所有文檔的單詞,記錄單詞到倒排列表的關(guān)聯(lián)關(guān)系;
- 倒排列表(Posting List)-記錄了單詞對應(yīng)的文檔,由倒排索引項(xiàng)組成;
- 倒排索引項(xiàng)(Posting):
- 文檔ID
- 詞頻TF–該單詞在文檔中出現(xiàn)的次數(shù),用于相關(guān)性評分;
- 位置(Position)-單詞在文檔中分詞的位置。用于短語搜索(match phrase query)
- 偏移(Offset)-記錄單詞的開始結(jié)束位置,實(shí)現(xiàn)高亮顯示。
Elasticsearch的JSON文檔中的每個字段,都有自己的倒排索引。
可以指定對某些字段不做索引:
- 優(yōu)點(diǎn)︰節(jié)省存儲空間
- 缺點(diǎn): 字段無法被搜索
2. 文檔映射Mapping
Mapping類似數(shù)據(jù)庫中的Schema的定義,作用如下:
- 定義索引中的字段的名稱
- 定義字段的數(shù)據(jù)類型,例如字符串,數(shù)字,布爾等;
- 字段,倒排索引的相關(guān)配置(Analyzer)。
ES中Mapping映射可以分為動態(tài)映射和靜態(tài)映射:
- 動態(tài)映射:在關(guān)系數(shù)據(jù)庫中,需要事先創(chuàng)建數(shù)據(jù)庫,然后在該數(shù)據(jù)庫下創(chuàng)建數(shù)據(jù)表,并創(chuàng)建表字段、類型、長度、主鍵等,最后才能基于表插入數(shù)據(jù)。而Elasticsearch中不需要定義Mapping映射(即關(guān)系型數(shù)據(jù)庫的表、字段等),在文檔寫入Elasticsearch時,會根據(jù)文檔字段自動識別類型,這種機(jī)制稱之為動態(tài)映射。
- 靜態(tài)映射:靜態(tài)映射是在Elasticsearch中也可以事先定義好映射,包含文檔的各字段類型、分詞器等,這種方式稱之為靜態(tài)映射。
動態(tài)映射(Dynamic Mapping)的機(jī)制,使得我們無需手動定義Mappings,Elasticsearch會自動根據(jù)文檔信息,推算出字段的類型。但是有時候會推算的不對,例如地理位置信息。當(dāng)類型如果設(shè)置不對時,會導(dǎo)致一些功能無法正常運(yùn)行,例如Range查詢。
- Dynamic Mapping類型自動識別:
??示例
#刪除原索引
DELETE /user
#創(chuàng)建文檔(ES根據(jù)數(shù)據(jù)類型, 會自動創(chuàng)建映射)
PUT /user/_doc/1
{
"name":"magic",
"age":32,
"address":"哈爾濱中央大街"
}
#獲取文檔映射
GET /user/_mapping
思考:能否后期更改Mapping的字段類型?
兩方面考慮:
- 新增加字段
- dynamic設(shè)為true時,一旦有新增字段的文檔寫入,Mapping也同時被更新;
- dynamic設(shè)為false,Mapping不會被更新,新增字段的數(shù)據(jù)無法被索引,但是信息會出現(xiàn)在_source中;
- dynamic設(shè)置成strict(嚴(yán)格控制策略),文檔寫入失敗,拋出異常。
true |
false |
strict |
|
文檔可索引 |
yes |
yes |
no |
字段可索引 |
yes |
no |
no |
Mapping被更新 |
yes |
no |
no |
- 對已有字段,一旦已經(jīng)有數(shù)據(jù)寫入,就不再支持修改字段定義。
- Lucene實(shí)現(xiàn)的倒排索引,一旦生成后,就不允許修改;
- 如果希望改變字段類型,可以利用 reindex API,重建索引。
原因:
- 如果修改了字段的數(shù)據(jù)類型,會導(dǎo)致已被索引的數(shù)據(jù)無法被搜索;
- 但是如果是增加新的字段,就不會有這樣的影響。
??測試
PUT /user
{
"mappings": {
"dynamic": "strict",
"properties": {
"name": {
"type": "text"
},
"address": {
"type": "object",
"dynamic": "true"
}
}
}
}
# 插入文檔報錯,原因?yàn)閍ge為新增字段,會拋出異常
PUT /user/_doc/1
{
"name":"fox",
"age":32,
"address":{
"province":"湖南",
"city":"長沙"
}
}
dynamic設(shè)置成strict,新增age字段導(dǎo)致文檔插入失敗。
修改dynamic后再次插入文檔成功
#修改daynamic
PUT /user/_mapping
{
"dynamic":true
}
對已有字段的mapping修改
- 如果要推倒現(xiàn)有的映射,你得重新建立一個靜態(tài)索引;
- 然后把之前索引里的數(shù)據(jù)導(dǎo)入到新的索引里
- 刪除原創(chuàng)建的索引
- 為新索引起個別名,為原索引名。
2.1 常用Mapping參數(shù)配置
2.1.1 index
index,控制當(dāng)前字段是否被索引,默認(rèn)為true;如果設(shè)置為false,該字段不可被搜索。
DELETE /user
PUT /user
{
"mappings" : {
"properties" : {
"address" : {
"type" : "text",
"index": false
},
"age" : {
"type" : "long"
},
"name" : {
"type" : "text"
}
}
}
}
PUT /user/_doc/1
{
"name":"magic",
"address":"哈爾濱中央大街",
"age":30
}
GET /user
GET /user/_search
{
"query": {
"match": {
"address": "廣州"
}
}
}
2.1.2 index options
index options有四種不同的基本配置,控制倒排索引記錄的內(nèi)容:
- docs : 記錄doc id
- freqs:記錄doc id 和term frequencies(詞頻)
- positions: 記錄doc id / term frequencies / term position
- offsets: doc id / term frequencies / term posistion / character offsets
text類型默認(rèn)記錄postions,其他默認(rèn)為 docs;記錄內(nèi)容越多,占用存儲空間越大。
DELETE /user
PUT /user
{
"mappings" : {
"properties" : {
"address" : {
"type" : "text",
"index_options": "offsets"
},
"age" : {
"type" : "long"
},
"name" : {
"type" : "text"
}
}
}
}
2.1.3 null_value
需要對Null值進(jìn)行搜索,只有keyword類型支持設(shè)計Null_Value。
DELETE /user
PUT /user
{
"mappings" : {
"properties" : {
"address" : {
"type" : "keyword",
"null_value": "NULL"
},
"age" : {
"type" : "long"
},
"name" : {
"type" : "text"
}
}
}
}
PUT /user/_doc/1
{
"name":"fox",
"age":32,
"address":null
}
GET /user/_search
{
"query": {
"match": {
"address": "NULL"
}
}
}
2.1.4 copy_to
????????將字段的數(shù)值拷貝到目標(biāo)字段,滿足一些特定的搜索需求;copy_to的目標(biāo)字段不出現(xiàn)在_source中。
# 設(shè)置copy_to
DELETE /address
PUT /address
{
"mappings" : {
"properties" : {
"province" : {
"type" : "keyword",
"copy_to": "full_address"
},
"city" : {
"type" : "text",
"copy_to": "full_address"
}
}
},
"settings" : {
"index" : {
"analysis.analyzer.default.type": "ik_max_word"
}
}
}
PUT /address/_bulk
{ "index": { "_id": "1"} }
{"province": "湖南","city": "長沙"}
{ "index": { "_id": "2"} }
{"province": "湖南","city": "常德"}
{ "index": { "_id": "3"} }
{"province": "廣東","city": "廣州"}
{ "index": { "_id": "4"} }
{"province": "湖南","city": "邵陽"}
GET /address/_search
{
"query": {
"match": {
"full_address": {
"query": "湖南常德",
"operator": "and"
}
}
}
}
2.2 Index Template
Index Templates可以幫助你設(shè)定Mappings和Settings,并按照一定的規(guī)則,自動匹配到新創(chuàng)建的索引之上。
- 模版僅在一個索引被新創(chuàng)建時,才會產(chǎn)生作用。修改模版不會影響已創(chuàng)建的索引;
- 你可以設(shè)定多個索引模版,這些設(shè)置會被“merge”在一起;
- 你可以指定“order”的數(shù)值,控制“merging”的過程。
2.2.1 模板的創(chuàng)建
PUT /_template/template_default
{
"index_patterns": ["*"],
"order": 0,
"version": 1,
"settings": {
"number_of_shards": 1,
"number_of_replicas": 1
}
}
PUT /_template/template_test
{
"index_patterns": ["test*"], #匹配index的
"order": 1,
"settings": {
"number_of_shards": 2,
"number_of_replicas": 1
},
"mappings": {
"date_detection": false,
"numeric_detection": true
}
}
2.2.2 模板的工作方式
當(dāng)一個索引被新創(chuàng)建時,配置信息的默認(rèn)規(guī)則:
- 應(yīng)用Elasticsearch默認(rèn)的settings和mappings
- 應(yīng)用order數(shù)值低的lndex Template中的設(shè)定
- 應(yīng)用order高的Index Template中的設(shè)定,之前的設(shè)定會被覆蓋;
- 應(yīng)用創(chuàng)建索引時,用戶所指定的Settings和Mappings,并覆蓋之前模版中的設(shè)定。
2.3 Dynamic Template
Dynamic Tempate定義在某個索引的Mapping中。粒度更細(xì),可以根據(jù)字段類型設(shè)置模板。
#Dynaminc Mapping 根據(jù)類型和字段名
DELETE my_index
PUT my_index/_doc/1
{
"firstName":"Ruan",
"isVIP":"true"
}
GET my_index/_mapping
DELETE my_index
PUT my_index
{
"mappings": {
"dynamic_templates": [
{
"strings_as_boolean": {
"match_mapping_type": "string",
"match":"is*",
"mapping": {
"type": "boolean"
}
}
},
{
"strings_as_keywords": {
"match_mapping_type": "string",
"mapping": {
"type": "keyword"
}
}
}
]
}
}
#結(jié)合路徑
PUT /my_test_index
{
"mappings": {
"dynamic_templates": [
{
"full_name":{
"path_match": "name.*",
"path_unmatch": "*.middle",
"mapping":{
"type": "text",
"copy_to": "full_name"
}
}
}
]
}
}
PUT /my_test_index/_doc/1
{
"name":{
"first": "John",
"middle": "Winston",
"last": "Lennon"
}
}
GET /my_test_index/_search
{
"query": {
"match": {
"full_name": "John"
}
}
}
3. ES高級查詢Query DSL
????????ES中提供了一種強(qiáng)大的檢索數(shù)據(jù)方式,這種檢索方式稱之為Query DSL(Domain Specified Language),Query DSL是利用Rest API傳遞JSON格式的請求體(RequestBody)數(shù)據(jù)與ES進(jìn)行交互,這種方式的豐富查詢語法讓ES檢索變得更強(qiáng)大,更簡潔。
Query DSL | Elasticsearch Guide [7.17] | Elastic
??語法
GET /es_db/_doc/_search {json請求體數(shù)據(jù)}
#可以簡化為下面寫法
GET /es_db/_search {json請求體數(shù)據(jù)}
??示例
#無條件查詢,默認(rèn)返回10條數(shù)據(jù)
GET /es_db/_search
{
"query":{
"match_all":{}
}
}
3.1 查詢所有match_all
????????使用match_all,默認(rèn)只會返回10條數(shù)據(jù)(_search查詢默認(rèn)采用的是分頁查詢,每頁記錄數(shù)size的默認(rèn)值為10);如果想顯示更多數(shù)據(jù),指定size。
GET /es_db/_search
等同于
GET /es_db/_search
{
"query":{
"match_all":{}
}
}
#在查詢中過濾
#不查看源數(shù)據(jù),僅查看元字段
{
"_source": false,
"query": {
...
}
}
#只看以obj.開頭的字段
{
"_source": "obj.*",
"query": {
...
}
}
3.1.1 返回指定條數(shù)size
????????使用size,指定查詢結(jié)果中返回指定條數(shù)(默認(rèn)返回值10條)。
GET /es_db/_search
{
"query": {
"match_all": {}
},
"size": 100
}
思考: size可以無限增加嗎?
- 測試
GET /es_db/_search
{
"query": {
"match_all": {}
},
"size": 20000
}
- 出現(xiàn)異常
異常原因:
- 查詢結(jié)果的窗口太大,from + size的結(jié)果必須小于或等于10000,而當(dāng)前查詢結(jié)果的窗口為20000。
- 可以采用scroll?api更高效的請求大量數(shù)據(jù)集。
- 查詢結(jié)果的窗口的限制可以通過參數(shù)index.max_result_window進(jìn)行設(shè)置。
PUT /es_db/_settings
{
"index.max_result_window" :"20000"
}
#修改現(xiàn)有所有的索引,但新增的索引,還是默認(rèn)的10000。
PUT /_all/_settings
{
"index.max_result_window" :"20000"
}
#查看所有索引中的index.max_result_window值
GET /_all/_settings/index.max_result_window
注意
????????參數(shù)index.max_result_window主要用來限制單次查詢滿足查詢條件的結(jié)果窗口的大小,窗口大小由from + size共同決定。不能簡單理解成查詢返回給調(diào)用方的數(shù)據(jù)量。這樣做主要是為了限制內(nèi)存的消耗。
????????比如:from為1000000,size為10,邏輯意義是從滿足條件的數(shù)據(jù)中取1000000到(1000000 + 10)的記錄。這時ES一定要先將(1000000 + 10)的記錄(即result_window)加載到內(nèi)存中,再進(jìn)行分頁取值的操作。盡管最后我們只取了10條數(shù)據(jù)返回給客戶端,但ES進(jìn)程執(zhí)行查詢操作的過程中確需要將(1000000 + 10)的記錄都加載到內(nèi)存中,可想而知對內(nèi)存的消耗有多大。這也是ES中不推薦采用(from + size)方式進(jìn)行深度分頁的原因。
????????同理,from為0,size為1000000時,ES進(jìn)程執(zhí)行查詢操作的過程中確需要將1000000 條記錄都加載到內(nèi)存中再返回給調(diào)用方,也會對ES內(nèi)存造成很大壓力。
3.1.2 分頁查詢form
????????from 關(guān)鍵字,用來指定起始返回位置,和size關(guān)鍵字連用可實(shí)現(xiàn)分頁效果。
ET /es_db/_search
{
"query": {
"match_all": {}
},
"size": 5,
"from": 0
}
3.1.3 指定字段排序sort
????????注意:會讓得分失效
GET /es_db/_search
{
"query": {
"match_all": {}
},
"sort": [
{
"age": "desc"
}
]
}
#排序,分頁
GET /es_db/_search
{
"query": {
"match_all": {}
},
"sort": [
{
"age": "desc"
}
],
"from": 10,
"size": 5
}
3.1.4?返回指定字段_source
????????_source 關(guān)鍵字,是一個數(shù)組,在這個數(shù)組中指定展示哪些字段。
GET /es_db/_search
{
"query": {
"match_all": {}
},
"_source": ["name","address"]
}
3.2 全文檢索
????????全文檢索查詢(Full Text Queries)和術(shù)語級別查詢(Term-Level Queries)是 Elasticsearch 中搜索和檢索數(shù)據(jù)的兩種不同方法。全文檢索查詢指在基于相關(guān)性搜索和匹配文本數(shù)據(jù)。這些查詢會對輸入的文本進(jìn)行分析,將其拆分為詞項(xiàng)(單個單詞),并執(zhí)行諸如分詞、詞干處理和標(biāo)準(zhǔn)化等操作。Elasticsearch 中的一些全文檢索查詢示例包括 match、match_phrase 和 multi_match 查詢。全文檢索的關(guān)鍵特點(diǎn):
- 對輸入的文本進(jìn)行分析,并根據(jù)分析后的詞項(xiàng)進(jìn)行搜索和匹配。全文檢索查詢會對輸入的文本進(jìn)行分析,將其拆分為詞項(xiàng),并基于這些詞項(xiàng)進(jìn)行搜索和匹配操作。
- 以相關(guān)性為基礎(chǔ)進(jìn)行搜索和匹配。全文檢索查詢使用相關(guān)性算法來確定文檔與查詢的匹配程度,并按照相關(guān)性進(jìn)行排序。相關(guān)性可以基于詞項(xiàng)的頻率、權(quán)重和其他因素來計算。
- 全文檢索查詢適用于包含自由文本數(shù)據(jù)的字段,例如文檔的內(nèi)容、文章的正文或產(chǎn)品描述等。
3.2.1 match query
????????match在匹配時會對所查找的關(guān)鍵詞進(jìn)行分詞,然后按分詞匹配查找,match支持以下參數(shù):
- query : 指定匹配的值
- operator : 匹配條件類型
- and:條件分詞后都要匹配
- or:條件分詞后有一個匹配即可(默認(rèn))
- operator : 匹配條件類型
- minmum_should_match:最低匹配度,即條件在倒排索引中最低的匹配度。
# 模糊匹配 分詞后"or"的效果
GET /es_db/_search
{
"query": {
"match": {
"address": "廣州白云山公園"
}
}
}
# 分詞后"and"的效果
GET /es_db/_search
{
"query": {
"match": {
"address":{
"query": "廣州白云山公園",
"operator": "and"
}
}
}
}
????????在match中的應(yīng)用: 當(dāng)operator參數(shù)設(shè)置為or時,minnum_should_match參數(shù)用來控制匹配的分詞的最少數(shù)量。
# 最少匹配廣州,公園兩個詞
GET /es_db/_search
{
"query": {
"match": {
"address": {
"query": "廣州公園",
"minimum_should_match": 2
}
}
}
}
3.2.2 match_phrase
????????短語查詢,match_phrase查詢分析文本并根據(jù)分析的文本創(chuàng)建一個短語查詢。match_phrase會將檢索關(guān)鍵詞分詞。match_phrase的分詞結(jié)果必須在被檢索字段的分詞中都包含,而且順序必須相同,而且默認(rèn)必須都是連續(xù)的。
GET /es_db/_search
{
"query": {
"match_phrase": {
"address": "廣州白云山"
}
}
}
GET /es_db/_search
{
"query": {
"match_phrase": {
"address": "廣州白云"
}
}
}
- 思考:為什么查詢廣州白云山有數(shù)據(jù),廣州白云沒有數(shù)據(jù)?
- 分析原因:
????????先查看廣州白云山公園分詞結(jié)果,可以知道廣州和白云不是相鄰的詞條,中間會隔一個白云山,而match_phrase匹配的是相鄰的詞條,所以查詢廣州白云山有結(jié)果,但查詢廣州白云沒有結(jié)果。
POST _analyze
{
"analyzer":"ik_max_word",
"text":"廣州白云山"
}
#結(jié)果
{
"tokens" : [
{
"token" : "廣州",
"start_offset" : 0,
"end_offset" : 2,
"type" : "CN_WORD",
"position" : 0
},
{
"token" : "白云山",
"start_offset" : 2,
"end_offset" : 5,
"type" : "CN_WORD",
"position" : 1
},
{
"token" : "白云",
"start_offset" : 2,
"end_offset" : 4,
"type" : "CN_WORD",
"position" : 2
},
{
"token" : "云山",
"start_offset" : 3,
"end_offset" : 5,
"type" : "CN_WORD",
"position" : 3
}
]
}
????????如何解決詞條間隔的問題?可以借助slop參數(shù),slop參數(shù)告訴match_phrase查詢詞條能夠相隔多遠(yuǎn)時仍然將文檔視為匹配。
#廣州云山分詞后相隔為2,可以匹配到結(jié)果
GET /es_db/_search
{
"query": {
"match_phrase": {
"address": {
"query": "廣州云山",
"slop": 2
}
}
}
}
3.2.3 multi_match
????????多字段查詢,可以根據(jù)字段類型,決定是否使用分詞查詢,得分最高的在前面。
GET /es_db/_search
{
"query": {
"multi_match": { #地址和名稱中如果匹配到都能查詢到
"query": "長沙張龍",
"fields": [
"address",
"name"
]
}
}
}
????????注意:字段類型分詞,將查詢條件分詞之后進(jìn)行查詢,如果該字段不分詞就會將查詢條件作為整體進(jìn)行查詢。
3.2.4 query_string
????????允許我們在單個查詢字符串中指定AND | OR | NOT條件,同時也和 multi_match query 一樣,支持多字段搜索。和match類似,但是match需要指定字段名,query_string是在所有字段中搜索,范圍更廣泛。
????????注意:查詢字段分詞就將查詢條件分詞查詢,查詢字段不分詞將查詢條件不分詞查詢。
3.2.4.1 未指定字段查詢
GET /es_db/_search
{
"query": {
"query_string": {
"query": "張三 OR 橘子洲"
}
}
}
3.2.4.2 指定單個字段查詢
#Query String
GET /es_db/_search
{
"query": {
"query_string": {
"default_field": "address",
"query": "白云山 OR 橘子洲"
}
}
}
3.2.4.3 指定多個字段查詢
GET /es_db/_search
{
"query": {
"query_string": {
"fields": ["name","address"],
"query": "張三 OR (廣州 AND 王五)"
}
}
}
3.2.5 simple_query_string
????????類似query_string,但是會忽略錯誤的語法,同時只支持部分查詢語法,不支持AND OR NOT,會當(dāng)作字符串處理。支持部分邏輯:
- + 替代AND
- | 替代OR
- - 替代NOT
#simple_query_string 默認(rèn)的operator是OR
GET /es_db/_search
{
"query": {
"simple_query_string": {
"fields": ["name","address"],
"query": "廣州公園",
"default_operator": "AND"
}
}
}
GET /es_db/_search
{
"query": {
"simple_query_string": {
"fields": ["name","address"],
"query": "廣州 + 公園"
}
}
}
3.3 術(shù)語級別查詢
????????術(shù)語級別查詢(Term-Level Queries)指的是搜索內(nèi)容不經(jīng)過文本分析直接用于文本匹配,這個過程類似于數(shù)據(jù)庫的SQL查詢,搜索的對象大多是索引的非text類型字段。Elasticsearch 中的一些術(shù)語級別查詢示例包括 term、terms 和 range 查詢。
3.3.1 關(guān)鍵詞查詢Term
????????Term用來使用關(guān)鍵詞查詢(精確匹配),還可以用來查詢沒有被進(jìn)行分詞的數(shù)據(jù)類型。Term是表達(dá)語意的最小單位,搜索和利用統(tǒng)計語言模型進(jìn)行自然語言處理都需要處理Term。match在匹配時會對所查找的關(guān)鍵詞進(jìn)行分詞,然后按分詞匹配查找,而term會直接對關(guān)鍵詞進(jìn)行查找。一般模糊查找的時候,多用match,而精確查找時可以使用term。
- ES中默認(rèn)使用分詞器為標(biāo)準(zhǔn)分詞器(StandardAnalyzer),標(biāo)準(zhǔn)分詞器對于英文單詞分詞,對于中文單字分詞。
- 在ES的Mapping Type 中 keyword、date、integer、long、double、boolean這些類型不分詞,只有text類型分詞。
????????注意:最好不要在term查詢的字段中使用text字段,因?yàn)閠ext字段會被分詞,這樣做既沒有意義,還很有可能什么也查不到。
# 對bool,日期,數(shù)字,結(jié)構(gòu)化的文本可以利用term做精確匹配
# term 精確匹配
GET /es_db/_search
{
"query": {
"term": {
"age": {
"value": 28
}
}
}
}
# 思考: 查詢廣州白云是否有數(shù)據(jù),為什么?
GET /es_db/_search
{
"query":{
"term": {
"address": {
"value": "廣州白云"
}
}
}
}
# 采用term精確查詢, 查詢字段映射類型為keyword
GET /es_db/_search
{
"query":{
"term": {
"address.keyword": {
"value": "廣州白云山公園"
}
}
}
}
????????在ES中,Term查詢時對輸入不做分詞。會將輸入作為一個整體,在倒排索引中查找準(zhǔn)確的詞項(xiàng),并且使用相關(guān)度算分公式為每個包含該詞項(xiàng)的文檔進(jìn)行相關(guān)度算分。
PUT /product/_bulk
{"index":{"_id":1}}
{"productId":"xxx123","productName":"iPhone"}
{"index":{"_id":2}}
{"productId":"xxx111","productName":"iPad"}
# 思考: 查詢iPhone可以查到數(shù)據(jù)嗎? 答:查不到,因?yàn)?iPhone"會被小寫保存。
GET /product/_search
{
"query":{
"term": {
"productName": {
"value": "iPhone"
}
}
}
}
GET /product/_analyze
{
"analyzer":"standard",
"text":"iPhone"
}
# 對于英文,可以考慮建立索引時忽略大小寫
PUT /product
{
"settings": {
"analysis": {
"normalizer": {
"es_normalizer": {
"filter": [
"lowercase",
"asciifolding"
],
"type": "custom"
}
}
}
},
"mappings": {
"properties": {
"productId": {
"type": "text"
},
"productName": {
"type": "keyword",
"normalizer": "es_normalizer",
"index": "true"
}
}
}
}
????????使用Term查詢時,可以通過Constant Score將查詢轉(zhuǎn)換成一個Filtering,避免算分,并利用緩存,提高性能。
- 將Query轉(zhuǎn)成Filter,忽略TF-IDF計算,避免相關(guān)性算分的開銷;
- Filter可以有效利用緩存
GET /es_db/_search
{
"query": {
"constant_score": {
"filter": {
"term": {
"address.keyword": "廣州白云山公園"
}
}
}
}
}
????????term處理多值字段時,term查詢是包含,不是等于。
POST /employee/_bulk
{"index":{"_id":1}}
{"name":"小明","interest":["跑步","籃球"]}
{"index":{"_id":2}}
{"name":"小紅","interest":["跳舞","畫畫"]}
{"index":{"_id":3}}
{"name":"小麗","interest":["跳舞","唱歌","跑步"]}
POST /employee/_search
{
"query": {
"term": {
"interest.keyword": {
"value": "跑步"
}
}
}
}
3.3.2 多術(shù)語查詢Terms
????????Terms用于在指定字段上匹配多個詞項(xiàng)(terms)。它會精確匹配指定字段中包含的任何一個詞項(xiàng)。
POST /es_db/_search
{
"query": {
"terms": {
"remark.keyword": ["java assistant", "java architect"]
}
}
}
3.3.3 exists query
????????在Elasticsearch中可以使用exists進(jìn)行查詢,以判斷文檔中是否存在對應(yīng)的字段。
#查詢索引庫中存在remarks字段的文檔數(shù)據(jù)
GET /es_db/_search
{
"query": {
"exists":
{
"field": "remark"
}
}
}
3.3.4 多id查詢ids
????????ids 關(guān)鍵字?: 值為數(shù)組類型,用來根據(jù)一組id獲取多個對應(yīng)的文檔。
GET /es_db/_search
{
"query": {
"ids": {
"values": [1,2]
}
}
}
3.3.5 范圍查詢range
- range:范圍關(guān)鍵字
- gte 大于等于
- lte ?小于等于
- gt 大于
- lt 小于
- now 當(dāng)前時間
POST /es_db/_search
{
"query": {
"range": {
"age": {
"gte": 25,
"lte": 28
}
}
}
}
3.3.6 日期range
DELETE /product
POST /product/_bulk
{"index":{"_id":1}}
{"price":100,"date":"2021-01-01","productId":"BJ-1293"}
{"index":{"_id":2}}
{"price":200,"date":"2022-01-01","productId":"HRB-5421"}
GET /product/_mapping
GET /product/_search
{
"query": {
"range": {
"date": {
"gte": "now-2y"
}
}
}
}
3.3.7 前綴查詢prefix
????????它會對分詞后的term進(jìn)行前綴搜索。
- 它不會分析要搜索字符串,傳入的前綴就是想要查找的前綴;
- 默認(rèn)狀態(tài)下,前綴查詢不做相關(guān)度分?jǐn)?shù)計算,它只是將所有匹配的文檔返回,然后賦予所有相關(guān)分?jǐn)?shù)值為1。它的行為更像是一個過濾器而不是查詢。兩者實(shí)際的區(qū)別就是過濾器是可以被緩存的,而前綴查詢不行。
prefix的原理:需要遍歷所有倒排索引,并比較每個term是否已所指定的前綴開頭。
GET /es_db/_search
{
"query": {
"prefix": {
"address": {
"value": "廣州"
}
}
}
}
3.3.8 通配符查詢wildcard
????????通配符查詢:工作原理和prefix相同,只不過它不是只比較開頭,它能支持更為復(fù)雜的匹配模式。
GET /es_db/_search
{
"query": {
"wildcard": {
"address": {
"value": "*白*"
}
}
}
}
3.3.9 模糊查詢fuzzy
????????在實(shí)際的搜索中,我們有時候會打錯字,從而導(dǎo)致搜索不到。在Elasticsearch中,我們可以使用fuzziness屬性來進(jìn)行模糊查詢,從而達(dá)到搜索有錯別字的情形。fuzzy查詢會用到兩個很重要的參數(shù):fuzziness、prefix_length
- fuzziness:表示輸入的關(guān)鍵字通過幾次操作可以轉(zhuǎn)變成為ES庫里面的對應(yīng)field的字段
- 操作是指:新增一個字符,刪除一個字符,修改一個字符,每次操作可以記做編輯距離為1;
- 如中文集團(tuán)到中威集團(tuán)編輯距離就是1,只需要修改一個字符;
- 該參數(shù)默認(rèn)值為0,即不開啟模糊查詢;
- 如果fuzziness值在這里設(shè)置成2,會把編輯距離為2的東東集團(tuán)也查出來。
- prefix_length:表示限制輸入關(guān)鍵字和ES對應(yīng)查詢field的內(nèi)容開頭的第n個字符必須完全匹配,不允許錯別字匹配;
- 如這里等于1,則表示開頭的字必須匹配,不匹配則不返回
- 默認(rèn)值也是0
- 加大prefix_length的值可以提高效率和準(zhǔn)確率。
GET /es_db/_search
{
"query": {
"fuzzy": {
"address": {
"value": "白運(yùn)山",
"fuzziness": 1
}
}
}
}
GET /es_db/_search
{
"query": {
"match": {
"address": {
"query": "廣洲",
"fuzziness": 1
}
}
}
}
注意:fuzzy模糊查詢最大模糊錯誤必須在0-2之間
- 搜索關(guān)鍵詞長度為 2,不允許存在模糊;
- 搜索關(guān)鍵詞長度為3-5,允許1次模糊;
- 搜索關(guān)鍵詞長度大于5,允許最大2次模糊。
3.4 高亮highlight
????????highlight 關(guān)鍵字,可以讓符合條件的文檔中的關(guān)鍵詞高亮。highlight相關(guān)屬性:
- pre_tags 前綴標(biāo)簽
- post_tags 后綴標(biāo)簽
- tags_schema 設(shè)置為styled可以使用內(nèi)置高亮樣式
- require_field_match 多字段高亮需要設(shè)置為false
3.4.1 自定義高亮html標(biāo)簽
????????可以在highlight中使用pre_tags和post_tags
GET /products/_search
{
"query": {
"term": {
"name": {
"value": "牛仔"
}
}
},
"highlight": {
"post_tags": ["</span>"],
"pre_tags": ["<span style='color:red'>"],
"fields": {
"*":{}
}
}
}
3.4.2 多字段高亮
GET /products/_search
{
"query": {
"term": {
"name": {
"value": "牛仔"
}
}
},
"highlight": {
"pre_tags": ["<font color='red'>"],
"post_tags": ["<font/>"],
"require_field_match": "false",
"fields": {
"name": {},
"desc": {}
}
}
}
3.5 bool query布爾查詢
????????布爾查詢可以按照布爾邏輯條件組織多條查詢語句,只有符合整個布爾條件的文檔才會被搜索出來。在布爾條件中,可以包含兩種不同的上下文。
- 搜索上下文(query context):使用搜索上下文時,Elasticsearch需要計算每個文檔與搜索條件的相關(guān)度得分,這個得分的計算需使用一套復(fù)雜的計算公式,有一定的性能開銷,帶文本分析的全文檢索的查詢語句很適合放在搜索上下文中。
- 過濾上下文(filter context):使用過濾上下文時,Elasticsearch只需要判斷搜索條件跟文檔數(shù)據(jù)是否匹配,例如使用Term query判斷一個值是否跟搜索內(nèi)容一致,使用Range query判斷某數(shù)據(jù)是否位于某個區(qū)間等。過濾上下文的查詢不需要進(jìn)行相關(guān)度得分計算,還可以使用緩存加快響應(yīng)速度,很多術(shù)語級查詢語句都適合放在過濾上下文中。
布爾查詢一共支持4種組合類型:
類型 |
說明 |
must |
可包含多個查詢條件,每個條件均滿足的文檔才能被搜索到,每次查詢需要計算相關(guān)度得分,屬于搜索上下文。 |
should |
可包含多個查詢條件,不存在must和fiter條件時,至少要滿足多個查詢條件中的一個,文檔才能被搜索到,否則需滿足的條件數(shù)量不受限制,匹配到的查詢越多相關(guān)度越高,也屬于搜索上下文。 |
filter |
可包含多個過濾條件,每個條件均滿足的文檔才能被搜索到,每個過濾條件不計算相關(guān)度得分,結(jié)果在一定條件下會被緩存, 屬于過濾上下文。 |
must_not文章來源:http://www.zghlxwxcb.cn/news/detail-808361.html |
可包含多個過濾條件,每個條件均不滿足的文檔才能被搜索到,每個過濾條件不計算相關(guān)度得分,結(jié)果在一定條件下會被緩存, 屬于過濾上下文。文章來源地址http://www.zghlxwxcb.cn/news/detail-808361.html |
- 示例
PUT /books
{
"settings": {
"number_of_replicas": 1,
"number_of_shards": 1
},
"mappings": {
"properties": {
"id": {
"type": "long"
},
"title": {
"type": "text",
"analyzer": "ik_max_word"
},
"language": {
"type": "keyword"
},
"author": {
"type": "keyword"
},
"price": {
"type": "double"
},
"publish_time": {
"type": "date",
"format": "yyy-MM-dd"
},
"description": {
"type": "text",
"analyzer": "ik_max_word"
}
}
}
}
POST /_bulk
{"index":{"_index":"books","_id":"1"}}
{"id":"1", "title":"Java編程思想", "language":"java", "author":"Bruce Eckel", "price":70.20, "publish_time":"2007-10-01", "description":"Java學(xué)習(xí)必讀經(jīng)典,殿堂級著作!贏得了全球程序員的廣泛贊譽(yù)。"}
{"index":{"_index":"books","_id":"2"}}
{"id":"2","title":"Java程序性能優(yōu)化","language":"java","author":"葛一鳴","price":46.5,"publish_time":"2012-08-01","description":"讓你的Java程序更快、更穩(wěn)定。深入剖析軟件設(shè)計層面、代碼層面、JVM虛擬機(jī)層面的優(yōu)化方法"}
{"index":{"_index":"books","_id":"3"}}
{"id":"3","title":"Python科學(xué)計算","language":"python","author":"張若愚","price":81.4,"publish_time":"2016-05-01","description":"零基礎(chǔ)學(xué)python,光盤中作者獨(dú)家整合開發(fā)winPython運(yùn)行環(huán)境,涵蓋了Python各個擴(kuò)展庫"}
{"index":{"_index":"books","_id":"4"}}
{"id":"4", "title":"Python基礎(chǔ)教程", "language":"python", "author":"Helant", "price":54.50, "publish_time":"2014-03-01", "description":"經(jīng)典的Python入門教程,層次鮮明,結(jié)構(gòu)嚴(yán)謹(jǐn),內(nèi)容翔實(shí)"}
{"index":{"_index":"books","_id":"5"}}
{"id":"5","title":"JavaScript高級程序設(shè)計","language":"javascript","author":"Nicholas C. Zakas","price":66.4,"publish_time":"2012-10-01","description":"JavaScript技術(shù)經(jīng)典名著"}
GET /books/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"title": "java編程"
}
},{
"match": {
"description": "性能優(yōu)化"
}
}
]
}
}
}
GET /books/_search
{
"query": {
"bool": {
"should": [
{
"match": {
"title": "java編程"
}
},{
"match": {
"description": "性能優(yōu)化"
}
}
],
"minimum_should_match": 1
}
}
}
GET /books/_search
{
"query": {
"bool": {
"filter": [
{
"term": {
"language": "java"
}
},
{
"range": {
"publish_time": {
"gte": "2010-08-01"
}
}
}
]
}
}
}
到了這里,關(guān)于ElasticSearch高級查詢語法的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!