elasticsearch的重写机制

144 阅读2分钟

概念

在使用前缀查询(prefix)及通配符查询(wildcard)时,本质上讲都是对多个关键词的查询;在这个概念的基础上,elasticsearch对用户的查询进行了重写(例如将前缀查询优化为should的term查询)。

目的

保证查询的性能。

例子

假定索引中有以下数据:

curl -XPUT 'localhost:9200/clients/client/1' -d
	'{"id":"1", "name":"Joe"}'
	curl -XPUT 'localhost:9200/clients/client/2' -d
	'{"id":"2", "name":"Jane"}'
	curl -XPUT 'localhost:9200/clients/client/3' -d
	'{"id":"3", "name":"Jack"}'
	curl -XPUT 'localhost:9200/clients/client/4' -d
	'{"id":"4", "name":"Rob"}'
	curl -XPUT 'localhost:9200/clients/client/5' -d
	'{"id":"5", "name":"Jannet"}'

我们要找到name以J开头的文档,即name域中包含以J开头的term:

{
  "query": {
	"prefix": {
	  "carNo": {
		"value": "J"
	  }
	}
  }
}

优化:

{
  "query": {
	"prefix": {
	  "carNo": {
		"value": "J",
		"rewrite": "constant_score_boolean"
	  }
	}
  }
}

增加了rewrite查询,lucene会列举倒排索引中存在以J为前缀的关键词,并且每个词都构建出一个query对象,性能会有所提升:

{
  "query": {
    "constant_score": {
      "query": {
        "bool": {
          "should": [
            {
              "term": {
                "name": "jack"
              }
            },
            {
              "term": {
                "name": "jane"
              }
            },
            {
              "term": {
                "name": "joe"
              }
            }
          ]
        }
      }
    }
  }
}

查询重写的相关属性:

scoring_boolean:该重写方法将对应的关键词转换成布尔查询的布尔Should子句,它有可能是CPU密集型的(因为每个关键词都需要计算得分),而且如果关键词数量太多,则会超出布尔查询的限制,限制条件的上限是1024。与此同时,该类型的查询语句还保存计算的得分。布尔查询的默认数量限制可以通过修改elasticsearch.yml文件中的index.query.bool.max_clause_count属性值来修改。但始终要记住的是,产生的布尔查询子句越多,查询的性能越低。

constant_score_boolean:该重写方法与上面提到的scoring_boolean重写方法类似,但是CPU消耗要低很多,因为它不计算得分,每个关键词的得分就是查询的权重,默认是1,也可以通过权重属性来设置其它的值。与scoring_boolean重写方法类似,该方法也受到布尔查询数量的限制。

constant_score_filter:如Apache Lucene Javadocs中所述,该重写方法通过对前缀创建一个私有的过滤器,然后查询文档。(即把查询处理成过滤模式) 。对于匹配的文档,给定一个与查询权重一样的得分。该方法比scoring_boolean要快,特别是索引中匹配的文档或者与前缀匹配的关键词数量比较大时。

top_terms_N:该重写方法将对应的关键词转换成布尔查询的布尔Should子句,同时保存计算得分。只是与scoring_boolean不同点在于,它只保留前N个关键词,来避免触发布尔子句数量的上限。 top_terms_boost_N:该重写方法与top_terms_N类似,只是得分的计算只与权重有关,与查询词无关。