Elasticsearch URI search 查詢語法整理


Elasticsearch URI search

一、請求體查詢與空查詢

1. 請求體查詢(request body search)

簡單查詢語句(lite)是一種有效的命令行adhoc查詢。但是,如果你想要善用搜索,你必須使用請求體查詢(request body search) API。之所以這么稱呼,是因為大多數的參數以JSON格式所容納而非查詢字符串。

請求體查詢(以下簡稱查詢),並不僅僅用於處理查詢,而且還可以高亮返回結果中的片段,並且給出幫助你的用戶找尋最好結果的相關數據建議。

2. 空查詢

我們以最簡單的search API開始,空查詢將會返回索引中所有的文檔。

GET /_search
{}

同字符串查詢一樣,你可以查詢一個,多個或_all索引(indices)或類型(types):

GET /index_2014*/type1,typ2/_search
{}

你可以使用from及size參數進行分頁:

GET /_search
{
   "from" : 30,
   "size" : 10
}

攜帶內容的GET請求?

任何一種語言(特別是js)的HTTP庫都不允許GET請求中攜帶交互數據。事實上,有些用戶很驚訝GET請求中居然會允許攜帶交互數據。
真實情況是,http://tools.ietf.org/html/rfc7231#page-24[RFC 7231], 一份規定HTTP語義及內容的RFC中並未規定 GET 請求中允許攜帶交互數據! 所以,有些HTTP服務允許這種行為,而另一些(特別是緩存代理),則不允許這種行為。

Elasticsearch的作者們傾向於使用GET提交查詢請求,因為他們覺得這個詞相比POST來說,能更好的描述這種行為。然而,因為攜帶交互數據的GET請求並不被廣泛支持,所以search API同樣支持POST請求,類似於這樣:

POST /_search
{
  "from" : 30,
  "size" : 10
}

這個原理同樣應用於其他攜帶交互數據的GET API請求中。

相對於神秘的查詢字符串方法,請求體查詢允許我們使用結構化查詢Query DSL(Query Domain Specific Language)

二、結構化查詢

bool聯合查詢: must, should, must_not

must: 文檔必須完全匹配條件,選擇多個即 且 的意思;
should: should下面會帶一個以上的條件,至少滿足一個條件,這個文檔就符合should,選擇多個即 且 的意思;
must_not: 文檔必須不匹配條件,選擇多個即 且 的意思;

如果我們想要請求"content中帶寶馬,但是tag中不帶寶馬"這樣類似的需求,就需要用到bool聯合查詢。

樣例

全文檢索,模糊匹配,message.keyword 包含“Error”,項目名稱不以“boe”開頭的數據。
此處我們需要使用 bool 查詢:

GET awsbpm_prod_log-2019.08.20/_search
{
    "query":{
        "bool":{
            "must": [
                {
                    "match_all":{

                    }
                },
                {
                    "wildcard":{
                        "message.keyword":"*Error*"
                    }
                }
            ],
            "must_not":[

            ],
            "should":[

            ]
        }
    },
    "from":11,
    "size":20,
    "sort":[

    ],
    "aggs":{

    }
}

高級檢索語法:term, wildcard, prefix, fuzzy, range, query_string, text, missing

term:嚴格匹配條件,所查詢的字段內容要與填入查詢框搜索值一致;
wildcard:通配符查詢,* 表示全匹配,? 表示單一匹配,etc: aaa* 或者 a?b;
prefix:前綴匹配,搜索框如果輸入aa,那么可能匹配到的字段值為 aab,aavb等;
fuzzy min_similarity:彈性模糊匹配,有兩個搜索框,第一個搜索框為搜索匹配值,會自動糾錯,比如輸入 ggjk,那么可能會匹配到ggjo,第二個框為最小相似度,采用的算法是Damerau-Levenshtein(最佳字符串對齊)算法,不建議填寫這個框,我到發稿前也是被搞的頭皮發麻,等我完全吃透再更新;
fuzzy max_expansions :彈性模糊匹配,有兩個搜索框,第一個搜索框為搜索匹配值,會自動糾錯,比如輸入 ggjk,那么可能會匹配到ggjo,第二個框是最大擴展匹配數,比如是1,那么ggjk只會隨機模糊匹配到一種可能結果,即使它會出現2種或者更加多,也只會搜索一種;
range:范圍查詢,gt為大於,gte為大於等於,lt小於,lte小於等於,所搜索的字段值在兩個搜索框標識數值之間;
query_string:字符片段查詢,如果是數字,則嚴格匹配數字,如果是字符串,則按照自身或者分片詞匹配;
text:分片詞查詢,等確定后更新;
missing:查詢沒有定義該字段或者該字段值為null的數據。

1. term query - 索引詞檢索

(1) term query - 不分詞檢索

term query: 把檢索串當作一個整體來執行檢索, 即不會對檢索串分詞.

term是完全匹配檢索, 要用在不分詞的字段上, 如果某個field在映射中被分詞了, term檢索將不起作用.
所以, 不分詞的field, 要在mapping中設置為不分詞.

—— ES 5.x之后, 為每個text類型的字段新增了名為keyword的子字段, 是不分詞的, 默認保留256個字符.

—— 可以使用keyword字段進行term檢索. 
示例:
GET shop/_search
{
	"query": {
		"term": {
		"name.keyword": "Java編程思想"
		}
	}
}

(2) terms query - in檢索

terms, 相當於多個term檢索, 類似於SQL中in關鍵字的用法, 即在某些給定的數據中檢索:

GET shop/_search
{
	"query": {
		"terms": {
			"name.keyword": [
				"Java編程思想", "Java並發編程的藝術"
				]
		}
	}
}

2. prefix query - 前綴檢索

prefix query, 就是前綴檢索. 比如商品name中有多個以"Java"開頭的document, 檢索前綴"Java"時就能檢索到所有以"Java"開頭的文檔.

—— 掃描所有倒排索引, 性能較差.

GET shop/_search
{
	"query": {
		"prefix": { "name": "java" }
	}
}

3. wildcard query - 通配符檢索

掃描所有倒排索引, 性能較差.

GET shop/_search
{
    "query": {
        "wildcard": { "name": "ja*" }
    }
}

4. regexp query - 正則檢索

掃描所有倒排索引, 性能較差.

GET shop/_search
{
    "query": {
        "regexp": { "name": "jav[a-z]*" }
    }
}

5. fuzzy query - 糾錯檢索

fuzziness的默認值是2 —— 表示最多可以糾錯兩次.

說明: fuzziness的值太大, 將削弱檢索條件的作用, 也就是說糾錯次數太多, 就會導致限定檢索結果的檢索條件被改變, 失去了限定作用.

示例: 檢索name中包含"Java"的文檔, Java中缺失了一個字母a:

GET shop/_search
{
    "query": {
        "match": { 
            "name": {
                "query": "Jav", 
                "fuzziness": 1, 
                "operator": "and"
            }
        }
    }
}

6. boost評分權重 - 控制文檔的優先級別

通過boost參數, 令滿足某個條件的文檔的得分更高, 從而使得其排名更靠前.

GET shop/_search
{
    "query": {
        "bool": {
            "must": [
                { "match": { "name": "編程思想"} }
            ], 
            "should": [
                { 
                   "match": { 
                        "name": {
                            "query": "藝術", 
                            "boost": 2        // 提升評分權重
                        } 
                    }
                }
            ]
        }
    }
}

7. dis_max的用法 - best fields策略

(1) dis_max的提出
如果我們希望檢索結果中 (檢索串被分詞后的) 關鍵字匹配越多, 這樣的文檔就越靠前, 而不是多個子檢索中匹配少量分詞的文檔靠前.

⇒ 此時可以使用dis_max和tie_breaker.

tie_breaker的值介於0~1之間, Elasticsearch將 bool檢索的分數 * tie_breaker的結果與dis_max的最高分進行比較, 除了取dis_max的最高分以外, 還會考慮其他的檢索結果的分數.

(2) 使用示例
為了增加精准度, 常用的是配合boost、minimum_should_match等參數控制檢索結果.

GET shop/_search
{
    "query": {
        "dis_max": {
            "queries": [
                { "match": { "name": "虛擬機" } },
                { "match": { "desc": "經典" } }
            ],
            "tie_breaker": 0.2      // 對同時滿足的文檔的分值進行提升
        }
    }
}
GET shop/_search
{
    "query": {
        "dis_max": {
            "queries": [
                { 
                    "match": { 
                        "name": {
                            "query": "虛擬機",
                            "minimum_should_match": "50%",
                            "boost": 2
                        }
                    }
                },
                {
                    "match": {
                        "desc": {
                            "query": "經典",
                            "minimum_should_match": "50%", 
                            "boost": 3
                        }
                    }
                }
            ],
            "tie_breaker": 0.3
        }
    }
}

三、復雜檢索的使用范例

1. 多條件過濾 - 包含

檢索出版時間在2012-07之后, 且至少滿足下述條件中一個的文檔:

a. 名稱(name)中包含"並發";

b. 描述(desc)中包含"java";

c. 出版社(publisher)名稱中不包含"電子".

GET shop/_search
{
    "query": {
        "bool": {
            "filter": {                 // 按時間過濾
                "range": {
                    "date": {"gte": "2012-07"}
                }
            },
            "should": [                 // 可匹配, 可不匹配
                {
                    "match": { "name": "並發" }
                },
                {
                    "bool": {
                        "must": {       // 必須匹配
                            "match": { "desc": "java" }
                        },
                        "must_not": {   // 不能匹配
                            "match": { "publisher": "電子" }
                        }
                    }
                }
            ],
            "minimum_should_match": 1   // 至少滿足should中的一個條件
        }
    }, 
    // 自定義排序
    "sort": [
        { "price": { "order": "desc" } }
    ]
}

注意: 排序的字段最好是數字, 或日期, 因為字符串字段會被分詞, ES會通過分詞后的某個詞去排序, 結果難以預測.

2. 多條件拼接 - 包含+范圍+排序

匹配檢索: name中包含"java"卻不包含"虛擬機";
范圍檢索: 價格大於50、小於80;
結果排序: 按照價格升序排序.

GET shop/_search
{
    "query": {
        "bool": {
            "must": {                       // 必須匹配
                "match": { "name": "java" }
            }, 
            "must_not": {                   // 必須不匹配
                "match": { "name": "虛擬機" }
            },
            "filter": {
                "range": {
                    "price": {
                        "gte": 40,
                        "lte": 80,
                        "boost": 2.0    // 設置得分的權重值(提升值), 默認是1.0
                    }
                }
            }
        }
    }
}

關於范圍檢索的使用, 請參考下篇文章: ES 22 - Elasticsearch對數值或日期類型進行范圍檢索

3. 定制檢索結果的排序規則

(1) 默認排序規則:

ES默認是按檢索結果的分值(_score)降序排列的.

某些情況下, 可能存在無實際意義的_score, 比如filter時所有_score的值都相同:

GET website/_search
{
    "query": {
        "bool": {
            "filter": {
                "term": {
                    "author_id": 5520   // 此時所有符合條件的_score都為0
                }
            }
        }
    }
}

// 或通過constant_score過濾:

GET website/_search
{
    "query": {
        "constant_score": {
            "filter": {
                "term": {
                    "author_id": 5520   // 此時所有符合條件的_score都為1
                }
            }
        }
    }
}

(2) 定制排序規則:

GET website/_search
{
    "query": {
        "constant_score": {
            "filter": {
                "term": {
                    "author_id": 5520
                }
            }
        }
    }, 
    "sort": [
        {
            "post_date": { "order": "asc" }
        }
    ]
}

四、Elasticsearch filter和query的不同

1. query和filter的本質區別?

query關注點:此文檔與此查詢子句的匹配程度如何?

filter關注點:此文檔和查詢子句匹配嗎?

2、Query檢索細化關注點

1)是否包含?

確定文檔是否應該成為結果的一部分.

2)相關度得分多少?

除了確定文檔是否匹配外,查詢子句還計算了表示文檔與其他文檔相比匹配程度的_score。

3)得分越高,相關度越高。

更相關的文件,在搜索排名更高。

典型應用場景:

1)全文檢索——這種相關性的概念非常適合全文搜索,因為很少有完全“正確”的答案。

舉例如下:

文檔中存在字段hotel_name:“上海浦東香格里拉酒店”

IK實際分詞結果如下:
上海浦東,上海,浦東,香格里拉,格里,里拉,酒店。

也就是說,搜索以上關鍵詞都能搜到:hotel_name:“上海浦東香格里拉酒店”的酒店。這些都是“相關”的。

但是搜索:“香格里” 是搜索不到結果的。

2)包含單詞“run”, 但也匹配”runs”, “running”, “jog”或者”sprint”。(都是奔跑的意思)

3. filter過濾細化關注點

1)是否包含?

確定是否包含在檢索結果中,回答只有“是”或“否”。

2)不涉及評分。

在搜索中沒有額外的相關度排名。

3)針對結構化數據。

適用於完全精確匹配,范圍檢索。

參見官網舉例:
以下場景適用於filter過濾檢索:

舉例1:時間戳timestamp 是否在2015至2016年范圍內?

舉例2:狀態字段status 是否設置為“published”?

4)更快。

只確定是否包括結果中,不需要考慮得分。

為什么會更快?——經常使用的過濾器將被Elasticsearch自動緩存,以提高性能。

4. query和filter的性能不同

過濾查詢(filter)是對集合包含/排除的簡單檢查,這使得它們計算速度非常快。 當至少有一個過濾查詢是“稀疏”(僅有少量匹配的文檔)時,可以利用各種優化,並且可以將緩存經常使用的filter過濾查詢緩存在內存中以加快訪問速度。

對比之下,query檢索(評分查詢)不僅要查找匹配的文檔,還要計算每個文檔的相關程度,這通常會使其比非評分文檔更復雜。 另外,查詢結果不可緩存。

由於倒排索引,只有幾個文檔匹配的簡單評分查詢(query檢索)可能會比跨越數百萬個文檔的過濾器(filter過濾)表現得更好。 但是,一般來說,fiter過濾的性能將勝過評分查詢(query檢索)。

過濾(filter)的目標是減少必須由評分查詢(query)檢查的文檔數量。

5. filter過濾怎么緩存呢?

Elasticsearch將創建一個文檔匹配過濾器的位集bitset(如果文檔匹配則為1,否則為0)。 隨后用相同的過濾器執行查詢將重用此信息。

每當添加或更新新文檔時,位集bitset也會更新。

6. 使用場景

全文檢索以及任何使用相關性評分的場景使用query檢索。

除此之外的其他使用filter過濾器過濾。

7. query和filter實戰

ebay在Elasticsearch使用經驗中總結到:

Use filter context instead of query context if possible.

即:如果可能,請使用filter過濾器上下文而不是query查詢上下文。

查詢query和過濾器filter已合並(在ES1.X版本是分開的,存在filtered檢索類型)。

ES高版本(2.X/5.X/6.x以后),任何查詢子句都可以在“查詢上下文query”中用作查詢,並在“過濾器上下文filter”中用作過濾器。

舉例:

GET /_search
{
  "query": { 
    "bool": { 
      "must": [
        { "match": { "title":   "Search"        }}, 
        { "match": { "content": "Elasticsearch" }}  
      ],
      "filter": [ 
        { "term":  { "status": "published" }}, 
        { "range": { "publish_date": { "gte": "2015-01-01" }}} 
      ]
    }
  }
}

參考資料:

Elasticsearch的高級檢索語法 (包括term、prefix、wildcard、fuzzy、boost等)
https://www.cnblogs.com/shoufeng/p/11103913.html
Elasticsearch URI search
https://www.elastic.co/guide/en/elasticsearch/reference/current/search-uri-request.html
query-filter-context
https://www.elastic.co/guide/en/elasticsearch/reference/current/query-filter-context.html#relevance-scores
Elasticsearch filter和query的不同
https://blog.csdn.net/laoyang360/article/details/80468757
queries_and_filters
https://www.elastic.co/guide/en/elasticsearch/guide/master/_queries_and_filters.html
How to monitor Elasticsearch performance
https://www.datadoghq.com/blog/monitor-elasticsearch-performance-metrics/
Elasticsearch Performance Tuning Practice at eBay
https://tech.ebayinc.com/engineering/elasticsearch-performance-tuning-practice-at-ebay/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM