赞
踩
一、过滤相关点:
1、查询与过滤:
Elasticsearch 使用的查询语言(DSL) 拥有一套查询组件,这些组件可以以无限组合的方式进行搭配。这套组件可以在以下两种情况下使用:过滤情况(filtering context)和查询情况(query context)。
当使用于 过滤情况 时,查询被设置成一个“不评分”或者“过滤”查询。即,这个查询只是简单的问一个问题:“这篇文档是否匹配?”。回答也是非常的简单,yes 或者 no ,二者必居其一。
说明:
自 Elasticsearch 问世以来,查询与过滤(queries and filters)就独自成为 Elasticsearch 的组件。但从 Elasticsearch 2.0 开始,过滤(filters)已经从技术上被排除了,同时所有的查询(queries)拥有变成不评分查询的能力。
然而,为了明确和简单,我们用 "filter" 这个词表示不评分、只过滤情况下的查询。你可以把 "filter" 、 "filtering query" 和 "non-scoring query" 这几个词视为相同的。相似的,如果单独地不加任何修饰词地使用 "query" 这个词,我们指的是 "scoring query" 。
2、性能差异:
过滤查询(Filtering queries)只是简单的检查包含或者排除,这就使得计算起来非常快。考虑到至少有一个过滤查询(filtering query)的结果是 “稀少的”(很少匹配的文档),并且经常使用不评分查询(non-scoring queries),结果会被缓存到内存中以便快速读取,所以有各种各样的手段来优化查询结果。相反,评分查询(scoring queries)不仅仅要找出 匹配的文档,还要计算每个匹配文档的相关性,计算相关性使得它们比不评分查询费力的多。同时,查询结果并不缓存。
多亏倒排索引(inverted index),一个简单的评分查询在匹配少量文档时可能与一个涵盖百万文档的filter表现的一样好,甚至会更好。但是在一般情况下,一个filter 会比一个评分的query性能更优异,并且每次都表现的很稳定。过滤(filtering)的目标是减少那些需要通过评分查询(scoring queries)进行检查的文档。
参考:https://www.elastic.co/guide/cn/elasticsearch/guide/current/_queries_and_filters.html
二、过滤实例:
在之前es版本(2.0之前)的官网中,介绍了两种过滤:一个是Filtered Query,一个是Post Filter。前者是先使用filter,过滤后的结果再query;后者是先query,query的结果再过滤。而在es中,filter的操作使用了cache,速度比query快。
在最新2.0版本的官网上中,提到了:
现在是时候忘掉你所知道的关于查询和过滤器的一切了:Elasticsearch 2.0将自己做出更好的决定,而不是依靠用户来制定一个优化的查询。这一变化在API层面几乎是看不见的,但是让我们来深入探讨使之成为可能的内部变化。本篇文章中提到的大部分更改都是在Lucene 5.0,5.1和5.2中完成的,并将集成到Elasticsearch 2.0中。
在Elasticsearch 2.0中,查询和过滤器是相同的内部对象,可以配置这些对象来评分文档或跳过评分。然后,查询DSL确保正确传播信息:例如,如果bool查询需要产生分数,则bool查询的must子句将需要产生分数,而must_not子句永远不需要产生分数,因为它可能只是用于过滤文件。为了使查询的DSL更加符合这种变化,我们已经废弃了过滤的查询,赞成在bool查询中使用一个新的过滤器子句:过滤器子句就像must子句,除了它们没有贡献分数。意味着:
- {
- “filtered” : {
- “query”: { query definition },
- “filter”: { filter definition }
- }
- }
应该被替代成:
- {
- “bool” : {
- “must”: { query definition },
- “filter”: { filter definition }
- }
- }
注:查询DSL仍然是向后兼容的,尽管有这种改变:如果你尝试运行一个过滤的查询,它将在内部解析为一个bool查询。但是,我们鼓励您迁移到新的语法,因为在未来的发行版中,已过滤的查询将被删除。
实例1:postfilter
注:使用QueryBuilder创建过滤(代替了之前版本的FilterBuilder)
public static void filterQuery1(String indexName,String indexType) { QueryBuilder qb = QueryBuilders.boolQuery() .must(QueryBuilders.constantScoreQuery(QueryBuilders.matchQuery("title", "java")).boost(1f)) .should(QueryBuilders.constantScoreQuery(QueryBuilders.termQuery("title", "elasticsearch")).boost(5f)) .should(QueryBuilders.termQuery("title", "hadoop")); QueryBuilder fb = QueryBuilders.rangeQuery("age").from(10).to(20); SearchResponse searchResponse = transportClient.prepareSearch(indexName).setTypes(indexType) .setQuery(qb) .setPostFilter(fb) .get(); SearchHits hits = searchResponse.getHits(); //long totalHits = hits.getTotalHits(); SearchHit[] hits2 = hits.getHits(); for (SearchHit sh:hits2) { Map<String, Object> source = sh.getSource(); String id = sh.getId(); float score = sh.getScore(); System.out.println("source:"+source+",id:"+id+",score:"+score); } }
实例2:filter
A、之前这种写法已经被废弃:QueryBuilders.
public static void filterQuery2(String indexName,String indexType) { QueryBuilder qb = QueryBuilders.boolQuery() .must(QueryBuilders.constantScoreQuery(QueryBuilders.matchQuery("title", "java")).boost(1f)) .should(QueryBuilders.constantScoreQuery(QueryBuilders.termQuery("title", "elasticsearch")).boost(5f)) .should(QueryBuilders.termQuery("title", "hadoop")) .filter(QueryBuilders.rangeQuery("age").from(10).to(20)); System.out.println(qb.toString()); SearchResponse searchResponse = transportClient.prepareSearch(indexName).setTypes(indexType) .setQuery(qb) .get(); SearchHits hits = searchResponse.getHits(); //long totalHits = hits.getTotalHits(); SearchHit[] hits2 = hits.getHits(); for (SearchHit sh:hits2) { Map<String, Object> source = sh.getSource(); String id = sh.getId(); float score = sh.getScore(); System.out.println("source:"+source+",id:"+id+",score:"+score); } }
- QueryBuilder qb = QueryBuilders.boolQuery()
- .must(QueryBuilders.constantScoreQuery(QueryBuilders.matchQuery("title", "java")).boost(1f))
- .should(QueryBuilders.constantScoreQuery(QueryBuilders.termQuery("title", "elasticsearch")).boost(5f))
- .should(QueryBuilders.termQuery("title", "hadoop"));
- System.out.println(qb.toString());
这样的boolean查询,会被优化成如下的dsl:
参考:
{ "bool" : { "must" : { "constant_score" : { "filter" : { "match" : { "title" : { "query" : "java", "type" : "boolean" } } }, "boost" : 1.0 } }, "should" : [ { "constant_score" : { "filter" : { "term" : { "title" : "elasticsearch" } }, "boost" : 5.0 } }, { "term" : { "title" : "hadoop" } } ] } }
https://www.elastic.co/blog/better-query-execution-coming-elasticsearch-2-0
https://www.elastic.co/guide/en/elasticsearch/reference/2.0/breaking_20_java_api_changes.html
https://www.elastic.co/guide/cn/elasticsearch/guide/current/_filter_bucket.html
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。