【问题标题】:Querying Elasticsearch Address Based Index查询基于 Elasticsearch 地址的索引
【发布时间】:2018-01-02 13:06:58
【问题描述】:

我很难让基于地址的索引返回结果,就像自动完成一样,我一直在尝试两种不同的方法,我开始尝试使用 nGram 和自定义分析器,但我真的很难获得相关结果以显示使用地址自动完成时的预期。

我关注的第二种方法是查看随附的完成建议程序 elasticsearch 是否更容易开始工作,但我似乎在各个方向都遇到了障碍。

我们根据每次按键时的输入值发送常规客户端 API 调用。

我似乎面临的问题是......我没有返回足够相关的结果,如果/当它们相关时,附加字符部分单词可能会强制不返回任何结果。

以下地址为示例:7 West Hill Gardens, West Hill EX9 6BL

我的文档是这样存储的:

完成建议

"id": "1",
"address": "7, Westhill Gardens, Bromyard HR74HW",
"suggest": "7, Westhill Gardens, Bromyard HR74HW"

完成建议映射:

{
  "mappings": {
    "addresses": {
      "properties": {
        "suggest": {
          "type": "completion",
          "preserve_separators": false,
          "analyzer": "standard",
          "search_analyzer": "standard"
        },
        "address": {
          "type": "text"
        },
        "id": {
          "type": "keyword"
        }
      }
    }
  }
}

请注意,我在建议器中将 preserve_separators 设置为 false 以允许将西山也匹配为西山,这在建议器上运行良好,但是在我的 nGram 索引中,我不确定如何使用映射启用相同的功能我相信这可能是我没有返回相关结果的问题的一部分。

当我使用以下查询查询7 westhill gardens 时,建议者是:

{
  "suggest": {
    "suggestions": {
     "prefix": "7 westhill gardens",
      "completion": {
        "field": "suggest",
        "fuzzy": {
          "fuzziness": 2 // Also tried with no fuzzy and fuzziness: 1
        }
      }
    }
  }
}

返回如下结果:

"address": "7, Westhill Gardens, Brackley NN136AA",
"address": "7, Westhill Gardens, Bromyard HR74HW",
"address": "7, West Hill Gardens, West Hill, Budleigh Salterton EX96BL",

但是,如果我从查询中删除数字 7 并执行此查询,它不会返回任何结果,这是一个关键问题,因为并非所有用户都会使用给定的门牌号开始他们的查询,执行搜索为 west hill gardens 与 7 west hill gardens 相对应

{
  "suggest": {
    "suggestions": {
      "prefix": "westhill gardens",
      "completion": {
        "field": "suggest",
        "fuzzy": {
          "fuzziness": 2
        }
      }
    }
  }
}

最后,如果我只查询如下所示的门牌号,则不会返回任何结果。

{
  "suggest": {
    "suggestions": {
      "prefix": "7 EX9 6BL",
      "completion": {
        "field": "suggest",
        "fuzzy": {
          "fuzziness": 2
        }
      }
    }
  }
}

我希望比我有更多经验的人能够对最佳方法是什么以及我是否应该坚持使用 nGrams 并尝试让自定义分析器/过滤器方法正常工作提出一些想法。或者我只是在这样做完全错了?!我才刚刚开始学习 elasticsearch,所以如果我的术语不正确,我向您致歉。

【问题讨论】:

    标签: elasticsearch indexing autocomplete lucene mapping


    【解决方案1】:

    将 Completion Suggester 更多地视为“以 ... 开始”机制。文档说:“完成提示器是所谓的前缀提示器。”因此,使用这种类型的搜索,您可能无法获得所需的一切。

    为了更接近一点,一个解决方案是preserve_position_increments 和停用词分析器的组合。首先使用以下设置创建索引:

    {
      "settings": {
        "analysis": {
          "analyzer": {
            "my_stop_analyzer": {
              "type": "stop"
            }
          }
        }
      }
    }
    

    然后为文档类型映射:

    {
      "properties": {
        "suggest": {
          "type": "completion",
          "preserve_separators": false,
          "preserve_position_increments": false
        },
        "address": {
          "type": "text"
        },
        "id": {
          "type": "keyword"
        }
      }
    }
    

    然后这个查询:

    {
      "suggest": {
        "suggestions": {
         "prefix": "westhill gardens",
          "completion": {
            "field": "suggest",
            "fuzzy": {
              "fuzziness": 2
            }
          }
        }
      }
    }
    

    会导致两者:

    "address": "5, West hill Gardens, Bromyard AAA"
    "address": "7, Westhill Gardens, Bromyard HR74HW"
    

    但是如果你尝试搜索:"prefix": "7 gardens" - 它不会给你结果(因为这种机制的所谓前缀建议性质)。

    还有什么选择?如前所述,nGrams,或者您也可以尝试使用query_string。简单的例子,假设你有一个标准映射:

    {
      "properties": {
        "suggest": {
          "type": "text"
        },
        "address": {
          "type": "text"
        },
        "id": {
          "type": "keyword"
        }
      }
    }
    

    然后使用query_string:

    {
      "query": {
            "query_string" : {
                "default_field" : "suggest",
                "query" : "west* Gardens*",
                "default_operator": "OR",
                "split_on_whitespace": "true",
                "fuzziness" : 2
        }
      }
    }
    

    它给了我结果,例如:

    "address": "267, Westhill Gardens, Bromyard HR74HW",
    "address": "5, West hill Gardens, Bromyard AAA",
    "address": "1, West hill Bromyard HR74HW"
    

    但请注意,使用 * 通配符会导致更差的性能和内存消耗(一定要避免在学期开头使用 *),但另一方面,query_string 是一个非常通用的工具。

    ***NGram 案例更新***

    正如我之前写过关于 NGrams 的文章,我将在这里发布第一个想法。

    一些初步假设:

    • 输入 3 个字符后启用自动完成(设置:“min_gram”:3)
    • 我们需要分析数字、空格、逗号等 - 如果用户键入“7, W”,我们需要获取结果集
    • 用于测试启用 ngram 向量 - 它允许查看它的实际工作原理(设置“term_vector”:“yes”),但应在生产中禁用

    映射 - 用于索引和类型 - 如下所示:

    {
       "settings": {
          "number_of_shards": 1,
          "analysis": {
             "tokenizer": {
                "ngram_tokenizer": {
                   "type": "nGram",
                   "min_gram": 3,
                   "max_gram": 10
                }
             },
             "analyzer": {
                "ngram_tokenizer_analyzer": {
                   "type": "custom",
                   "tokenizer": "ngram_tokenizer"
                }
             }
          }
       },
       "mappings": {
          "addresses": {
             "properties": {
                "suggest": {
                   "type": "text",
                   "term_vector": "yes",
                   "analyzer": "ngram_tokenizer_analyzer"
                },
                "address": {
                  "type": "text"
                },
                "id": {
                  "type": "keyword"
                }
             }
          }
       }
    }
    

    现在可以对文档进行索引。您可以通过以下方式检查分析器的工作原理(感谢“term_vector”:“yes”):

    GET http://127.0.0.1:9200/sug/addresses/{documentId}/_termvector?fields=suggest
    

    然后查询(这次是布尔查询)真的很简单:

    { 
      "query" : 
      { "bool" : 
        { "must" : [ 
            { "match" : { "suggest": { "query": "1, Westhil" } } }
        ]}
    }
    

    }

    我认为它应该满足您描述的所有要求 - 使用地址的起始部分、门牌号或任何其他部分以及空格问题进行搜索。如果确实有必要,您可以将min_gram 减少到2。如果您需要了解更多详细信息,请随时提问,或者按照您的建议提出一个新问题。

    【讨论】:

    • 嗨乔安娜,非常感谢您抽出时间给我一些建议并伸出援助之手。从我所看到的.. 在我的 nGram 索引上执行上面的 query_string 查询,对默认字段进行了一些细微的更改,并且还使用字段而不是 default_field 似乎有所改善。如果我创建另一个问题并共享链接,您可以就 nGram 索引向完成建议者分享一些建议,而不是将所有映射发布到我的 nGram 索引并用另一个问题淹没这个问题,我们将不胜感激。
    • 是的,当然,这是一个有趣的案例,我会尽力提供帮助。
    • 我用一般 ngram 案例更新了我的答案 - 如果您仍然有一些案例无法按预期工作,请随时询问。
    • 嗨乔安娜,对不起,我刚刚有机会回到 S/O。感谢您花时间添加 nGram 解决方案。我现在会过一遍,如果值得我创建另一个帖子,我会这样做,因为它也会给你所有的功劳,因为我现在接受这个答案,你应该得到功劳:) - 谢谢你,我真的很感激它。
    • 乔安娜我看过你所说的,它与我之前提到的 nGram 索引上的设置非常接近,所以我认为最好的办法是创建另一个问题并向你展示我的映射有。话虽如此,我还为您的映射添加了一个新索引并返回结果,唯一的问题是排名,但我索引了 1000 万个地址,并将再次执行查询以查看它们如何使用更多数据,我还将创建另一个问题并在那里发布所有内容,包括我得到的结果,但它在英国很晚(凌晨 4 点 47 分),所以我将创建问题....
    【解决方案2】:

    完成建议器仅完成完成字段中给出的确切术语,因此没有“7”的查询返回零结果。

    您想到的使用 nGrams 的解决方案是可行的方法。

    【讨论】:

      猜你喜欢
      • 2021-10-13
      • 2013-04-11
      • 2021-11-22
      • 2018-11-14
      • 2018-05-14
      • 2014-05-30
      • 1970-01-01
      • 1970-01-01
      • 2016-12-28
      相关资源
      最近更新 更多