ElasticSearch總結1-查詢表達式


參考資料:Elasticsearch: 權威指南 

在線地址:https://www.elastic.co/guide/cn/elasticsearch/guide/current/index.html

 

1. 查詢表達式

  查詢表達式(Query DSL)是一種非常靈活又富有表現力的 查詢語言。 Elasticsearch 使用它可以以簡單的 JSON 接口來展現 Lucene 功能的絕大部分。在你的應用中,你應該用它來編寫你的查詢語句。它可以使你的查詢語句更靈活、更精確、易讀和易調試。 要使用這種查詢表達式,只需將查詢語句傳遞給 query 參數:

GET /_search
{
    "query": YOUR_QUERY_HERE
}

  查詢語句的典型結構:

{
    QUERY_NAME: {
        ARGUMENT: VALUE,
        ARGUMENT: VALUE,...
    }
}

  如果是針對某個字段,那么它的結構如下:

{
    QUERY_NAME: {
        FIELD_NAME: {
            ARGUMENT: VALUE,
            ARGUMENT: VALUE,...
        }
    }
}

  舉例,使用 match 關鍵字查詢語句 來查詢 tweet 字段中包含 elasticsearch 的 tweet

GET /_search
{
    "query": {
        "match": {
            "tweet": "elasticsearch"
        }
    }
}

 

2. 查詢與過濾

  Elasticsearch 使用的查詢語言(DSL)擁有一套查詢組件,這些組件可以以無限組合的方式進行搭配。這套組件可以在以下兩種情況下使用:過濾情況(filtering context)和查詢情況(query context)。

  當使用於 過濾情況 時,查詢被設置成一個“不評分”或者“過濾”查詢。即,這個查詢只是簡單的問一個問題:“這篇文檔是否匹配?”。回答也是非常的簡單,yes 或者 no ,二者必居其一。

  當使用於 查詢情況 時,查詢就變成了一個“評分”的查詢。和不評分的查詢類似,也要去判斷這個文檔是否匹配,同時它還需要判斷這個文檔匹配的有 多好(匹配程度如何)。 

  性能差異:

  過濾查詢(Filtering queries)只是簡單的檢查包含或者排除,這就使得計算起來非常快。考慮到至少有一個過濾查詢(filtering query)的結果是 “稀少的”(很少匹配的文檔),並且經常使用不評分查詢(non-scoring queries),結果會被緩存到內存中以便快速讀取,所以有各種各樣的手段來優化查詢結果。

  相反,評分查詢(scoring queries)不僅僅要找出匹配的文檔,還要計算每個匹配文檔的相關性,計算相關性使得它們比不評分查詢費力的多。同時,查詢結果並不緩存。

  多虧倒排索引(inverted index),一個簡單的評分查詢在匹配少量文檔時可能與一個涵蓋百萬文檔的filter表現的一樣好,甚至會更好。但是在一般情況下,一個filter 會比一個評分的query性能更優異,並且每次都表現的很穩定。

過濾(filtering)的目標是減少那些需要通過評分查詢(scoring queries)進行檢查的文檔。

 

3. 查詢關鍵字

3.1 match_all 查詢

  match_all 查詢簡單的匹配所有文檔。在沒有指定查詢方式時,它是默認的查詢:

{ "match_all": {}}

  等同於空查詢,如下:

GET /_search
{} 

  它經常與 filter 結合使用—​例如,檢索收件箱里的所有郵件。所有郵件被認為具有相同的相關性,所以都將獲得分值為 1 的中性 _score。

 

3.2 match 查詢

  無論你在任何字段上進行的是全文搜索還是精確查詢,match 查詢是你可用的標准查詢。 如果你在一個全文字段上使用 match 查詢,在執行查詢前,它將用正確的分析器去分析查詢字符串:

{ "match": { "tweet": "About Search" }}

  如果在一個精確值的字段上使用它,例如數字、日期、布爾或者一個 not_analyzed 字符串字段,那么它將會精確匹配給定的值:

{ "match": { "age":    26           }}
{ "match": { "date":   "2014-09-01" }}
{ "match": { "public": true         }}
{ "match": { "tag":    "full_text"  }}

  對於精確值的查詢,你可能需要使用 filter 語句來取代 query,因為 filter 將會被緩存。接下來,我們將看到一些關於 filter 的例子。

 

3.3 multi_match 查詢

  multi_match 查詢可以在多個字段上執行相同的 match 查詢:

{
    "multi_match": {
        "query":    "full text search",
        "fields":   [ "title", "body" ]
    }
}

 

3.4 range 查詢

  range 查詢找出那些落在指定區間內的數字或者時間:

{
    "range": {
        "age": {
            "gte":  20,
            "lt":   30
        }
    }
}

  被允許的操作符如下:

  gt 大於

  gte 大於等於

  lt 小於

  lte 小於等於

 

3.5 term 查詢

  term 查詢被用於精確值匹配,這些精確值可能是數字、時間、布爾或者那些 not_analyzed 的字符串:

{ "term": { "age":    26           }}
{ "term": { "date":   "2014-09-01" }}
{ "term": { "public": true         }}
{ "term": { "tag":    "full_text"  }}

   term 查詢對於輸入的文本不 分析 ,所以它將給定的值進行精確查詢。

 

3.6 terms 查詢

  terms 查詢和 term 查詢一樣,但它允許你指定多值進行匹配。如果這個字段包含了指定值中的任何一個值,那么這個文檔滿足條件:

{ "terms": { "tag": [ "search", "full_text", "nosql" ] }}

  和 term 查詢一樣,terms 查詢對於輸入的文本不分析。它查詢那些精確匹配的值(包括在大小寫、重音、空格等方面的差異)。

 

3.7 exists查詢和 missing查詢 

  exists 查詢和 missing 查詢被用於查找那些指定字段中有值 (exists) 或無值 (missing) 的文檔。這與SQL中的 IS_NULL (missing) 和 NOT IS_NULL (exists) 在本質上具有共性:

{
    "exists":   {
        "field":    "title"
    }
}

  這些查詢經常用於某個字段有值的情況和某個字段缺值的情況。

 

4. 合並查詢語句

  你可以用 bool 查詢來實現你的需求。這種查詢將多查詢組合在一起,成為用戶自己想要的布爾查詢。

  它接收以下參數:

  must 文檔 必須 匹配這些條件才能被包含進來。

  must_not 文檔 必須不 匹配這些條件才能被包含進來。

  should 如果滿足這些語句中的任意語句,將增加 _score ,否則,無任何影響。它們主要用於修正每個文檔的相關性得分。

  filter 必須 匹配,但它以不評分、過濾模式來進行。這些語句對評分沒有貢獻,只是根據過濾標准來排除或包含文檔。

 

4.1 基礎組合

  由於這是我們看到的第一個包含多個查詢的查詢,所以有必要討論一下相關性得分是如何組合的。每一個子查詢都獨自地計算文檔的相關性得分。一旦他們的得分被計算出來, bool 查詢就將這些得分進行合並並且返回一個代表整個布爾操作的得分。

下面的查詢用於查找 title 字段匹配 how to make millions 並且不被標識為 spam 的文檔。那些被標識為 starred 或在2014之后的文檔,將比另外那些文檔擁有更高的排名。如果 兩者 都滿足,那么它排名將更高:

{
    "bool": {
        "must":     { "match": { "title": "how to make millions" }},
        "must_not": { "match": { "tag":   "spam" }},
        "should": [
            { "match": { "tag": "starred" }},
            { "range": { "date": { "gte": "2014-01-01" }}}
        ]
    }
}

  如果沒有 must 語句,那么至少需要能夠匹配其中的一條 should 語句。但,如果存在至少一條 must 語句,則對 should 語句的匹配沒有要求。

 

4.2 增加帶過濾器(filtering)的查詢

  如果我們不想因為文檔的時間而影響得分,可以用 filter 語句來重寫前面的例子:

{
    "bool": {
        "must":     { "match": { "title": "how to make millions" }},
        "must_not": { "match": { "tag":   "spam" }},
        "should": [
            { "match": { "tag": "starred" }}
        ],
        "filter": {
          "range": { "date": { "gte": "2014-01-01" }} 
        }
    }
}

  range 查詢已經從 should 語句中移到 filter 語句

  通過將 range 查詢移到 filter 語句中,我們將它轉成不評分的查詢,將不再影響文檔的相關性排名。

  由於它現在是一個不評分的查詢,可以使用各種對 filter 查詢有效的優化手段來提升性能。所有查詢都可以借鑒這種方式。將查詢移到 bool 查詢的 filter 語句中,這樣它就自動的轉成一個不評分的 filter 了。 

  如果你需要通過多個不同的標准來過濾你的文檔,bool 查詢本身也可以被用做不評分的查詢。簡單地將它放置到 filter 語句中並在內部構建布爾邏輯:

{
    "bool": {
        "must":     { "match": { "title": "how to make millions" }},
        "must_not": { "match": { "tag":   "spam" }},
        "should": [
            { "match": { "tag": "starred" }}
        ],
        "filter": {
          "bool": { 
              "must": [
                  { "range": { "date": { "gte": "2014-01-01" }}},
                  { "range": { "price": { "lte": 29.99 }}}
              ],
              "must_not": [
                  { "term": { "category": "ebooks" }}
              ]
          }
        }
    }
}

  將 bool 查詢包裹在 filter 語句中,我們可以在過濾標准中增加布爾邏輯

  通過混合布爾查詢,我們可以在我們的查詢請求中靈活地編寫 scoring 和 filtering 查詢邏輯。

 

4.3 constant_score 查詢

  盡管沒有 bool 查詢使用這么頻繁,constant_score 查詢也是你工具箱里有用的查詢工具。它將一個不變的常量評分應用於所有匹配的文檔。它被經常用於你只需要執行一個 filter 而沒有其它查詢(例如,評分查詢)的情況下。

  可以使用它來取代只有 filter 語句的 bool 查詢。在性能上是完全相同的,但對於提高查詢簡潔性和清晰度有很大幫助。

{
    "constant_score":   {
        "filter": {
            "term": { "category": "ebooks" } 
        }
    }
}

  term 查詢被放置在 constant_score 中,轉成不評分的 filter。這種方式可以用來取代只有 filter 語句的 bool 查詢。

 

5. 查詢語句分析

5.1 驗證是否合法

  查詢可以變得非常的復雜,尤其和不同的分析器與不同的字段映射結合時,理解起來就有點困難了。不過 validate-query API 可以用來驗證查詢是否合法。

GET /gb/tweet/_validate/query
{
   "query": {
      "tweet" : {
         "match" : "really powerful"
      }
   }
}

  以上 validate 請求的應答告訴我們這個查詢是不合法的:

{
  "valid" :         false,
  "_shards" : {
    "total" :       1,
    "successful" :  1,
    "failed" :      0
  }
}

 

5.2 理解錯誤信息

  為了找出 查詢不合法的原因,可以將 explain 參數 加到查詢字符串中:

GET /gb/tweet/_validate/query?explain 
{
   "query": {
      "tweet" : {
         "match" : "really powerful"
      }
   }
}

  explain 參數可以提供更多關於查詢不合法的信息。 很明顯,我們將查詢類型(match)與字段名稱 (tweet)搞混了:

{
  "valid" :     false,
  "_shards" :   { ... },
  "explanations" : [ {
    "index" :   "gb",
    "valid" :   false,
    "error" :   "org.elasticsearch.index.query.QueryParsingException:
                 [gb] No query registered for [tweet]"
  } ]
}

 

5.3 理解查詢語法

  對於合法查詢,使用 explain 參數將返回可讀的描述,這對准確理解 Elasticsearch 是如何解析你的 query 是非常有用的:

GET /_validate/query?explain
{
   "query": {
      "match" : {
         "tweet" : "really powerful"
      }
   }
}

  我們查詢的每一個 index 都會返回對應的 explanation ,因為每一個 index 都有自己的映射和分析器:

{
  "valid" :         true,
  "_shards" :       { ... },
  "explanations" : [ {
    "index" :       "us",
    "valid" :       true,
    "explanation" : "tweet:really tweet:powerful"
  }, {
    "index" :       "gb",
    "valid" :       true,
    "explanation" : "tweet:realli tweet:power"
  } ]
}

  從 explanation 中可以看出,匹配 really powerful 的 match 查詢被重寫為兩個針對 tweet 字段的 single-term 查詢,一個single-term查詢對應查詢字符串分出來的一個term。

  當然,對於索引 us ,這兩個 term 分別是 really 和 powerful ,而對於索引 gb ,term 則分別是 realli 和 power 。之所以出現這個情況,是由於我們將索引 gb 中 tweet 字段的分析器修改為 english 分析器。

 

6. 排序

  Elasticsearch默認是相關性排序的,為了按照相關性來排序,需要將相關性表示為一個數值。在 Elasticsearch 中, 相關性得分 由一個浮點數進行表示,並在搜索結果中通過 _score 參數返回, 默認排序是 _score 降序。

  相關性解釋:https://www.elastic.co/guide/cn/elasticsearch/guide/current/relevance-intro.html

 

6.1 按字段排序

  我們可以使用 sort 參數進行實現。下面的例子中,通過時間來對 tweets 進行排序是有意義的,最新的 tweets 排在最前。 

GET /_search
{
    "query" : {
        "bool" : {
            "filter" : { "term" : { "user_id" : 1 }}
        }
    },
    "sort": { "date": { "order": "desc" }}
}

 

7. 分頁查詢

  分頁查詢要在查詢請求體里使用size和from關鍵字,size是返回數量,from是跳過多少數據。

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

 


免責聲明!

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



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