天天看點

elasticsearch DSL java api總結引言query和filterterm級别query全文queryDSL的組合

引言

DSL,叫“特定領域語言”,是針對某一領域,具有受限表達性的一種計算機程式設計語言。elasticsearch的 query DSL即是針對elasticsearch檢索的一種特定語言。

es的DSL在使用java API通路es時候也特别好用,本文我們詳細了解下es的DSL java API的使用。

在使用java api檢索es時候,我們使用的方式是:

QueryBuilder builders = null;// 重點講這個的構造
            SearchResponse response = client.prepareSearch(index)
                    .setFrom().setSize()
                    .setTimeout(TimeValue.timeValueMillis())
                    .setFetchSource(retFields, null)
                    .setQuery(builders)
                    .setTypes(type)
                    .execute().actionGet();
           

上面查詢API中的setQuery就是指定查詢的DSL,也是本文主要講的。

es版本:5.1.x

query和filter

我們知道,es的查詢分為兩種query和filter,兩種不同的上下文環境用于不同的目的。

query

使用上下文

query字句解決的問題是“文檔和查詢字句比對程度”,并通過一個score分數來具體表示比對程度。

query子句查詢生效條件

直接在search API中指定query參數(通過setQuery),比如設定如下:

SearchRequestBuilder requestBuilder = client.prepareSearch(index);
requestBuilder.setQuery(QueryBuilders.termQuery("val", "field"));  // 指定query,使用的是query上下文
System.out.println(requestBuilder.toString());                     // 列印查詢語句 
SearchResponse response = requestBuilder.execute().actionGet();    // 執行query
           

在上例中,我們通過設定query參數,使用的就是query上下文查詢。如果通過toString方法列印出來,如下:

"query" : {
    "term" : {
      "field" : {
        "value" : "val",
        "boost" : 
      }
    }
  }
           

filter

使用上下文

filter字句解決的問題是“文檔和查詢字句是否比對”,隻有兩種情況YES和NO,不會計算分數。filter字句常用來過濾結構型資料,比如:

  • 是否時間字段timestamp處于2015和2016之間
  • 是否status字段被設定為true

另外,filter查詢會被es緩存到記憶體以提高性能。

filter字句查詢生效條件

觸發filter上下文有三種情況:

  • 在bool查詢中指定filter參數或者must_not參數;
  • 在 constant_score查詢中指定filter參數;
  • filter aggregation,即filter聚合查詢;

示例

如下一段查詢語句:

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

說明如下:

(1) query參數表明是query上下文;

(2)(3)(4)bool和兩個match查詢字句處于query上下文,用score表示比對度;

(5) filter參數表明是filter上下文;

(6) (7) term和range子句用于filter上下文,将會過濾掉不比對的文檔,這些查詢語句不會影響match查詢的比對分數;

term級别query

全文檔比對

用于比對所有的文檔,java API使用如下:

MatchAllQueryBuilder allQueryBuilder = QueryBuilders.matchAllQuery(); // match_all比對
SearchRequestBuilder requestBuilder = client.prepareSearch(index);
requestBuilder.setQuery(allQueryBuilder); 
SearchResponse response = requestBuilder.execute().actionGet();    // 執行query
           

上面用于比對index下面所有文檔。

term query

說明:term級别檢索是在es的反向索引中排序的term準确的比對。

場景:

  • 結構化資料的查詢,比如數字,日期,enum,而不是全文本字段;
  • 低級别查詢,忽略分詞處理;

    API使用:

TermQueryBuilder builder = QueryBuilders.termQuery("field", "val"); // 在field字段中查詢val
SearchRequestBuilder requestBuilder = client.prepareSearch(index);
requestBuilder.setQuery(builder);
SearchResponse response = requestBuilder.execute().actionGet();
           

terms query

說明:在指定字段中查詢包含任意一個term的文檔。

API使用:

TermsQueryBuilder builder = QueryBuilders.termsQuery("field", "val1", "val2"); // field中包含val1或者val2
SearchRequestBuilder requestBuilder = client.prepareSearch(index);
requestBuilder.setQuery(builder);
SearchResponse response = requestBuilder.execute().actionGet();
           

rank query

說明:在指定的field中是否包含固定的值(一個範圍值),比如數字,日期,字元串。

API使用:

RangeQueryBuilder builder = QueryBuilders.rangeQuery("age").from().to() // 從到
        .includeLower(true)  // 是否包含下界,即>=
        .includeUpper(true); // 是否包含上界,即<=40
SearchRequestBuilder requestBuilder = client.prepareSearch(index);
requestBuilder.setQuery(builder);
SearchResponse response = requestBuilder.execute().actionGet();
           

exist query

說明:查詢指定的field是否包含任意非null的值。

API使用:

ExistsQueryBuilder builder = QueryBuilders.existsQuery("field"); // 字段field是否非null
SearchRequestBuilder requestBuilder = client.prepareSearch(index);
requestBuilder.setQuery(builder);
SearchResponse response = requestBuilder.execute().actionGet();
           

prefix query

說明:查詢指定的filed是否包含指定的字首開頭的term。

API使用:

PrefixQueryBuilder builder = QueryBuilders.prefixQuery("field", "prefix"); // 字段field是否包含prefix開頭的term
SearchRequestBuilder requestBuilder = client.prepareSearch(index);
requestBuilder.setQuery(builder);
SearchResponse response = requestBuilder.execute().actionGet();
           

wildcard query

說明:查詢指定的field是否包含符合通配符比對的term,通配符支援?和*。

API使用:

WildcardQueryBuilder builder = QueryBuilders.wildcardQuery("field", "a?pre*"); // 字段field是否比對a?pre*
SearchRequestBuilder requestBuilder = client.prepareSearch(index);
requestBuilder.setQuery(builder);
SearchResponse response = requestBuilder.execute().actionGet();
           

其他query

其他還包括ids query,type query,regexp query,類似上面一樣。

全文query

即full text query,一般使用者類似郵件内容、文章内容這樣的全文檢索,每個field對應一個analyzer,即将field内容分詞并建構反向索引。通常也會在執行檢索前對query字元串進行分詞(每個field對應一個analyzer或search_analyzer。

全文query相關API使用參考官網。

DSL的組合

bool query

我們經常遇到如果我的查詢條件是(A || B ) && (C || D)這樣情況時,該如何組織我們的API,這其實就是一個bool組合查詢。

bool查詢是将多種查詢組合在一起,并且每個都對應一個“事件”(即must,should,must_not和filter),四種事件說明如下:

事件 描述
must 查詢子句must出現在文檔中,并且會影響文檔得分score
filter 查詢子句must出現在文檔中,但是不會影響文檔得分,并且會緩存
should 查詢子句should出現在文檔中,即并列的should子句必須有一個或者多個出現在文檔中,可以通過設定參數 minimum_should_match來指定最少比對的查詢子句
must_not 查詢子句一定不能出現在文檔中,處于filter上下文,不影響文檔得分,會被緩存

是以,bool組合查詢條件就像建構一棵樹一樣,按照我們的邏輯構造bool查詢即可,比如上述的(A || B ) && (C || D)組合構造結構如下圖:

elasticsearch DSL java api總結引言query和filterterm級别query全文queryDSL的組合

使用java api編寫代碼如下:

BoolQueryBuilder builder = QueryBuilders.boolQuery();
BoolQueryBuilder shoud1 = QueryBuilders.boolQuery();
TermQueryBuilder tqbA = QueryBuilders.termQuery("fieldA", "A");
TermQueryBuilder tqbB = QueryBuilders.termQuery("fieldB", "B");
shoud1.should(tqbA);
shoud1.should(tqbB);
BoolQueryBuilder shoud2 = QueryBuilders.boolQuery();
TermQueryBuilder tqbC = QueryBuilders.termQuery("fieldC", "C");
TermQueryBuilder tqbD = QueryBuilders.termQuery("fieldD", "D");
shoud2.should(tqbC);
shoud2.should(tqbD);
builder.must(shoud1);
builder.must(shoud2);
SearchRequestBuilder requestBuilder = client.prepareSearch(index);
requestBuilder.setQuery(builder);
SearchResponse response = requestBuilder.execute().actionGet();
           

boosting query

在實際使用過程中,我們經常用到的是,對于不同關鍵詞的查詢,我們希望不同term詞對查詢結果得分score的影響不同,即不同查詢詞的權重不同;還有一種情況就是,我們希望包含某些查詢詞的文檔降級(而不是直接過濾掉),這時候就可以用到我們的booting查詢了。

指定boost值得java示例如下:

BoolQueryBuilder builder = QueryBuilders.boolQuery();
TermQueryBuilder tqbA = QueryBuilders.termQuery("fieldA", "A").boost(f);
TermQueryBuilder tqbB = QueryBuilders.termQuery("fieldB", "B").boost(f);
TermQueryBuilder tqbC = QueryBuilders.termQuery("fieldC", "C").boost(f);
SearchRequestBuilder requestBuilder = client.prepareSearch(index);
requestBuilder.setQuery(builder);
SearchResponse response = requestBuilder.execute().actionGet();
           

同樣,也可以直接使用boost query,示例如下:

TermQueryBuilder tqbA = QueryBuilders.termQuery("fieldA", "A");
TermQueryBuilder tqbB = QueryBuilders.termQuery("fieldB", "B");
BoostingQueryBuilder builder = QueryBuilders.boostingQuery(tqbA, tqbB).negativeBoost(f); // tqbA提權,tqbB降級
SearchRequestBuilder requestBuilder = client.prepareSearch(index);
requestBuilder.setQuery(builder);
SearchResponse response = requestBuilder.execute().actionGet();
           

其他組合

除了常用的bool query和boost query,還有其他幾種compound query方式。比如function score query,可以指定計算文檔分數的函數;constant score query,指定每個文檔的分數相同;dis max query,用于指定不同的子查詢分數不同,進而文檔取子查詢中分數最高的一個。 這些可以從官網來去學習了解。

繼續閱讀