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

时间:2016-09-30 19:08:54

标签: elasticsearch elasticsearch-query

我正在寻找更好的方法。

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

未分析的prefix query是我现在正在使用的 - 请参阅下面的示例 - 但是我也承担了分析师通过创建自定义编程来分解在空格上输入术语,修剪,缩小它们,然后使用标记构造一系列前缀查询以提高评分。

  1. 示例输入是一堆姓氏,如“Smith,Rodriguez,ROBERTS,doe”。
  2. 然后我的编程将它们解析为令牌并将它们缩小为:
    史密斯
    罗德里格斯
    罗伯茨
    doe

  3. 最后,我构建了多个前缀查询以提高分数,如此

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

    我不禁想到我以低效的方式这样做,而弹性搜索可能会提供我不知道的更智能的功能。我希望分析前缀查询的形式,让我的生活轻松。例如,将输入逐字输入分析到弹性查询是理想的"someAnalyzedPrefix": {"surname": "smith rodriguez roberts doe", prefix_length: 3}我在这里做了一点梦想,但你得到了我正在寻找一个更简洁的解决方案的事实的要点。

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

    欢迎提出改进建议,否则我会坚持上述模式,因为它确实满足了需求,但不一定非常漂亮。

1 个答案:

答案 0 :(得分:0)

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

您可以拥有仅包含索引的索引和search only分析器。 索引分析器只会小写并生成边缘ngrams。搜索分析器有Word Delimiter filter,它将负责解析您的查询。 请注意,您可以省略Word Delimiter过滤器,只使用Standard tokenizer而不是Whitespace,它将负责在空格和逗号上拆分它。 Word分隔符使您可以更好地控制分割标记的方式。

您始终可以使用_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"
        }
      }
    ]
  }
}