Elasticsearch 入门教程 – bool 过滤器

在了解之前,先来理解filter与query不同:

Query与Filter

    查询在Query查询上下文和Filter过滤器上下文中,执行的操作是不一样的:

查询上下文:

     在查询上下文中,查询会回答这个问题——“这个文档匹不匹配这个查询,它的相关度高么?”

      如何验证匹配很好理解,如何计算相关度呢?之前说过,ES中索引的数据都会存储一个_score分值,分值越高就代表越匹配。另外关于某个搜索的      分值计算还是很复杂的,因此也需要一定的时间。

      查询上下文 是在 使用query进行查询时的执行环境,比如使用search的时候。

过滤器上下文:

     在过滤器上下文中,查询会回答这个问题——“这个文档匹不匹配?”

     答案很简单,是或者不是。它不会去计算任何分值,也不会关心返回的排序问题,因此效率会高一点。

     过滤上下文 是在使用filter参数时候的执行环境,比如在bool查询中使用Must_not或者filter 

      另外,经常使用过滤器,ES会自动的缓存过滤器的内容,这对于查询来说,会提高很多性能。

总结

   1 查询上下文中,查询操作不仅仅会进行查询,还会计算分值,用于确定相关度;在过滤器上下文中,查询操作仅判断是否满足查询条件

  2 过滤器上下文中,查询的结果可以被缓存。

前提准备:

(1)插入一些测试帖子数据

POST /forum/article/_bulk
{ "index": { "_id": 1 }}
{ "articleID" : "XHDK-A-1293-#fJ3", "userID" : 1, "hidden": false, "postDate": "2017-01-01" }
{ "index": { "_id": 2 }}
{ "articleID" : "KDKE-B-9947-#kL5", "userID" : 1, "hidden": false, "postDate": "2017-01-02" }
{ "index": { "_id": 3 }}
{ "articleID" : "JODL-X-1937-#pV7", "userID" : 2, "hidden": false, "postDate": "2017-01-01" }
{ "index": { "_id": 4 }}
{ "articleID" : "QQPX-R-3956-#aD8", "userID" : 2, "hidden": true, "postDate": "2017-01-02" }

布尔过滤器

    前面的两个例子都是单个过滤器(filter)的使用方式。 在实际应用中,我们很有可能会过滤多个值或字段。比方说,怎样用 Elasticsearch 来表达下面的 SQL ?

SELECT product
FROM   products
WHERE  (price = 20 OR productID = "XHDK-A-1293-#fJ3")
 AND  (price != 30)

    这种情况下,我们需要 bool (布尔)过滤器。 这是个 复合过滤器(compound filter) ,它可以接受多个其他过滤器作为参数,并将这些过滤器结合成各式各样的布尔(逻辑)组合。

一个 bool 过滤器由三部分组成:

{
  "bool" : {
     "must" :     [],
     "should" :   [],
     "must_not" : [],
  }
}
  • must

    所有的语句都 必须(must) 匹配,与 AND 等价。

  • must_not

    所有的语句都 不能(must not) 匹配,与 NOT 等价。

  • should

    至少有一个语句要匹配,与 OR 等价。

  就这么简单! 当我们需要多个过滤器时,只须将它们置入 bool 过滤器的不同部分即可。

一个 bool 过滤器的每个部分都是可选的(例如,我们可以只有一个 must 语句),而且每个部分内部可以只有一个或一组过滤器。

用 Elasticsearch 来表示本部分开始处的 SQL 例子,将两个 term 过滤器置入 bool 过滤器的 should 语句内,再增加一个语句处理 NOT 非的条件:

GET /my_store/products/_search
{
  "query" : {
     "filtered" : {
        "filter" : {
           "bool" : {
             "should" : [
                { "term" : {"price" : 20}},
                { "term" : {"productID" : "XHDK-A-1293-#fJ3"}}
             ],
             "must_not" : {
                "term" : {"price" : 30}
             }
          }
        }
     }
  }
}

注意,我们仍然需要一个 filtered 查询将所有的东西包起来。

 

在 should 语句块里面的两个 term 过滤器与 bool 过滤器是父子关系,两个 term 条件需要匹配其一。

如果一个产品的价格是 30 ,那么它会自动被排除,因为它处于 must_not 语句里面。

我们搜索的结果返回了 2 个命中结果,两个文档分别匹配了 bool 过滤器其中的一个条件:

"hits" : [
   {
       "_id" :     "1",
       "_score" :  1.0,
       "_source" : {
         "price" :     10,
         "productID" : "XHDK-A-1293-#fJ3"
       }
   },
   {
       "_id" :     "2",
       "_score" :  1.0,
       "_source" : {
         "price" :     20,
         "productID" : "KDKE-B-9947-#kL5"
       }
   }
]

与 term 过滤器中 productID = "XHDK-A-1293-#fJ3" 条件匹配

与 term 过滤器中 price = 20 条件匹配

Java 客户端代码:

SearchRequestBuilder srq =  client.prepareSearch("forum").setTypes("article");  
        srq.setSearchType(SearchType.DFS_QUERY_AND_FETCH);  
        QueryBuilder queryBuilder=QueryBuilders.constantScoreQuery(
        		 QueryBuilders.boolQuery().should(QueryBuilders.termQuery("postDate", "2017-01-01"))
        				 .should(QueryBuilders.termQuery("articleID", "XHDK-A-1293-#fJ3"))
        				.mustNot(QueryBuilders.termQuery("postDate", "2017-01-02")));
        
        srq.setQuery(queryBuilder);
        SearchResponse response=srq.execute().get();
        System.out.println(srq.toString());
        for (SearchHit searchHit : response.getHits()) {
			System.out.println(searchHit.getScore());
			Map source = searchHit.getSource();
			System.out.println(source.toString());
		}

嵌套布尔过滤器

尽管 bool 是一个复合的过滤器,可以接受多个子过滤器,需要注意的是 bool 过滤器本身仍然还只是一个过滤器。 这意味着我们可以将一个 bool 过滤器置于其他 bool 过滤器内部,这为我们提供了对任意复杂布尔逻辑进行处理的能力。

对于以下这个 SQL 语句:

SELECT document
FROM   products
WHERE  productID      = "KDKE-B-9947-#kL5"
 OR (     productID = "JODL-X-1937-#pV7"
      AND price     = 30 )

我们将其转换成一组嵌套的 bool 过滤器:

GET /my_store/products/_search
{
  "query" : {
     "filtered" : {
        "filter" : {
           "bool" : {
             "should" : [
               { "term" : {"productID" : "KDKE-B-9947-#kL5"}},
               { "bool" : {
                 "must" : [
                   { "term" : {"productID" : "JODL-X-1937-#pV7"}},
                   { "term" : {"price" : 30}}
                 ]
               }}
             ]
          }
        }
     }
  }
}

 

因为 term 和 bool 过滤器是兄弟关系,他们都处于外层的布尔逻辑 should 的内部,返回的命中文档至少须匹配其中一个过滤器的条件。

 

这两个 term 语句作为兄弟关系,同时处于 must 语句之中,所以返回的命中文档要必须都能同时匹配这两个条件。

得到的结果有两个文档,它们各匹配 should 语句中的一个条件:

"hits" : [
   {
       "_id" :     "2",
       "_score" :  1.0,
       "_source" : {
         "price" :     20,
         "productID" : "KDKE-B-9947-#kL5"
       }
   },
   {
       "_id" :     "3",
       "_score" :  1.0,
       "_source" : {
         "price" :      30,
         "productID" : "JODL-X-1937-#pV7"
       }
   }
]

这个 productID 与外层的 bool 过滤器 should 里的唯一一个 term 匹配。

 

这两个字段与嵌套的 bool 过滤器 must 里的两个 term 匹配。


Java 客户端代码:

SearchRequestBuilder srq =  client.prepareSearch("forum").setTypes("article");  
        srq.setSearchType(SearchType.DFS_QUERY_AND_FETCH);  
        srq.setQuery( QueryBuilders.boolQuery().should(
				 QueryBuilders.termQuery("productID", "XHDK-A-1293-#fJ3"))
		         .should(
		        QueryBuilders.boolQuery().must(QueryBuilders.termQuery("articleID", "JODL-X-1937-#pV7"))
		         .must(QueryBuilders.termQuery("postDate", "2017-01-01"))
		        		 ));
        SearchResponse response=srq.execute().get();
        System.out.println(srq.toString());
        for (SearchHit searchHit : response.getHits()) {
			System.out.println(searchHit.getScore());
			Map source = searchHit.getSource();
			System.out.println(source.toString());
		}

这只是个简单的例子,但足以展示布尔过滤器可以用来作为构造复杂逻辑条件的基本构建模块。

    https://www.cnblogs.com/xing901022/p/5994210.html

发表评论