Search
URI Search
Profiling Queries
Profiling Aggregations
Profiling Considerations
multi search API 允许在同一API中执行多个搜索请求。它的端点(endpoint)是 _msearch
。
它的请求格式与 multi API 相似,结构如下(如果特定搜索最终重定向到另一个节点,则结构被特别优化以减少解析):
header\n
body\n
header\n
body\n
header 分包括要搜索的 index / indices ,可搜索的可选(mapping)types ,search_type, preference
和 routing
。 正文包括典型的搜索正文请求(包括query
, aggregations
, from
, size
等)。 这里是一个例子:
$ cat requests
{"index" : "test"}
{"query" : {"match_all" : {}}, "from" : 0, "size" : 10}
{"index" : "test", "search_type" : "dfs_query_then_fetch"}
{"query" : {"match_all" : {}}}
{}
{"query" : {"match_all" : {}}}
{"query" : {"match_all" : {}}}
{"search_type" : "dfs_query_then_fetch"}
{"query" : {"match_all" : {}}}
$ curl -XGET localhost:9200/_msearch --data-binary "@requests"; echo
注意,上面包括也被支持的空标题(也可以只是没有任何内容)的示例。
该响应返回一个响应数组,其中包括每个搜索请求的搜索响应和状态代码,与其在原始 multi search 请求中的顺序相匹配。 如果该特定搜索请求的完全失败,将返回具有错误消息和相应状态代码的对象,而不是实际的搜索响应。
端点还允许对URI中的 index/indices和 type/types 进行搜索,在这种情况下,它将被用作默认值,除非在标题中另有明确定义。 例如:
$ cat requests
{}
{"query" : {"match_all" : {}}, "from" : 0, "size" : 10}
{}
{"query" : {"match_all" : {}}}
{"index" : "test2"}
{"query" : {"match_all" : {}}}
$ curl -XGET localhost:9200/test/_msearch --data-binary @requests; echo
上面将针对没有定义索引的所有请求对 test 索引执行搜索,最后一个将针对 test2 索引执行。
可以以类似的方式设置 search_type 以全局地应用于所有搜索请求。
msearch 的 max_concurrent_searches 请求参数可用于控制 multi search api 将执行的并发搜索的最大数量。 此默认值基于数据节点的数量和默认搜索线程池大小。
Count API 允许轻松执行查询并获取该查询的匹配数。 它可以跨一个或多个索引并跨越一个或多个类型执行。 可以使用简单的查询字符串作为参数或使用在请求正文中定义的 Query DSL 来提供查询。 这里是一个例子:
PUT /twitter/tweet/1?refresh
{
"user": "kimchy"
}
GET /twitter/tweet/_count?q=user:kimchy
GET /twitter/tweet/_count
{
"query" : {
"term" : { "user" : "kimchy" }
}
}
注意
在正文中发送的查询必须嵌套在查询键中,与 Search API 相同
上面的两个例子都做同样的事情,这是从某个用户的 twitter 索引计数 tweets 的数量。 其结果是:
{
"count" : 1,
"_shards" : {
"total" : 5,
"successful" : 5,
"failed" : 0
}
}
查询是可选的,如果没有提供,它将使用 match_all 来计算所有的文档。
count API 可以应用于多个索引中的多个类型。
当使用查询参数q执行计数时,传递的查询是使用Lucene查询解析器的查询字符串。 还有其他可以传递的参数:
Name | Description |
---|---|
df |
在查询中未定义字段前缀时使用的默认字段。 |
analyzer |
分析查询字符串时使用的分析器名称。 |
default_operator |
要使用的默认运算符,可以是 AND 或 OR。 默认为 OR。 |
lenient |
如果设置为 true 将导致基于格式的失败(例如向数字字段提供文本)被忽略。 默认为 false。 |
lowercase_expanded_terms |
术语是否自动小写,默认为 true 。 |
analyze_wildcard |
是否分析通配符和前缀查询。 默认为false。 |
terminate_after |
每个分片的最大计数,到达时,查询执行将提前终止。 如果设置,响应将具有布尔字段 terminated_early 以指示查询执行是否实际已终止。 默认为无 terminate_after。 |
计数可以使用其身体内的 Query DSL 来表达应该执行的查询。 主体内容也可以作为名为 source 的 REST 参数传递。
HTTP GET 和 HTTP POST 都可以用于以主体执行计数。 由于并不是所有的客户端都支持带主体的 GET,因此也允许 POST。
计数操作在所有分片上广播。 每个 shard id group 选择一个副本并对其执行。 这意味着副本增加了计数的可伸缩性。
可以指定路由值(路由值的逗号分隔列表),以控制将对哪些分片执行计数请求。
validate API 允许用户验证一个可能复杂(expensive)的查询而不执行它。 我们将使用以下测试数据来解释_validate:
PUT twitter/tweet/_bulk?refresh
{"index":{"_id":1}}
{"user" : "kimchy", "post_date" : "2009-11-15T14:12:12", "message" : "trying out Elasticsearch"}
{"index":{"_id":2}}
{"user" : "kimchi", "post_date" : "2009-11-15T14:12:13", "message" : "My username is similar to @kimchy!"}
当发送一个有效查询时:
GET twitter/_validate/query?q=user:foo
响应包含有效:true:
{"valid":true,"_shards":{"total":1,"successful":1,"failed":0}}
当执行查询使用查询参数q时,传递的查询是使用Lucene查询解析器的查询字符串。 还有其他可以传递的参数:
Name | Description |
---|---|
df |
在查询中未定义字段前缀时使用的默认字段。 |
analyzer |
分析查询字符串时使用的分析器名称。 |
default_operator |
要使用的默认运算符,可以是 AND 或 OR。 默认为 OR。 |
lenient |
如果设置为 true 将导致基于格式的失败(例如向数字字段提供文本)被忽略。 默认为 false。 |
lowercase_expanded_terms |
术语是否自动小写,默认为 true 。 |
analyze_wildcard |
是否分析通配符和前缀查询。 默认为false。 |
查询也可以在请求主体中发送:
GET twitter/tweet/_validate/query
{
"query" : {
"bool" : {
"must" : {
"query_string" : {
"query" : "*:*"
}
},
"filter" : {
"term" : { "user" : "kimchy" }
}
}
}
}
注意
在正文中发送的查询必须嵌套在查询键中,与 Search API 相同。
如果查询无效,则返回信息中 valid
将为 false。 在这里,查询无效,因为 Elasticsearch 知道post_date字段应该是动态映射的日期,foo无法正确解析为日期:
GET twitter/tweet/_validate/query?q=post_date:foo
{"valid":false,"_shards":{"total":1,"successful":1,"failed":0}}
可以指定 explain 参数以获取有关查询失败原因的更详细信息:
GET twitter/tweet/_validate/query?q=post_date:foo&explain=true
响应是:
{
"valid" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"failed" : 0
},
"explanations" : [ {
"index" : "twitter",
"valid" : false,
"error" : "twitter/IAEc2nIXSSunQA_suI0MLw] QueryShardException[failed to create query:...failed to parse date field [foo]"
} ]
}
当查询有效时,explanations 默认为该查询的字符串表示形式。 将 rewrite 设置为 true 时,explanations 将更详细地显示将要执行的实际Lucene查询。
模糊查询(Fuzzy Queries):
GET twitter/tweet/_validate/query?rewrite=true
{
"query": {
"match": {
"user": {
"query": "kimchy",
"fuzziness": "auto"
}
}
}
}
响应:
{
"valid": true,
"_shards": {
"total": 1,
"successful": 1,
"failed": 0
},
"explanations": [
{
"index": "twitter",
"valid": true,
"explanation": "+user:kimchy +user:kimchi^0.75 #(ConstantScore(_type:tweet))^0.0"
}
]
}
相似度查询(More Like This):
GET twitter/tweet/_validate/query?rewrite=true
{
"query": {
"more_like_this": {
"like": {
"_id": "2"
},
"boost_terms": 1
}
}
}
响应:
{
"valid": true,
"_shards": {
"total": 1,
"successful": 1,
"failed": 0
},
"explanations": [
{
"index": "twitter",
"valid": true,
"explanation": "((user:terminator^3.71334 plot:future^2.763601 plot:human^2.8415773 plot:sarah^3.4193945 plot:kyle^3.8244398 plot:cyborg^3.9177752 plot:connor^4.040236 plot:reese^4.7133346 ... )~6) -ConstantScore(_uid:tweet#2)) #(ConstantScore(_type:tweet))^0.0"
}
]
}
警告
请求只在单个分片上执行,这是随机选择的。 查询的详细解释可以取决于哪个分片被命中,并且因此可以从一个请求到另一个请求而变化。
Explain API 计算查询和特定文档的分数说明。 这可以提供有用的反馈,无论文档是否匹配特定查询。
index 和 type 参数分别期望单个索引和单个类型。
完整查询示例:
GET /twitter/tweet/0/_explain
{
"query" : {
"match" : { "message" : "elasticsearch" }
}
}
这将产生以下结果:
{
"_index" : "twitter",
"_type" : "tweet",
"_id" : "0",
"matched" : true,
"explanation" : {
"value" : 1.55077,
"description" : "sum of:",
"details" : [ {
"value" : 1.55077,
"description" : "weight(message:elasticsearch in 0) [PerFieldSimilarity], result of:",
"details" : [ {
"value" : 1.55077,
"description" : "score(doc=0,freq=1.0 = termFreq=1.0\n), product of:",
"details" : [ {
"value" : 1.3862944,
"description" : "idf(docFreq=1, docCount=5)",
"details" : [ ]
}, {
"value" : 1.1186441,
"description" : "tfNorm, computed from:",
"details" : [
{ "value" : 1.0, "description" : "termFreq=1.0", "details" : [ ] },
{ "value" : 1.2, "description" : "parameter k1", "details" : [ ] },
{ "value" : 0.75, "description" : "parameter b", "details" : [ ] },
{ "value" : 5.4, "description" : "avgFieldLength", "details" : [ ] },
{ "value" : 4.0, "description" : "fieldLength", "details" : [ ] }
]
} ]
} ]
}, {
"value" : 0.0,
"description" : "match on required clause, product of:",
"details" : [ {
"value" : 0.0,
"description" : "# clause",
"details" : [ ]
}, {
"value" : 1.0,
"description" : "_type:tweet, product of:",
"details" : [
{ "value" : 1.0, "description" : "boost", "details" : [ ] },
{ "value" : 1.0, "description" : "queryNorm", "details" : [ ] }
]
} ]
} ]
}
}
还有一种更简单的通过 q 参数指定查询的方法。 然后解析指定的 q 参数值,就像使用 query_string 查询一样。 在api中的 q 参数的用法示例:
GET /twitter/tweet/0/_explain?q=message:search
这将产生与先前请求相同的结果。
所有的参数:
Name | Description |
---|---|
_source |
设置为true以检索所解释的文档的_source。 您还可以使用_source_include&_source_exclude检索文档的一部分(有关更多详细信息,请参阅Get API) |
stored_fields |
允许控制哪些存储字段作为文档说明的一部分返回。 |
routing |
在索引期间使用路由的情况下控制路由。 |
parent |
与设置 routing 参数的效果相同。 |
preference |
控制执行解释的分片。 |
source |
允许请求的数据放在url的查询字符串中。 |
q |
查询字符串(映射到 query_string 查询)。 |
df |
在查询中未定义字段前缀时使用的默认字段。 默认为_all字段。 |
analyzer |
分析查询字符串时使用的分析器名称。 默认为_all字段的分析器。 |
analyze_wildcard |
是否分析通配符和前缀查询。 默认为false。 |
lowercase_expanded_terms |
术语是否自动小写,默认为 true 。 |
lenient |
如果设置为 true 将导致基于格式的失败(例如向数字字段提供文本)被忽略。 默认为 false。 |
default_operator |
要使用的默认运算符,可以是AND或OR。 默认为OR。 |
Profiling Queries
query 部分包含了Lucene在特定分片上执行的查询树的详细选择,此查询树的总体结构将类似于您的原始Elasticsearch查询,但有还是有点区别,它也将使用类似但不总是相同的命名。 使用我们以前的匹配查询示例,让我们分析查询部分:
"query": [
{ "type": "BooleanQuery", "description": "message:message message:number", "time": "1.873811000ms", "breakdown": {...}, (1) "children": [ { "type": "TermQuery", "description": "message:message", "time": "0.3919430000ms", "breakdown": {...} }, { "type": "TermQuery", "description": "message:number", "time": "0.2106820000ms", "breakdown": {...} } ] } ]
(1) 为了方便学习使用的省略号
基于配置文件结构,我们可以看到,我们的 match 查询被Lucene重写成一个BooleanQuery,带有两个子句(两者都持有一个TermQuery)“type”字段显示Lucene类名,常常也是与ES一样的,“description”字段显示查询的Lucene描述文本并可用于帮助区分查询的各个部分(例如,“message:search”和“message:test”都是TermQuery的,否则会显示相同的内容。
“time”字段显示该查询时间 -15ms来执行整个BooleanQuery。 记录的时间包括所有的子类。
“breakdown”字段将提供花费时间的详细统计信息,我们会在下面看到。 最后,“children”数组列出可能存在的任何子查询。 因为我们搜索了两个值(“search test”),我们的BooleanQuery保存两个子项TermQueries。 它们具有相同的信息(type,time,分类等)。 childern可以还有自己的childern(父子、嵌套mapping)。
timing breakdown(时间分类)
“breakdown”组件列出了有关低级Lucene执行的详细时序统计信息:
"breakdown": { "score": 51306, "score_count": 4, "build_scorer": 2935582, "build_scorer_count": 1, "match": 0, "match_count": 0, "create_weight": 919297, "create_weight_count": 1, "next_doc": 53876, "next_doc_count": 5, "advance": 0, "advance_count": 0 }
时序以纳秒为单位列出,并且根本没有标准化。
统计的含义如下:
全部参数
create_weight:Lucene中的Query必须能够跨多个IndexSearcher重用(认为它是针对特定Lucene Index执行搜索的引擎)这使得Lucene在一个棘手的地方,因为许多查询需要累积与正在使用的索引相关联的临时state/statistices 信息,但是Query 结构要求它必须是不可变的。为了解决这个问题,Lucene要求每个查询生成一个Weight对象,该对象充当临时上下文对象,用于保存与此特定(IndexSearcher,Query)元组相关联的状态。 权重度量显示此过程需要多长时间
build_scorer: 此参数显示为查询构建Scorer所需的时间。 Scorer是迭代匹配文档生成每个文档的分数(例如,“foo”与文档匹配得多好)的机制。注意,这会记录生成Scorer对象所需的时间,而不会实际记录文档。 一些查询具有更快或更慢的Scorer初始化,这取决于优化,复杂性等。这也可以示出与缓存相关联的定时,如果启用 and/or 查询
next_doc: Lucene方法next_doc返回与查询匹配的下一个文档的文档ID。 此统计信息显示确定哪个文档是下一个匹配所需的时间,这个过程根据查询的性质有很大的不同。
Next_doc是advance()的一种特殊形式,对于Lucene中的许多查询都更方便。 它等价于advance(docId()+ 1)
advance: advance是next_doc的“lower level”版本:它具有找到下一个匹配文档的相同目的,但是需要调用查询来执行额外的任务,例如识别和移动过去的跳过等。然而,不是所有的查询都可以使用next_doc ,所以advance也为这些查询计时。 连接(例如布尔值中的must子句)是提前的典型消费者
matches:某些查询(例如词组查询)使用“two phase”过程匹配文档。 首先,文档“近似”匹配,并且如果大致匹配,则用更严格(且昂贵)的过程第二次检查该文档。 第二阶段验证是 matches 统计量度量。 例如,短语查询首先大致通过确保短语中的所有词语都存在于文档中来检查文档。 如果所有术语都存在,则其然后执行第二阶段验证以确保术语是为了形成短语,这比仅仅检查术语的存在相对更贵。 由于此两阶段过程仅由少量查询使用,因此 metric 统计数据通常为零
score :这记录了通过它的Scorer对特定文档记分所花费的时间
*_count: 记录特定方法的调用数。 例如,“next_doc_count”:2,表示在两个不同的文档上调用nextDoc()方法。 这可以用于通过比较不同查询组件之间的计数来帮助判断选择性查询的方式。
collectors Section
响应的Collectors部分显示高级执行详细信息。 Lucene通过定义一个“Collector”来工作,它负责协调匹配文档的遍历,评分和收集。 收集器也是单个查询如何记录聚合结果,执行未范围化的“全局”查询,执行查询后过滤器等。
看看例子:
"collector": [ { "name": "SimpleTopScoreDocCollector", "reason": "search_top_hits", "time": "0.06989100000ms" } ]
我们看到一个名为SimpleTopScoreDocCollector的收集器。 这是Elasticsearch使用的默认“评分和排序”收集器。“reason”字段试图给出类名的简单的描述。 “time”类似于查询树中的时间:包含所有子项的时间。 同样,children列出所有子收集
应该注意,收集器时间与查询时间无关。 它们是独立计算,组合和规范的! 由于Lucene的执行性质,不可能将时间从收集器“合并”到查询部分,因此它们以单独的部分显示。
作为参考,各种收集器的原因是:
search_sorted:文档评分和排序的收集器。 这是最常见的收集器,将在最简单的搜索中看到
search_count: 仅计算与查询匹配的文档数,但不会获取源的收集器。 这在指定size:0时可见
search_terminate_after_count: 已找到在找到n个匹配文档后终止搜索执行的收集器。 当指定了terminate_after_count查询参数时,会看到这一点
search_min_score: 仅返回具有大于n的分数的匹配文档的收集器。 这在指定顶级参数min_score时可见。
search_multi: 包装其他收集器的收集器。 当搜索,聚合,全局agg和post_filters的组合在单个搜索中组合时,可以看到这一点。
search_timeout: 在指定时间段后停止执行的收集器。 这在指定超时顶级参数时可见。
aggregation: Elasticsearch用于针对查询范围运行聚合的收集器。 单个聚合收集器用于收集所有聚合的文档,因此您将看到名称中的聚合列表。
global_aggregation:对全局查询作用域而不是指定的查询执行聚合的收集器。 因为全局范围必须不同于执行的查询,
rewrite Section
Lucene中的所有查询都经历了“重写”过程。 查询(及其子查询)可以重写一次或多次,并且该过程继续,直到查询停止改变。此过程允许Lucene执行优化,例如删除冗余子句,替换一个查询以获得更有效的执行路径等。例如,Boolean→Boolean→TermQuery可以重写为TermQuery,因为在这种情况下所有布尔值都是不必要的 。
重写过程很复杂,难以显示,因为查询可能会发生巨大变化。 不是显示中间结果,而是将总重写时间简单地显示为值(以纳秒为单位)。此值是累积的,包含正在重写的所有查询的总时间。
更复杂例子
为了演示稍微更复杂的查询和相关联的结果,我们可以对以下查询进行概要分析:
curl -XPOST 'slave1:9200/test/_search?pretty' -d ' { "profile": true, "query": { "term": { "message": { "value": "search" } } }, "aggs": { "non_global_term": { "terms": { "field": "agg" }, "aggs": { "second_term": { "terms": { "field": "sub_agg" } } } }, "another_agg": { "cardinality": { "field": "aggB" } }, "global_agg": { "global": {}, "aggs": { "my_agg2": { "terms": { "field": "globalAgg" } } } } }, "post_filter": { "term": { "my_field": "foo" } } }
此示例具有:
响应:
{ "profile": { "shards": [ { "id": "[P6-vulHtQRWuD4YnubWb7A][test][0]", "searches": [ { "query": [ { "type": "TermQuery", "description": "my_field:foo", "time": "0.4094560000ms", "breakdown": { "score": 0, "score_count": 1, "next_doc": 0, "next_doc_count": 2, "match": 0, "match_count": 0, "create_weight": 31584, "create_weight_count": 1, "build_scorer": 377872, "build_scorer_count": 1, "advance": 0, "advance_count": 0 } }, { "type": "TermQuery", "description": "message:search", "time": "0.3037020000ms", "breakdown": { "score": 0, "score_count": 1, "next_doc": 5936, "next_doc_count": 2, "match": 0, "match_count": 0, "create_weight": 185215, "create_weight_count": 1, "build_scorer": 112551, "build_scorer_count": 1, "advance": 0, "advance_count": 0 } } ], "rewrite_time": 7208, "collector": [ { "name": "MultiCollector", "reason": "search_multi", "time": "1.378943000ms", "children": [ { "name": "FilteredCollector", "reason": "search_post_filter", "time": "0.4036590000ms", "children": [ { "name": "SimpleTopScoreDocCollector", "reason": "search_top_hits", "time": "0.006391000000ms" } ] }, { "name": "BucketCollector: [[non_global_term, another_agg]]", "reason": "aggregation", "time": "0.9546020000ms" } ] } ] }, { "query": [ { "type": "MatchAllDocsQuery", "description": ":", "time": "0.04829300000ms", "breakdown": { "score": 0, "score_count": 1, "next_doc": 3672, "next_doc_count": 2, "match": 0, "match_count": 0, "create_weight": 6311, "create_weight_count": 1, "build_scorer": 38310, "build_scorer_count": 1, "advance": 0, "advance_count": 0 } } ], "rewrite_time": 1067, "collector": [ { "name": "GlobalAggregator: [global_agg]", "reason": "aggregation_global", "time": "0.1226310000ms" } ] } ] } ] } }
你可以看到,输出是从前的显着冗长。 查询的所有主要部分都表示为: 1、第一个TermQuery(message:search)表示主要术语查询 2、第二个TermQuery(my_field:foo)表示post_filter查询 3、有一个MatchAllDocsQuery(:)查询,作为第二个不同的搜索执行。 这不是用户指定的查询的一部分,但是由全局聚合自动生成以提供全局查询作用域
Collector树是相当简单的,显示单个MultiCollector如何包装一个FilteredCollector来执行post_filter(反过来包装正常评分SimpleCollector),一个BucketCollector来运行所有作用域聚合。在MatchAll搜索中,有一个GlobalAggregator运行全局聚合。
理解多术语查询输出
需要对MultiTermQuery查询类进行特别说明。 这包括通配符,正则表达式和模糊查询。 这些查询发出非常详细的响应,并且不过度结构化。基本上,这些查询基于每个段重写自身。 如果你想象通配符查询b *,它技术上可以匹配任何以字母“b”开头的。 它不可能枚举所有可能的组合,因此Lucene在被评估的段的上下文中重写查询。例如。 一个段可以包含标记[bar,baz],因此查询重写为“bar”和“baz”的BooleanQuery组合。另一个细分受众群可能只有[bakery],因此查询将重写为单个TermQuery for“bakery”。
由于这种动态的,每个段的重写,树结构变得混乱,并且不再遵循清晰的“lineage”,显示一个查询如何重写到下一个。 目前,我们没有实现 表示抱歉,并建议您折叠查询的children的细节,如果它太混乱了。 幸运的是,所有的时序统计都是正确的,只是不是响应中的物理布局,所以只要分析顶层的MultiTermQuery就可以忽略它的子节点,如果你发现细节太难解释。
希望这将在未来的迭代中固定,但它是一个棘手的问题,要解决,仍在进行中....)
Profiling Aggregations
aggregations Section
聚合部分包含由特定分片执行的聚合树的详细时序。 此聚合树的总体结构将类似于您的原始Elasticsearch请求。 让我们考虑以下示例聚合请求:
curl -XPOST 'slave1:9200/house-prices/_search?pretty' -d '{
"profile": true, "size": 0, "aggs": { "property_type": { "terms": { "field": "propertyType" }, "aggs": { "avg_price": { "avg": { "field": "price" } } } } } }
输出
"aggregations": [ { "type": "org.elasticsearch.search.aggregations.bucket.terms.GlobalOrdinalsStringTermsAggregator", "description": "property_type", "time": "4280.456978ms", "breakdown": { "reduce": 0, "reduce_count": 0, "build_aggregation": 49765, "build_aggregation_count": 300, "initialise": 52785, "initialize_count": 300, "collect": 3155490036, "collect_count": 1800 }, "children": [ { "type": "org.elasticsearch.search.aggregations.metrics.avg.AvgAggregator", "description": "avg_price", "time": "1124.864392ms", "breakdown": { "reduce": 0, "reduce_count": 0, "build_aggregation": 1394, "build_aggregation_count": 150, "initialise": 2883, "initialize_count": 150, "collect": 1124860115, "collect_count": 900 } } ] } ]
从概要文件结构中,我们可以看到我们的property_type术语聚合,它由GlobalOrdinalsStringTermsAggregator类和由AvgAggregator类在内部表示的子聚合器avg_price内部表示。类型字段显示内部用于表示聚合的类。 描述字段显示聚合的名称。
“time”字段显示整个聚合需要大约4秒的时间来执行。 记录的时间包括所有的children。
“breakdown”字段将提供有关时间花费的详细统计信息,我们稍后将介绍。 最后,“children”数组列出可能存在的任何子聚合。 因为我们有一个avg_price聚合作为property_type聚合的子聚合,我们看到它被列为property_type聚合的子节点。 这两个聚合输出具有相同的信息(type,time,breakdown ..)。 children可以有自己的children。
timing Breakdown
“breakdown”组件列出了有关低级Lucene执行的详细时序统计信息:
"breakdown": { "reduce": 0, "reduce_count": 0, "build_aggregation": 49765, "build_aggregation_count": 300, "initialise": 52785, "initialize_count": 300, "collect": 3155490036, "collect_count": 1800 }
时序以纳秒为单位列出,并且根本没有标准化。 所有关于整体时间的注意事项适用于此。
分解的目的是给你一个感觉A)什么机械在Elasticsearch实际上的时间,和B)各种组件之间的时间差异的大小。 像总时间,分解包括所有children时间。
统计的含义如下:
initialise:在开始收集文档之前创建和初始化聚合所需的时间。
collect:这表示在聚集的收集阶段中花费的累积时间。 这是将匹配文档传递到聚合的地方,并且基于文档中包含的信息更新聚合器的状态。
build_aggregation:这表示在文档集合完成之后,用于创建准备好传递回节点的聚合的分片级结果所花费的时间。 reduce:这当前未使用,将始终报告为0.当前的聚合分析仅次于聚合执行的分片级别部分。 *_count:记录特定方法的调用数。 例如,“collect_count”:2,表示在两个不同的文档上调用了collect()方法。
Profiling Considerations
Performance Notes(性能说明)
和任何分析器一样,Profile API引入了一个不可忽略的搜索执行开销。 插入低级方法调用(如collect,advance和next_doc)的行为可能相当费时,因为这些方法在紧密循环中调用。 因此,默认情况下不应在生产设置中启用分析,并且不应与非分析查询时间进行比较。 分析只是一个诊断工具。
还有一些情况下,特殊的Lucene优化被禁用,因为它们不适合进行概要分析。 这可能导致一些查询报告比他们的非配置文件对应的更大的相对时间,但是通常不应该与配置文件查询中的其他组件相比。
局限性
* 分析统计信息当前不可用,突出显示,dfs_query_then_fetch
* 聚合的缩减阶段的分析当前不可用 * Profiler 仍然是高度实验性的。 Profiler 是对 Lucene中从未设计过以这种方式暴露的部分进行检测,因此所有结果都应被视为尽力提供详细的诊断。 我们希望随着时间的推移改善这一点。 如果你发现明显错误的数字,奇怪的查询结构或其他错误,请提出!
Percolator
Percolate Query
Percolate 查询可以用于匹配存储在索引中的查询。 Percolate查询本身包含将用作与存储的查询匹配的查询的文档。
示例:
创建两个映射的索引:
PUT /my-index { "mappings": { "doctype": { "properties": { "message": { "type": "text" } } }, "queries": { "properties": { "query": { "type": "percolator" } } } } }
doctype 映射是用于预处理 Percolator 查询中定义的文档之前,它被索引到临时索引中的映射。
queries 映射是用于索引查询文档的映射。 查询字段将保存表示实际Elasticsearch查询的json对象。queries 字段已配置为使用percolator field type。 此字段类型理解查询dsl并以这样的方式存储查询,以便稍后可以将其用于匹配在 percolate 查询上定义的文档。
在过滤器中注册查询:
PUT /my-index/queries/1?refresh { "query" : { "match" : { "message" : "bonsai tree" } } }
将文档与已注册的过滤器查询匹配:
GET /my-index/_search { "query" : { "percolate" : { "field" : "query", "document_type" : "doctype", "document" : { "message" : "A new bonsai tree in the office" } } } }
上面请求将产生以下响应:
{ "took": 13, "timed_out": false, "_shards": { "total": 5, "successful": 5, "failed": 0 }, "hits": { "total": 1, "max_score": 0.5716521, "hits": [ { (1) "_index": "my-index", "_type": "queries", "_id": "1", "_score": 0.5716521, "_source": { "query": { "match": { "message": "bonsai tree" } } } } ] } }
(1)ID为1的查询与我们的文档匹配。
过滤器文档时需要以下参数:
field:类型 percolator 的字段,并保存索引查询。 这是必需的参数。
document_type: 过滤器文档type/mapping 映射,这是必需的参数
document:文档的来源
代替指定正在被执行的文档的源,还可以从已经存储的文档中检索源。 过滤器查询然后将在内部执行获取请求以获取该文档。
在这种情况下,文档参数可以用以下参数替换:
index:文档所在的索引。这是必需的参数。 type :文档所在的类型。这是必需的参数。 id:文档所在的id。这是必需的参数。 routing:可选,用于获取文档以进行过滤的路由。 preference:优先使用过滤获取文档。 version:提取的文档的预期版本。
过滤已有的文档 为了过滤新索引的文档,可以使用过滤查询。 基于来自索引请求的响应,_id和其他元信息可以用于立即过滤新添加的文档。
eg: 基于前面的例子。
索引要过滤的文档:
PUT /my-index/message/1 { "message" : "A new bonsai tree in the office" }
索引请求 { "_index": "my-index", "_type": "message", "_id": "1", "_version": 1, "_shards": { "total": 2, "successful": 1, "failed": 0 }, "created": true, "result": "created" }
过滤已有文档 使用索引请求 去查询 new的请求
GET /my-index/_search { "query" : { "percolate" : { "field": "query", "document_type" : "doctype", "index" : "my-index", "type" : "message", "id" : "1", "version" : 1 (1) } } }
版本是可选的,但在某些情况下有用。 然后,我们可以确保我们试图过滤我们刚刚建立索引的文档。在我们建立索引之后可以进行更改,如果是这样,那么搜索请求将失败,并出现版本冲突错误。
返回的搜索响应与上一个示例中的相同。
过滤查询和高示显示
过滤查询在处理突出显示时以特殊方式处理。 查询命中用于突出显示在 percolate 查询中提供的文档。 而定期突出显示在搜索请求中的查询用于突出点击。
eg: 此示例是用第一个示例的映射。
第一个查询 PUT /my-index/queries/1?refresh { "query" : { "match" : { "message" : "brown fox" } } }
第二个查询
PUT /my-index/queries/2?refresh { "query" : { "match" : { "message" : "lazy dog" } } }
执行具有过滤查询和高示显示的搜索请求:
GET /my-index/_search { "query" : { "percolate" : { "field": "query", "document_type" : "doctype", "document" : { "message" : "The quick brown fox jumps over the lazy dog" } } }, "highlight": { "fields": { "message": {} } } }
这将产生以下响应。
{ "took": 7, "timed_out": false, "_shards": { "total": 5, "successful": 5, "failed": 0 }, "hits": { "total": 2, "max_score": 0.5446649, "hits": [ { "_index": "my-index", "_type": "queries", "_id": "2", "_score": 0.5446649, "_source": { "query": { "match": { "message": "lazy dog" } } }, "highlight": { "message": [ "The quick brown fox jumps over the <em>lazy</em> <em>dog</em>" ] } }, { "_index": "my-index", "_type": "queries", "_id": "1", "_score": 0.5446649, "_source": { "query": { "match": { "message": "brown fox" } } }, "highlight": { "message": [ "The quick <em>brown</em> <em>fox</em> jumps over the lazy dog" ] } } ] } }
代替在搜索请求中的查询高示显示渗滤器命中,渗滤器查询突出显示在过滤查询中定义的文档。
如果工作的当将文档索引到配置了 percolator field type 映射的索引时,文档的查询部分将被解析为Lucene查询并存储到Lucene索引中。 查询的二进制表示被存储,而且查询的项被分析并存储到索引字段中。
在搜索时,请求中指定的文档将被解析为Lucene文档,并存储在内存中的临时Lucene索引中。 这个内存索引只能保存这一个文档,并为此进行了优化。 此后,基于存储器内索引中的项来构建特殊查询,该项基于它们的索引查询项来选择候选过滤器查询。 然后,如果这些查询实际匹配,则由内存索引评估这些查询。
候选渗滤器查询匹配的选择在执行过滤查询期间是重要的性能优化, 因为它可以显着减少存储器内索引需要评估的候选匹配的数量。过滤查询可以执行此操作的原因是因为在过滤器查询的索引期间,
查询术语正在被提取并用渗滤器查询索引。 不幸的是,过滤器不能从所有查询(例如通配符或geo_shape查询)中提取术语,因此在某些情况下,渗滤器不能进行选择优化(例如,如果一个不支持的查询在 布尔查询或不支持的查询是渗透文档中的唯一查询)。 这些查询由过滤器标记,可以通过运行以下搜索找到:
GET /_search { "query": { "term" : { "query.extraction_result" : "failed" } } }
Field States API
字段数据 API 允许在不执行搜索的情况下查找字段的统计属性,但查找Lucene索引中本机可用的度量。 这可以用来探索一个你不确定的数据集。
例如,这允许基于值的man/min范围创建具有有意义间隔的直方图聚集。
全部索引
curl -XGET "http://localhost:9200/_field_stats?fields=rating"
具体索引 curl -XGET "http://localhost:9200/index1,index2/_field_stats?fields=rating"
请求的选项
fields:要计算统计信息的字段列表。 字段名称支持通配符符号。 例如,使用text_ *将导致返回与表达式匹配的所有字段。
level:定义是否应在每个索引级别或群集级别返回字段统计信息。 有效值为索引和集群(默认)。
或者,也可以在请求主体中定义fields选项:
curl -XPOST "http://localhost:9200/_field_stats?level=indices" -d '{ "fields" : ["rating"] }'
字段统计数据
字段stats API支持基于字符串,基于数字和基于日期的字段,并且可以为每个字段返回以下统计信息:
max_doc:文档总数 doc_count:具有此字段至少一个术语的文档数,如果此度量在一个或多个分片上不可用,则为-1。 density:此字段至少有一个值的文档的百分比。 这是一个导出的统计信息,基于max_doc和doc_count。 sum_doc_freq:此字段中每个术语的文档频率的总和,如果此测量在一个或多个分片上不可用,则为-1。 文档频率是包含特定字词的文档数。 sum_total_term_freq:所有文档中此字段中所有术语的术语频率之和,如果此度量在一个或多个分片上不可用,则为-1。 术语频率是术语在特定文档和字段中出现的总数。
is_searchable 如果字段的任何实例可搜索,则为true,否则为false。 is_aggregatable 如果字段的任何实例是可聚合的,则为True,否则为false。
min_value 字段中的最小值。 min_value_as_string 字段中的最低值以可显示的形式表示。 所有字段,但字符串字段返回此。 (因为字符串字段,表示已经作为字符串的值) max_value 字段中的最高值。 max_value_as_string 字段中的最高值以可显示的形式表示。 所有字段,但字符串字段返回此。 (因为字符串字段,表示已经作为字符串的值)
集群级别字段数据的例子
请求 curl -XGET "http://localhost:9200/_field_stats?fields=rating,answer_count,creation_date,display_name"
响应 { "_shards": { "total": 1, "successful": 1, "failed": 0 }, "indices": { "_all": { (1) "fields": { "creation_date": { "max_doc": 1326564, "doc_count": 564633, "density": 42, "sum_doc_freq": 2258532, "sum_total_term_freq": -1, "min_value": "2008-08-01T16:37:51.513Z", "max_value": "2013-06-02T03:23:11.593Z", "is_searchable": "true", "is_aggregatable": "true" }, "display_name": { "max_doc": 1326564, "doc_count": 126741, "density": 9, "sum_doc_freq": 166535, "sum_total_term_freq": 166616, "min_value": "0", "max_value": "???", "is_searchable": "true", "is_aggregatable": "false" }, "answer_count": { "max_doc": 1326564, "doc_count": 139885, "density": 10, "sum_doc_freq": 559540, "sum_total_term_freq": -1, "min_value": 0, "max_value": 160, "is_searchable": "true", "is_aggregatable": "true" }, "rating": { "max_doc": 1326564, "doc_count": 437892, "density": 33, "sum_doc_freq": 1751568, "sum_total_term_freq": -1, "min_value": -14, "max_value": 1277, "is_searchable": "true", "is_aggregatable": "true" } } } } }
(1)_all键表示它包含集群中所有索引的字段统计信息。
当使用集群级别字段统计时,如果在具有不兼容类型的不同索引中使用相同的字段,则可能存在冲突。 例如,long类型的字段与float或string类型的字段不兼容。 如果出现一个或多个冲突,则会将名为冲突的节添加到响应中。 它包含所有具有冲突的字段和不兼容的原因。
{ "_shards": { "total": 1, "successful": 1, "failed": 0 }, "indices": { "_all": { "fields": { "creation_date": { "max_doc": 1326564, "doc_count": 564633, "density": 42, "sum_doc_freq": 2258532, "sum_total_term_freq": -1, "min_value": "2008-08-01T16:37:51.513Z", "max_value": "2013-06-02T03:23:11.593Z", "is_searchable": "true", "is_aggregatable": "true" } } } }, "conflicts": { "field_name_in_conflict1": "reason1", "field_name_in_conflict2": "reason2" } }
索引级别字段例子
请求 curl -XGET "http://localhost:9200/_field_stats?fields=rating,answer_count,creation_date,display_name&level=indices"
响应:
{ "_shards": { "total": 1, "successful": 1, "failed": 0 }, "indices": { "stack": { (1) "fields": { "creation_date": { "max_doc": 1326564, "doc_count": 564633, "density": 42, "sum_doc_freq": 2258532, "sum_total_term_freq": -1, "min_value": "2008-08-01T16:37:51.513Z", "max_value": "2013-06-02T03:23:11.593Z", "is_searchable": "true", "is_aggregatable": "true" }, "display_name": { "max_doc": 1326564, "doc_count": 126741, "density": 9, "sum_doc_freq": 166535, "sum_total_term_freq": 166616, "min_value": "0", "max_value": "???", "is_searchable": "true", "is_aggregatable": "false" }, "answer_count": { "max_doc": 1326564, "doc_count": 139885, "density": 10, "sum_doc_freq": 559540, "sum_total_term_freq": -1, "min_value": 0, "max_value": 160, "is_searchable": "true", "is_aggregatable": "true" }, "rating": { "max_doc": 1326564, "doc_count": 437892, "density": 33, "sum_doc_freq": 1751568, "sum_total_term_freq": -1, "min_value": -14, "max_value": 1277, "is_searchable": "true", "is_aggregatable": "true" } } } } }
stack 键意味着它包含 stack 索引的所有字段统计信息。
字段数据索引的约束
字段统计信息索引约束允许省略与约束不匹配的索引的所有字段统计信息。 索引约束可以基于min_value和max_value统计量排除索引的字段统计信息。 此选项仅在level选项设置为indices时有用。
例如,索引约束可用于在基于时间的情况下找出数据的特定属性的最小值和最大值。
以下请求仅返回2014年创建的问题的索引的answer_count属性的字段统计信息:
curl -XPOST "http://localhost:9200/_field_stats?level=indices" -d '{ "fields" : ["answer_count"] (1) "index_constraints" : { (2) "creation_date" : { (3) "max_value" : { (4) "gte" : "2014-01-01T00:00:00.000Z" }, "min_value" : {(5) "lt" : "2015-01-01T00:00:00.000Z" } } } }'
(1)计算和返回字段统计信息的字段。 (2)设置索引约束。 请注意,可以为未在fields选项中定义的字段定义索引约束。 (3)字段creation_date的索引约束。 (4)字段统计信息的max_value和min_value属性的索引约束。 (5)对于字段,可以在min_value统计量,max_value统计量或两者上定义索引约束。每个索引约束支持以下比较: gte:大于或等于 gt: 大于 lte :小于或等于 lt :小于
字段统计信息日期字段的索引约束可选地接受格式选项,用于解析约束的值。 如果缺少,则使用字段映射中配置的格式。
curl -XPOST "http://localhost:9200/_field_stats?level=indices" -d '{ "fields" : ["answer_count"] "index_constraints" : { "creation_date" : { "max_value" : { "gte" : "2014-01-01", "format" : "date_optional_time" (1) }, "min_value" : { "lt" : "2015-01-01", "format" : "date_optional_time" } } } }'
自定义日期格式