寻找一种更简洁的方法来对多个术语进行前缀匹配

Looking for a more concise way to prefix match on multiple terms

我正在寻找更好的方法。

我有任意数量的用户输入词(假设它们是姓氏)。我想对每个匹配项执行前缀搜索并提高任何匹配项的分数。

未分析的 prefix query 是我现在使用的——参见下面的示例——但是我也承担了分析器通过创建自定义编程来拆分的其他方式的责任将输入术语与空格分开,修剪,小写它们,然后使用标记构建一系列前缀查询以提高评分。

  1. 示例输入是一堆姓氏,如 "Smith, Rodriguez, ROBERTS, doe"。
  2. 然后我的程序将它们解析成标记并将它们小写成:
    史密斯
    罗德里格斯
    罗伯茨
    母鹿

  3. 最后我构建了多个前缀查询来提高分数

"should": [
  {
      "dis_max" : {
          "tie_breaker": 1,
          "boost": 3,
          "queries": [
              {
                  "prefix" : { "surname": "doe"}
              },
                {
                  "prefix" : { "surname": "rob"}
              },
                {
                  "prefix" : { "surname": "rod"}
              },
                {
                  "prefix" : { "surname": "smi"}
              }
          ]
      }
  }
],

我不禁认为我这样做效率低下,而 elasticsearch 可能会提供我不知道的更智能的功能。我希望前缀查询的分析形式可以让我的生活更轻松。例如,将用于分析的输入逐字传递给像这样的弹性查询将是理想的 "someAnalyzedPrefix": {"surname": "smith rodriguez roberts doe", prefix_length: 3} 我在这里有点梦想,但你明白我正在寻找更简单的解决方案这一事实的要点。

我想知道是否有任何其他类型的查询可以在负责分析的同时产生相同的结果。

欢迎大家提出改进建议,否则我会坚持上面的模式,因为它确实满足了需要,但不一定很漂亮。

我认为 Edge NGram tokenizer / filter 会有所帮助。

您可以拥有仅包含索引的索引和 search only 个分析器。 索引分析器只会小写并生成边缘 ngram。搜索分析器有一个 Word Delimiter filter,它将负责解析您的查询。 请注意,您可以省略 Word Delimiter 过滤器,只使用 Standard tokenizer 而不是 Whitespace,它会负责将其拆分为空格和逗号。单词定界符使您可以更好地控制要如何拆分标记。

您始终可以使用 _analyze api 来测试标记化的工作方式。

索引设置:

{
    "settings" : {
        "analysis" : {
          "filter": {
            "word_delimiter_filter": {
                  "preserve_original": "true",
                  "catenate_words": "true",
                  "catenate_all": "true",
                  "split_on_case_change": "true",
                  "type": "word_delimiter",
                  "catenate_numbers": "true",
                  "stem_english_possessive": "false"
            },
            "edgengram_filter": {
                    "type":     "edge_ngram",
                    "min_gram": 3,
                    "max_gram": 3
            }
        },
        "analyzer" : {
                "my_edge_ngram_analyzer" : {
                    "filter": [
                        "lowercase",
                        "edgengram_filter"
                    ],
                    "type": "custom",
                    "tokenizer" : "whitespace"
                },
                "my_edge_ngram_search_analyzer": {
                  "filter": [
                    "lowercase",
                    "word_delimiter_filter",
                    "edgengram_filter"
                  ],
                  "type": "custom",
                  "tokenizer": "whitespace"
                }
            }
        }
    }
}

映射:

{
      "properties": {
        "surname_edgengrams": {
            "type": "string",
            "analyzer": "my_edge_ngram_analyzer",
            "search_analyzer": "my_edge_ngram_search_analyzer"
        },
        "surname": {
          "type": "string",
          "index": "not_analyzed",
          "copy_to": [
              "surname_edgengrams"
            ]
        }
      }  
}

我使用批量索引了一些文档 api:

{ "index" : { "_index" : "edge_test", "_type" : "test_mapping", "_id" : "1" } }
{ "surname" : "Smith" }
{ "index" : { "_index" : "edge_test", "_type" : "test_mapping", "_id" : "2" } }
{ "surname" : "Rodriguez" }
{ "index" : { "_index" : "edge_test", "_type" : "test_mapping", "_id" : "3" } }
{ "surname" : "Roberts" }
{ "index" : { "_index" : "edge_test", "_type" : "test_mapping", "_id" : "4" } }
{ "surname" : "Doe" }

并使用以下搜索模板:

{
    "query" : {
        "bool" : {
            "should" : [{
                    "match" : {
                        "surname_edgengrams" : {
                            "query" : "Smith, Rodriguez, ROBERTS, doe",
                            "boost" : 3
                        }
                    }
                }
            ]
        }
    }
}

结果:

{
  "took": 5,
  "timed_out": false,
  "_shards": {
    "total": 3,
    "successful": 3,
    "failed": 0
  },
  "hits": {
    "total": 4,
    "max_score": 0.14085768,
    "hits": [
      {
        "_index": "edge_test",
        "_type": "test_mapping",
        "_id": "1",
        "_score": 0.14085768,
        "_source": {
          "surname": "Smith"
        }
      },
      {
        "_index": "edge_test",
        "_type": "test_mapping",
        "_id": "3",
        "_score": 0.14085768,
        "_source": {
          "surname": "Roberts"
        }
      },
      {
        "_index": "edge_test",
        "_type": "test_mapping",
        "_id": "2",
        "_score": 0.13145615,
        "_source": {
          "surname": "Rodriguez"
        }
      },
      {
        "_index": "edge_test",
        "_type": "test_mapping",
        "_id": "4",
        "_score": 0.065728076,
        "_source": {
          "surname": "Doe"
        }
      }
    ]
  }
}