Elasticsearch查詢

Query DSLhtml

Elasticsearch提供了一個基於JSON的完整的查詢DSL(領域特定語言)。它定義的查詢語言由兩種類型的子句組成:「葉子查詢子句」和「組合查詢子句」。正則表達式

葉子查詢子句json

葉子查詢子句查找特定字段中的特定值,例如 matchtermrange 查詢。緩存

複合查詢子句app

複合查詢子句包裝其餘葉子或複合查詢,並用於以邏輯方式組合多個查詢(如 bool 或 dis_max 查詢),或更改其行爲(如 constant_score 查詢)。curl

1.  Query and filter contextelasticsearch

查詢子句的行爲取決於它是用在查詢上下文(query context)仍是用在過濾器上下文(filter context):ide

1.1.  Query context性能

在查詢上下文中的查詢子句回答了「這個文檔與這個查詢子句的匹配程度是怎樣的?」問題。除了決定文檔是否匹配之外,查詢子句還會計算一個「_score」,它表示文檔與其餘文檔的相關程度。ui

1.2.  Filter context

在過濾器上下文中,一個查詢子句回答了「這個文檔與查詢子句匹配嗎?」的問題。這個答案是簡單的Yes或者No,也不會計算分數。過濾上下文主要用於過濾結構化數據,例如:

  • 這個timestamp在2015年到2016年的範圍內嗎?
  • 這個status字段的值是「published」嗎?

PS:Query VS Filter

  1. 查詢反應的是文檔與查詢子句的匹配程度,而過濾反應的是文檔是否匹配查詢子句
  2. 一個是篩選是否知足條件,狀況無非兩種:是或不是;一個是看知足條件的記錄與查詢條件的匹配程度
  3. 哪些知足條件,這是過濾;知足條件的這些記錄與條件的匹配程度,這是查詢
  4. 過濾不會計算評分,查詢會計算評分

頻繁使用的過濾器將被Elasticsearch自動緩存,以提升性能。

當查詢子句中被傳遞了一個filter參數時過濾器上下文就生效了。例如,bool查詢中的filter參數或者must_not參數。

下面是一個查詢子句的例子,這個查詢將匹配知足如下全部條件的文檔:

  • title 字段包含單詞「search
  • content 字段包含單詞「elasticsearch
  • status 字段包含明確的單詞「published
  • publish_date 字段的包含的日期大於或等於2015-01-01
curl -X GET "localhost:9200/_search" -H 'Content-Type: application/json' -d'
{
    "query": { 
        "bool": { 
            "must": [
                { "match": { "title":   "Search"        }}, 
                { "match": { "content": "Elasticsearch" }}  
            ],
            "filter": [ 
                { "term":  { "status": "published" }}, 
                { "range": { "publish_date": { "gte": "2015-01-01" }}} 
            ]
        }
    }
}
'

關於上面的查詢子句做以下說明:

  1. quary 參數表示這是一個查詢上下文
  2. bool 和 兩個match子句用在查詢上下文中,代表它們參與每條文檔的打分
  3. filter 參數代表這是過濾器上下文
  4. termrange 子句用在過濾器上下文中,它們會過濾掉不匹配的文檔,並且不會影響匹配文檔的分數

(PS:類比SQL的話,match至關於模糊查詢,term至關於精確查詢,range至關於範圍查詢)

2.  Match All Query

最簡單的查詢,匹配全部文檔,使它們的_score爲1.0

curl -X GET "localhost:9200/_search" -H 'Content-Type: application/json' -d'
{
    "query": {
        "match_all": {}
    }
}
'

_score能夠被改變,經過用boost參數

curl -X GET "localhost:9200/_search" -H 'Content-Type: application/json' -d'
{
    "query": {
        "match_all": { "boost" : 1.2 }
    }
}
'

match_all相反的是match_none,它不匹配任何文檔

curl -X GET "localhost:9200/_search" -H 'Content-Type: application/json' -d'
{
    "query": {
        "match_none": {}
    }
}
'

3.  Full text queries

3.1.  Match Query

match查詢接受文本/數值/日期類型的數據,分析它們,並構造一個查詢。

match是一種布爾類型的查詢。這意味着它對提供的文本進行分析,並在分析的過程當中爲提供的文本構造一個布爾查詢。operator 選項能夠設置爲 or 或者 and 以此來控制布爾子句(默認是 or )。例如:

curl -X GET "localhost:9200/_search" -H 'Content-Type: application/json' -d'
{
    "query": {
        "match" : {
            "message" : "this is a test"
        }
    }
}
'

注意,查詢語句都是以「query」開頭的,這裏「message」是字段名

你也能夠加一些參數,好比:

curl -X GET "localhost:9200/_search" -H 'Content-Type: application/json' -d'
{
    "query": {
        "match" : {
            "message" : {
                "query" : "this is a test",
                "operator" : "and"
            }
        }
    }
}
'

(PS:match是模糊查詢)

3.2.  Match Phrase Query

match_phrase 查詢與 match相似,可是它是用於精確匹配或單詞接近匹配的。例如:

curl -X GET "localhost:9200/_search" -H 'Content-Type: application/json' -d'
{
    "query": {
        "match_phrase" : {
            "message" : "this is a test"
        }
    }
}
'

固然,你也能夠加參數

curl -X GET "localhost:9200/_search" -H 'Content-Type: application/json' -d'
{
    "query": {
        "match_phrase" : {
            "message" : {
                "query" : "this is a test",
                "analyzer" : "my_analyzer"
            }
        }
    }
}
'

這裏「analyzer」是用來設置用那個分析器來分析文本

3.3.  Match Phrase Prefix Query

相似於match_phrase查詢,可是對最後一個單詞進行通配符搜索。

match_phrase_prefix容許文本的最後一個單詞進行前綴匹配

curl -X GET "localhost:9200/_search" -H 'Content-Type: application/json' -d'
{
    "query": {
        "match_phrase_prefix" : {
            "message" : "quick brown f"
        }
    }
}
'

除了match_phrase容許的那些參數外,match_phrase_prefix還能夠接受一個max_expansions參數,它是用來控制最後一個單詞能夠擴展多少後綴(默認50)。

curl -X GET "localhost:9200/_search" -H 'Content-Type: application/json' -d'
{
    "query": {
        "match_phrase_prefix" : {
            "message" : {
                "query" : "quick brown f",
                "max_expansions" : 10
            }
        }
    }
}
'

3.4.  Multi Match Query

multi_match 至關於 match 的多字段版本

顧名思義,multi_match能夠指定多個字段,而match只能針對一個字段

curl -X GET "localhost:9200/_search" -H 'Content-Type: application/json' -d'
{
  "query": {
    "multi_match" : {
      "query":    "this is a test", 
      "fields": [ "subject", "message" ] 
    }
  }
}
'

另外,字段能夠用通配符,例以下面的例子中能夠查詢 title , first_name , last_name 等字段:

curl -X GET "localhost:9200/_search" -H 'Content-Type: application/json' -d'
{
  "query": {
    "multi_match" : {
      "query":    "Will Smith",
      "fields": [ "title", "*_name" ] 
    }
  }
}
'

單個字段能夠被提高,例如:

curl -X GET "localhost:9200/_search" -H 'Content-Type: application/json' -d'
{
  "query": {
    "multi_match" : {
      "query" : "this is a test",
      "fields" : [ "subject^3", "message" ] 
    }
  }
}
'

上面的例子,subject字段的重要性是message字段的三倍

3.5.  Query String Query

支持Lucene查詢字符串語法,容許指定 AND | OR | NOT ,而且在單個查詢字符串中進行多字段查詢

curl -X GET "localhost:9200/_search" -H 'Content-Type: application/json' -d'
{
    "query": {
        "query_string" : {
            "default_field" : "content",
            "query" : "this AND that OR thus"
        }
    }
}
'

query_string查詢解析輸入並圍繞操做符拆分文本,每一個文本部分都是獨立分析的,例如:

curl -X GET "localhost:9200/_search" -H 'Content-Type: application/json' -d'
{
    "query": {
        "query_string" : {
            "default_field" : "content",
            "query" : "(new york city) OR (big apple)"
        }
    }
}
'

上面的例子中,將被拆分紅 「new york city」 和 「big apple」 兩部分,而且每一部分都被分析器獨立分析

注意,按操做符拆分

query_string的參數包括:

query  實例被解析的查詢文本

default_field  若是沒有指定前綴字段的話,這是默認的查詢字段。(默認查詢全部字段)

default_operator  若是沒有明確指定操做符的話,那麼這是默認的操做符。例如,若是默認操做符是OR的話,那麼「my name is jack」將被翻譯成「my OR name OR is OR jack」,同理,若是是AND,則被翻譯成「my AND name AND is AND jack」

analyzer  用來解析查詢字符串的解析器的名字

allow_leading_wildcard  若是設置了,那麼 * 或 ? 容許做爲第一個字符。默認是true

lenient  若是設置爲true,則格式失敗將被忽略

在query_string中,多字段查詢應該這樣寫:

curl -X GET "localhost:9200/_search" -H 'Content-Type: application/json' -d'
{
    "query": {
        "query_string" : {
            "fields" : ["content", "name"],
            "query" : "this AND that"
        }
    }
}
'

等價於

curl -X GET "localhost:9200/_search" -H 'Content-Type: application/json' -d'
{
    "query": {
        "query_string": {
            "query": "(content:this OR name:this) AND (content:that OR name:that)"
        }
    }
}
'

上面兩個是等價的

3.6.  Simple Query String Query

simple_query_string 是query_string的一個更簡單、更健壯、更適合面向用戶的版本

使用SimpleQueryParser解析上下文的查詢。與常規的query_string查詢不一樣,simple_query_string查詢永遠不會拋出異常,並丟棄查詢的無效部分。

curl -X GET "localhost:9200/_search" -H 'Content-Type: application/json' -d'
{
  "query": {
    "simple_query_string" : {
        "query": "\"fried eggs\" +(eggplant | potato) -frittata",
        "fields": ["title^5", "body"],
        "default_operator": "and"
    }
  }
}
'

3.7.  實例練習

準備數據

//    刪除索引
curl -X DELETE "192.168.1.134:9200/book"

//    建立索引
curl -X PUT "192.168.1.134:9200/book" -H 'Content-Type: application/json' -d'
{
    "settings" : {
        "number_of_shards" : 1
    },
    "mappings" : {
        "_doc" : {
            "properties" : {
                "title":        { "type": "text"  }, 
                "author":         { "type": "text"  }, 
                "introduction": { "type": "text"  },
                "publish_date": { 
                    "type": "date",
                    "format": "yyyy-MM-dd"
                }
            }
        }
    }
}
'

//    查看索引
curl -X GET "192.168.1.134:9200/book?pretty"

//    插入文檔
curl -X PUT "192.168.1.134:9200/book/_doc/1" -H 'Content-Type: application/json' -d'
{
    "title" : "Hello Java",
    "author": "zhangsan",
    "publish_date" : "2008-11-15",
    "introduction" : "This is a book for novice."
}
'

//    查看文檔
curl -X GET "192.168.1.134:9200/book/_search?pretty" -H 'Content-Type: application/json' -d'
{
    "query": {
        "match_all": {}
    }
}
'

 

match查詢(注意,match查詢只能是針對單個字段)

這個例子中,咱們用「Java」查詢到2條,接下來用「Java入門」將查到5條

這是由於解析器會將「Java入門」拆分爲「Java」和「入門」兩個單詞,並且默認的操做符是or

也就是說,查詢的結果是title中包含「Java」或者「入門」的記錄

如今變成查詢title中同時包含「Java」和「入門」的記錄,所以只有1條

 multi_match多字段查詢

 match_phrase查詢

對比不難發現,一樣的關鍵字「Java從」,用match查出5條,用match_phrase只查出1條

 

query_string查詢

4.  Term level queries(單詞級別查詢)

全文本查詢會在執行以前對查詢字符串進行分析,而單詞級別查詢會對存儲在反向索引中的精確的term進行操做。

這些查詢一般用於結構化的數據,好比:numbers , dates ,enums 等,而不是對全文本字段。

(PS:也就是說,全文本查詢以前要先對文本內容進行分詞,而單詞級別的查詢直接在相應字段的反向索引中精確查找,單詞級別的查詢通常用於數值、日期等類型的字段上)

4.1.  Term Query

在指定的字段中查找包含指定的精確的term的文檔

term查詢將在反向索引(或者叫倒排索引)中查找包含特定的精確的term的文檔。例如:

curl -X POST "localhost:9200/_search" -H 'Content-Type: application/json' -d'
{
  "query": {
    "term" : { "user" : "Kimchy" } 
  }
}
'

上面的例子,在user字段的反向索引中查找包含精確的Kimchy的文檔

還能夠指定一個boost參數,使這個term查詢比另外一個查詢具備更高的相關性得分。例如:

curl -X GET "localhost:9200/_search" -H 'Content-Type: application/json' -d'
{
    "query": {
        "bool": {
            "should": [
            {
                "term": {
                    "status": {
                        "value": "urgent",
                        "boost": 2.0 
                    }
                }
            },
            {
                "term": {
                    "status": "normal" 
                }
            }
          ]
        }
    }
}
'

這個例子中,urgent查詢子句有一個boost參數值爲2.0,這就意味着它的重要程度是後面的normal查詢子句的兩倍,normal子句默認的boost是1.0

4.2.  Terms Query

查找包含指定字段中指定的任何確切term的文檔

篩選出與所提供的terms中任何一個匹配的文檔

curl -X GET "localhost:9200/_search" -H 'Content-Type: application/json' -d'
{
    "query": {
        "terms" : { "user" : ["kimchy", "elasticsearch"]}
    }
}
'

4.3.  Range Query

查找指定字段在指定範圍內包含值(日期、數字或字符串)的文檔。

下面的例子返回age字段的值在10到20之間的文檔:

curl -X GET "localhost:9200/_search" -H 'Content-Type: application/json' -d'
{
    "query": {
        "range" : {
            "age" : {
                "gte" : 10,
                "lte" : 20,
                "boost" : 2.0
            }
        }
    }
}
'

range查詢能夠接受下列參數:

gte  大於或等於

gt    大於

lte   小於或等於

lt     小於

boost  設置boost值,默認是1.0

4.3.1.  Range on date fields

當range查詢用於date類型的字段時,範圍能夠用Date Math表示:

curl -X GET "localhost:9200/_search" -H 'Content-Type: application/json' -d'
{
    "query": {
        "range" : {
            "date" : {
                "gte" : "now-1d/d",
                "lt" :  "now/d"
            }
        }
    }
}
'

當使用Date Math將日期四捨五入到最近的日期、月份、小時等時,四捨五入日期取決於範圍的兩端是包含的仍是排除的。

例如:

rounded up 向上舍入

rounded down 向下舍入

gt 大於2014-11-18||/M  變成 2014-11-30T23:59:59.999 

gte 大於或等於2014-11-18||/M  變成 2014-11-01

lt 小於2014-11-18||/M  變成  2014-11-01

lte 小於或等於2014-11-18||/M  變成2014-11-30T23:59:59.999 

這個其實很好理解,

大於2014-11-18||/M至關因而大於2014年11月,所以大於2014-11-18||/M等價於大於2014-11-30 23:59:59

也就是說,大於11月,至關因而大於11月的最後一天,即11-30 23:59:59

同理,大於或等於2014-11-18||/M,至關於大於或等於11月,天然是11月的第一天,即2014-11-01

同理,小於2014-11-18||/M,至關於小於11月,天然是小於11月1日,故而小於2014-11-18||/M等價於小於2014-11-01

同理,小於或等於2014-11-18||/M,等於11月天然是包含11月的,意味着小於11月30日,故而小於或等於2014-11-18||/M等價於小於或等於2014-11-30 23:59:59

4.3.2.  Date format in range query

在日期範圍查詢的時候,咱們能夠指定日期格式。例如:

curl -X GET "localhost:9200/_search" -H 'Content-Type: application/json' -d'
{
    "query": {
        "range" : {
            "born" : {
                "gte": "01/01/2012",
                "lte": "2013",
                "format": "dd/MM/yyyy||yyyy"
            }
        }
    }
}
'

這個例子是查詢在2012-01-01到2013-12-31之間出生的人

下面看時間範圍查詢

curl -X GET "localhost:9200/_search" -H 'Content-Type: application/json' -d'
{
    "query": {
        "range" : {
            "timestamp" : {
                "gte": "2015-01-01 00:00:00", 
                "lte": "now", 
                "time_zone": "+01:00"
            }
        }
    }
}
'

4.4.  Exsit Query

在特定的字段中查找非空值的文檔

curl -X GET "localhost:9200/_search" -H 'Content-Type: application/json' -d'
{
    "query": {
        "exists" : { "field" : "user" }
    }
}
'

4.5.  Prefix Query

查找包含帶有指定前綴的term的文檔

curl -X GET "localhost:9200/_search" -H 'Content-Type: application/json' -d'
{ "query": {
    "prefix" : { "user" : "ki" }
  }
}
'

能夠關聯boost

curl -X GET "localhost:9200/_search" -H 'Content-Type: application/json' -d'
{ "query": {
    "prefix" : { "user" :  { "value" : "ki", "boost" : 2.0 } }
  }
}
'

4.6.  Wildcard Query

支持通配符查詢,*表示任意字符,?表示任意單個字符

curl -X GET "localhost:9200/_search" -H 'Content-Type: application/json' -d'
{
    "query": {
        "wildcard" : { "user" : "ki*y" }
    }
}
'

能夠加boost參數

curl -X GET "localhost:9200/_search" -H 'Content-Type: application/json' -d'
{
    "query": {
        "wildcard" : { "user" : { "value" : "ki*y", "boost" : 2.0 } }
    }
}
'

4.7.  Regexp Query

正則表達式查詢

curl -X GET "localhost:9200/_search" -H 'Content-Type: application/json' -d'
{
    "query": {
        "regexp":{
            "name.first": "s.*y"
        }
    }
}
'

4.8.  Ids Query

用_uid字段查詢

curl -X GET "localhost:9200/_search" -H 'Content-Type: application/json' -d'
{
    "query": {
        "ids" : {
            "type" : "_doc",
            "values" : ["1", "4", "100"]
        }
    }
}
'

4.9.  實例練習

5.  複合查詢

複合查詢包裝其餘複合查詢或葉子查詢,以組合它們的結果和得分,更改它們的行爲,或從查詢切換到篩選上下文。

5.1.  固定分數查詢

curl -X GET "localhost:9200/_search" -H 'Content-Type: application/json' -d'
{
    "query": {
        "constant_score" : {
            "filter" : {
                "term" : { "user" : "kimchy"}
            },
            "boost" : 1.2
        }
    }
}
'

5.2.  布爾查詢

關於should子句,特別要注意:

若是這個布爾查詢位於查詢上下文,而且有must或者filter子句,那麼即便should子句沒有匹配任何文檔,也不要緊
若是是位於過濾器上下文,或者既沒有must也沒有filter,那麼至少有一個should查詢必須匹配文檔。
這個行爲能夠經過設置minimum_should_match參數來顯式地控制。

舉個例子:

curl -X POST "localhost:9200/_search" -H 'Content-Type: application/json' -d'
{
    "query": {
        "bool" : {
            "must" : {
                "term" : { "user" : "kimchy" }
            },
            "filter": {
                "term" : { "tag" : "tech" }
            },
            "must_not" : {
                "range" : {
                    "age" : { "gte" : 10, "lte" : 20 }
                }
            },
            "should" : [
                { "term" : { "tag" : "wow" } },
                { "term" : { "tag" : "elasticsearch" } }
            ],
            "minimum_should_match" : 1,
            "boost" : 1.0
        }
    }
}
'

查詢user爲「kimchy」,而且tag爲「tech」,而且age不在10~20之間,而且tag爲wow或elasticsearch的文檔

filter查詢分數默認是0

curl -X GET "localhost:9200/_search" -H 'Content-Type: application/json' -d'
{
  "query": {
    "bool": {
      "filter": {
        "term": {
          "status": "active"
        }
      }
    }
  }
}
'

5.3.  實例練習

 

參考

https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl.html

相關文章
相關標籤/搜索