gpt4 book ai didi

elasticsearch - 如何使用include和regex正确查询elasticsearch中术语聚合值的内部?

转载 作者:行者123 更新时间:2023-12-03 18:57:25 25 4
gpt4 key购买 nike

您如何有效地过滤/搜索聚合结果?
假设您在 Elasticsearch 中有 100 万个文档。在这些文档中,您有一个 multi_field (keyword, text) tags :

{
...
tags: ['Race', 'Racing', 'Mountain Bike', 'Horizontal'],
...
},
{
...
tags: ['Tracey Chapman', 'Silverfish', 'Blue'],
...
},
{
...
tags: ['Surfing', 'Race', 'Disgrace'],
...
},
您可以将这些值用作过滤器(方面),针对查询仅提取包含此标签的文档:
...
"filter": [
{
"terms": {
"tags": [
"Race"
]
}
},
...
]
但是您希望用户能够查询可能的标签过滤器。所以如果用户输入, race返回应该显示(来自上一个示例), ['Race', 'Tracey Chapman', 'Disgrace'] .这样,用户就可以查询要使用的过滤器。为了实现这一点,我不得不使用聚合:
{
"aggs": {
"topics": {
"terms": {
"field": "tags",
"include": ".*[Rr][Aa][Cc][Ee].*", // I have to dynamically form this
"size": 6
}
}
},
"size": 0
}
这正是我所需要的!但它很慢,非常慢。我试过添加 execution_hint,它对我没有帮助。
您可能会想,“只需在聚合之前使用查询!”但问题是它会提取该查询中所有文档的所有值。这意味着,您可以显示完全不相关的标签。如果我查询 race在聚合之前,并且没有使用包含正则表达式,我最终会得到所有其他值,例如 'Horizontal', etc...如何重写此聚合以更快地工作?有没有更好的方法来写这个?我真的必须为值创建一个单独的索引吗? (悲伤的脸)这似乎是一个常见问题,但通过文档和谷歌搜索没有找到答案。

最佳答案

您当然不需要单独的索引仅用于值...
这是我的看法:

  • 您对正则表达式所做的基本上是tokenizer 应该做的。 -- 即构建子字符串(或 N-grams )以便以后可以定位它们。
    这意味着关键字 Race将需要被标记为 n-gram ["rac", "race", "ace"] . (少于 3 个字符实际上没有意义——大多数自动完成库选择忽略少于 3 个字符,因为可能的匹配膨胀太快。)

  • Elasticsearch 提供了 N-gram tokenizer但我们需要增加名为 max_ngram_diff 的默认索引级别设置从 1 到(任意)10,因为我们想要捕获尽可能多的 ngrams:
    PUT tagindex
    {
    "settings": {
    "index": {
    "max_ngram_diff": 10
    },
    "analysis": {
    "analyzer": {
    "my_ngrams_analyzer": {
    "tokenizer": "my_ngrams",
    "filter": [ "lowercase" ]
    }
    },
    "tokenizer": {
    "my_ngrams": {
    "type": "ngram",
    "min_gram": 3,
    "max_gram": 10,
    "token_chars": [ "letter", "digit" ]
    }
    }
    }
    },
    { "mappings": ... } --> see below
    }
  • 当您的 tags字段是关键字列表,根本不可能在该字段上聚合 没有 求助于include选项可以是完全匹配或正则表达式(您已经在使用)。现在,我们不能保证完全匹配,但我们也不想正则表达式!所以这就是为什么我们需要使用 nested list这将 分别对待每个标签 .

  • 现在,嵌套列表应该包含对象,所以
    {
    "tags": ["Race", "Racing", "Mountain Bike", "Horizontal"]
    }
    将需要转换为
    {
    "tags": [
    { "tag": "Race" },
    { "tag": "Racing" },
    { "tag": "Mountain Bike" },
    { "tag": "Horizontal" }
    ]
    }
    之后我们将继续处理 multi field映射,保持原始标签不变,但也添加了 .tokenized要搜索的字段和 .keyword要聚合的字段:
      "index": { ... },
    "analysis": { ... },
    "mappings": {
    "properties": {
    "tags": {
    "type": "nested",
    "properties": {
    "tag": {
    "type": "text",
    "fields": {
    "tokenized": {
    "type": "text",
    "analyzer": "my_ngrams_analyzer"
    },
    "keyword": {
    "type": "keyword"
    }
    }
    }
    }
    }
    }
    }
    然后我们将添加我们调整后的标签文档:
    POST tagindex/_doc
    {"tags":[{"tag":"Race"},{"tag":"Racing"},{"tag":"Mountain Bike"},{"tag":"Horizontal"}]}

    POST tagindex/_doc
    {"tags":[{"tag":"Tracey Chapman"},{"tag":"Silverfish"},{"tag":"Blue"}]}

    POST tagindex/_doc
    {"tags":[{"tag":"Surfing"},{"tag":"Race"},{"tag":"Disgrace"}]}
    并申请 nested filter terms聚合:
    GET tagindex/_search
    {
    "aggs": {
    "topics_parent": {
    "nested": {
    "path": "tags"
    },
    "aggs": {
    "topics": {
    "filter": {
    "term": {
    "tags.tag.tokenized": "race"
    }
    },
    "aggs": {
    "topics": {
    "terms": {
    "field": "tags.tag.keyword",
    "size": 100
    }
    }
    }
    }
    }
    }
    },
    "size": 0
    }
    屈服
    {
    ...
    "topics_parent" : {
    ...
    "topics" : {
    ...
    "topics" : {
    ...
    "buckets" : [
    {
    "key" : "Race",
    "doc_count" : 2
    },
    {
    "key" : "Disgrace",
    "doc_count" : 1
    },
    {
    "key" : "Tracey Chapman",
    "doc_count" : 1
    }
    ]
    }
    }
    }
    }
    注意事项
  • 为了使它起作用,您必须重新索引
  • ngrams 会增加存储空间——取决于每个文档有多少标签,这可能会成为一个问题
  • 嵌套字段在内部被视为“单独的文档”,因此这也会影响磁盘空间

  • P.S.:这是一个有趣的用例。让我知道实现的进展情况!

    关于elasticsearch - 如何使用include和regex正确查询elasticsearch中术语聚合值的内部?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65581838/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com