【问题标题】:Grouping match_phrase search results by match text in Elastic Search在 Elastic Search 中按匹配文本对 match_phrase 搜索结果进行分组
【发布时间】:2016-01-23 02:40:53
【问题描述】:

给定这样的词组匹配查询:

{
    'match_phrase': {
        'text.english': {
            'query': "The fox jumped over the wall",
            'phrase_slop': 4,
        }
    }
}

有没有办法按完全匹配对结果进行分组?

因此,如果我有 1 个文档 text.english 包含“快速狐狸跳过小墙”和 3 个文档包含“懒狐狸跳过大墙”,我最终会得到这两组结果。

我可以在 ES 之外运行多个查询并进行一些处理,但我需要一个能够在大量文档上合理执行的解决方案。理想情况下,我希望有一种方法可以使用我错过的聚合来做到这一点。

我想出的最佳解决方案是运行上面的高亮查询,从所有结果中解析出所有高亮,然后根据高亮内容对它们进行分组。这对于非常小的结果集来说很好,但是对于超过 1000 个文档的结果集,它的速度非常慢。

编辑: 也许我可以让这更清楚一点。如果我有具有以下值的示例文档:

  1. “敏捷的狐狸跳过小墙。废话废话很多页无关的文字。”
  2. “懒惰的狐狸跳过了大墙。废话废话很多页无关的文字。”
  3. “懒惰的狐狸跳过了大墙。废话废话很多页无关的文字。”
  4. “懒惰的狐狸跳过了大墙。废话废话很多页无关的文字。”

我希望能够使用查询文本“狐狸跳过墙”将结果分组如下:

  • “快狐跳过小墙” - 文档 1
  • “懒狐跳过大墙” - 文档 2、3、4

【问题讨论】:

  • 你想达到什么目的?从这两个示例文档中,您能解释一下期望的结果是什么?
  • 好的,所以您希望您的查询匹配,但结果应该按它们匹配的文本分组? text.english.raw 上的简单聚合应该可以做到(其中.rawnot_analyzed 子字段)。
  • 没错,我想按完全匹配的文本对结果进行分组。我有每个文档的分析副本和原始副本。聚合是如何工作的?我找不到能做到这一点的人。
  • "The lazy fox jumped over the big wall" 这是最初编入索引的文本。您想根据此文本或其他内容进行分组吗?如果你的文本有 5 行,你想对整个文本进行分组吗?
  • 我想根据匹配进行分组,而不是整个文本。

标签: elasticsearch


【解决方案1】:

我在产品搜索应用程序中遇到了类似的问题/挑战。我想按品牌对产品进行分组,例如

Nikon
Nikos

为了解决这个问题,我正在尝试使用Suggester 。背后的想法是建议者将为我的搜索提供建议。这些建议将被分组,并且不会对所有文档重复(即使它们周围可能有一些其他文本)。您可以使用Term SuggesterPhrase Suggester

但是,这种方法可能需要您更改结果的处理方式。您必须将建议显示为组并单独处理搜索结果。这种方法的优点是您不必自己进行分组。

另一种解决方案是使用带状疱疹的Terms Aggregation。这种聚合将分组词组(shingles)。但是,要获得结果,您必须获取所有聚合并将它们与您的查询输入相匹配。查看示例映射、数据和查询:

PUT /so
{
   "settings": {
      "analysis": {
         "analyzer": {
            "suggestion_analyzer": {
               "tokenizer": "standard",
               "filter": [
                  "lowercase"
               ]
            },
            "analyzer_shingle": {
               "type": "custom",
               "tokenizer": "standard",
               "filter": [
                  "filter_shingle"
               ]
            }
         },
         "filter": {
            "filter_shingle": {
               "type": "shingle",
               "min_shingle_size": 4,
               "max_shingle_size": 16,
               "output_unigrams": "false"
            }
         }
      }
   },
   "mappings": {
      "d": {
         "properties": {
            "text": {
               "properties": {
                  "english": {
                     "type": "string",
                     "fields": {
                        "shingles": {
                           "type": "string",
                           "analyzer": "analyzer_shingle"
                        },
                        "suggest": {
                           "type": "completion",
                           "index_analyzer": "analyzer_shingle",
                           "search_analyzer": "analyzer_shingle",
                           "payloads": true
                        }
                     }
                  }
               }
            }
         }
      }
   }
}

文档 1:

POST /so/d/1
{
    "text": {
        "english": "The quick fox jumps over the big wall. JJKJKJKJ"
    }
}

文档 2:

POST /so/d/2
{
    "text": {
        "english": "The quick fox jumps over the small wall. JJKJKJKJ"
    }
}

文档 3:

POST /so/d/3
{
    "text": {
        "english": "The quick fox jumps over the gugus wall. LLLLLLL"
    }
}

查询:

POST /so/_search
{
    "size": 0,
    "query": {
        "match": {
           "text.english": "The quick fox jumps over the wall"
        }
    }, 
    "aggs" : {
        "states" : {
            "terms" : {
                "field" : "text.english.shingles",
                "size": 40
            }
        }
    }
}

【讨论】:

    【解决方案2】:

    在我看来,highlighting 是唯一的选择,因为它是 Elasticsearch 显示匹配的文本“部分”的唯一方式。在您的情况下,您希望根据“匹配”对文档进行分组。

    如果文本更短(比如几个词),也许更复杂的解决方案是以shingle 的方式拆分文本并以某种方式对这些短语进行分组...... 也许.

    但是对于文本页面,我认为唯一的选择是使用突出显示并在之后执行其他步骤来对突出显示的部分进行分组。

    【讨论】:

      【解决方案3】:

      我相信您可以在未分析的字段版本上创建术语聚合。

      如果text.raw 定义为not_analyzed,则聚合应采用整个字段值。

      我没有测试过,但是我发现了一些非常相似的东西:ElasticSearch terms aggregation by entire field

      【讨论】:

      • 整个字段都不起作用,很遗憾——我需要匹配。我将更新示例
      【解决方案4】:

      如果您的 text.english 中的语句“完全”相同,那么它们的分数应该相同。您可以根据 Elastic Search _score 聚合结果。

      请参考这个SO问题ElasticSearch: aggregation on _score field?

      由于 ES 已禁用动态脚本,这可能会有所帮助。 ElasticSearch: aggregation on _score field w/ Groovy disabled

      【讨论】:

      • 谢谢,我没想到。非常接近,但问题是在分析和提取文本时,我会有一些不同但得分相同的匹配项(例如上面的两个示例短语)。
      • 呃,也许我上面的评论有误导性。我已经索引了该字段的词干和原始版本。我想复杂性是因为我想在词干上进行匹配,并按原始分组。
      • 刚刚看到您的编辑。由于您有“Blah blah blah many pages of unrelated text.”,因此 ES _score 会有所不同,并且由于同样的原因,您也不能使用其他用户建议的术语聚合
      • 这可能不相关,但由于您正在使用突出显示,因此突出显示的片段存在持续问题。 highlighting issue 。我个人遇到过这个问题。抱歉帮不了你
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-03
      • 1970-01-01
      • 2022-07-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多