elasticsearch DSL java api总结

引言

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(0).setSize(100)
                    .setTimeout(TimeValue.timeValueMillis(300))
                    .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" : 1.0
      }
    }
  }

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": { (1"bool": { (2"must": [
        { "match": { "title":   "Search"        }}, (3)
        { "match": { "content": "Elasticsearch" }}  (4)
      ],
      "filter": [ (5)
        { "term":  { "status": "published" }}, (6)
        { "range": { "publish_date": { "gte": "2015-01-01" }}} (7)
      ]
    }
  }
}

说明如下:
(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(20).to(40) // 从2040
        .includeLower(true)  // 是否包含下界,即>=20
        .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总结_第1张图片
使用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(5.0f);
TermQueryBuilder tqbB = QueryBuilders.termQuery("fieldB", "B").boost(2.0f);
TermQueryBuilder tqbC = QueryBuilders.termQuery("fieldC", "C").boost(0.2f);
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(0.2f); // 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,用于指定不同的子查询分数不同,从而文档取子查询中分数最高的一个。 这些可以从官网来去学习了解。

你可能感兴趣的:(elasticsearch)