1

我在弹性搜索中索引指标名称。度量名称的格式为foo.bar.baz.aux。这是我使用的索引。

{
    "index": {
        "analysis": {
            "analyzer": {
                "prefix-test-analyzer": {
                    "filter": "dotted",
                    "tokenizer": "prefix-test-tokenizer",
                    "type": "custom"
                }
            },
            "filter": {
                "dotted": {
                    "patterns": [
                        "([^.]+)"
                    ],
                    "type": "pattern_capture"
                }
            },
            "tokenizer": {
                "prefix-test-tokenizer": {
                    "delimiter": ".",
                    "type": "path_hierarchy"
                }
            }
        }
    }
}

{
    "metrics": {
        "_routing": {
            "required": true
        },
        "properties": {
            "tenantId": {
                "type": "string",
                "index": "not_analyzed"
            },
            "unit": {
                "type": "string",
                "index": "not_analyzed"
            },
            "metric_name": {
                "index_analyzer": "prefix-test-analyzer",
                "search_analyzer": "keyword",
                "type": "string"
            }
        }
    }
}

上述索引为度量名称创建了以下术语foo.bar.baz

foo
bar
baz
foo.bar
foo.bar.baz

如果我有一堆指标,如下所示

a.b.c.d.e
a.b.c.d
a.b.m.n
x.y.z

我必须编写一个查询来获取第 n 级令牌。在上面的例子中

for level = 0, I should get [a, x] 
for level = 1, with 'a' as first token I should get [b]
               with 'x' as first token I should get [y]  
for level = 2, with 'a.b' as first token I should get [c, m]

除了写术语聚合之外,我想不出任何其他方式。要找出 的 2 级标记a.b,这是我提出的查询。

time curl -XGET http://localhost:9200/metrics_alias/metrics/_search\?pretty\&routing\=12345 -d '{
      "size": 0,
      "query": {
        "term": {
            "tenantId": "12345"
        }
      },
      "aggs": {
          "metric_name_tokens": {
              "terms": {
                  "field" : "metric_name",
                  "include": "a[.]b[.][^.]*",
                  "execution_hint": "map",
                  "size": 0
              }
          }
      }
  }'

这将导致以下存储桶。我解析输出并从那里抓取 [c, m] 。

"buckets" : [ {
     "key" : "a.b.c",
     "doc_count" : 2
   }, {
     "key" : "a.b.m",
     "doc_count" : 1
 } ]

到目前为止,一切都很好。该查询适用于大多数租户(tenantId term上面的通知查询)。对于某些拥有大量数据(大约 1 百万)的租户,性能确实很慢。我猜所有的术语聚合都需要时间。

我想知道术语聚合是否是此类数据的正确选择,并且还在寻找其他可能的查询类型。

4

1 回答 1

2

一些建议:

  • 在查询部分的聚合级别“镜像”过滤器。因此,为了a.b.匹配,请使用以下内容作为查询并保留相同的 aggs 部分:
"bool": {
  "must": [
    {
      "term": {
        "tenantId": 123
      }
    },
    {
      "prefix": {
        "metric_name": {
          "value": "a.b."
        }
      }
    }
  ]
}

甚至使用regexp与聚合部分相同的正则表达式。这样,聚合将不得不评估更少的桶,因为到达聚合部分的文档会更少。你提到这regexp对你来说效果更好,我最初的猜测是它prefix会表现得更好。

  • "size": 0从聚合更改为"size": 100. 测试后你提到这没有任何区别
  • 删除"execution_hint": "map"并让 Elasticsearch 使用默认值。在测试之后,您提到默认execution_hint的性能要差得多。
  • 我唯一能想到的另一件事是通过在索引时移动它来减轻搜索时的压力。我的意思是:在索引时,在您自己的应用程序或您使用的任何索引方法中,以编程方式拆分要索引的文本(不是 ES 这样做)并将层次结构中的每个元素索引到单独的字段中。例如a.bin field2a.b.cinfield3等。这适用于同一个文件。然后,在搜索时,您会根据搜索文本的内容查看特定字段。然而,这整个想法需要在 ES 之外进行一些额外的工作。

从以上所有建议中,第一个影响最大:查询响应时间从 23 秒提高到 11 秒。

于 2016-07-19T21:40:33.667 回答