查询基于Elasticsearch地址的索引

Bir*_*rdy 2 lucene mapping indexing autocomplete elasticsearch

我很难尝试获得基于地址的索引来返回与自动完成工作相同的结果,我一直在尝试两种不同的方法,我开始尝试使用 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"
Run Code Online (Sandbox Code Playgroud)

完成建议者映射:

{
  "mappings": {
    "addresses": {
      "properties": {
        "suggest": {
          "type": "completion",
          "preserve_separators": false,
          "analyzer": "standard",
          "search_analyzer": "standard"
        },
        "address": {
          "type": "text"
        },
        "id": {
          "type": "keyword"
        }
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

请注意,我在建议器中设置了preserve_separatorsfalse以允许 west hill 也与 westhill 匹配,这在建议器上工作得很好,但是在我的 nGram 索引中,我不确定如何通过映射启用相同的功能,我相信这可能是我遇到的问题是没有返回相关结果。

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

{
  "suggest": {
    "suggestions": {
     "prefix": "7 westhill gardens",
      "completion": {
        "field": "suggest",
        "fuzzy": {
          "fuzziness": 2 // Also tried with no fuzzy and fuzziness: 1
        }
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

返回结果如下:

"address": "7, Westhill Gardens, Brackley NN136AA",
"address": "7, Westhill Gardens, Bromyard HR74HW",
"address": "7, West Hill Gardens, West Hill, Budleigh Salterton EX96BL",
Run Code Online (Sandbox Code Playgroud)

但是,如果我从查询中删除数字 7 并执行此查询,它不会返回任何结果,这是一个关键问题,因为并非所有用户都会以给定的门牌号开始查询,并且执行搜索的情况很常见,如下west hill gardens所示反对7 west hill gardens

{
  "suggest": {
    "suggestions": {
      "prefix": "westhill gardens",
      "completion": {
        "field": "suggest",
        "fuzzy": {
          "fuzziness": 2
        }
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

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

{
  "suggest": {
    "suggestions": {
      "prefix": "7 EX9 6BL",
      "completion": {
        "field": "suggest",
        "fuzzy": {
          "fuzziness": 2
        }
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

我希望比我有更多经验的人可以就最好的方法是什么以及我是否应该坚持使用 nGrams 并尝试让自定义分析器/过滤器方法起作用提出一些想法。或者我只是做得完全错误? !我才刚刚开始学习 Elasticsearch,所以如果我的术语不正确,我深表歉意。

Joa*_*nna 5

将完成建议更多地视为“从...开始”机制。文档说:“完成建议器是所谓的前缀建议器。” 因此,通过这种类型的搜索,您可能无法获得您想要的一切。

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

{
  "settings": {
    "analysis": {
      "analyzer": {
        "my_stop_analyzer": {
          "type": "stop"
        }
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

然后映射文档类型:

{
  "properties": {
    "suggest": {
      "type": "completion",
      "preserve_separators": false,
      "preserve_position_increments": false
    },
    "address": {
      "type": "text"
    },
    "id": {
      "type": "keyword"
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

然后这个查询:

{
  "suggest": {
    "suggestions": {
     "prefix": "westhill gardens",
      "completion": {
        "field": "suggest",
        "fuzzy": {
          "fuzziness": 2
        }
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

会导致:

"address": "5, West hill Gardens, Bromyard AAA"
"address": "7, Westhill Gardens, Bromyard HR74HW"
Run Code Online (Sandbox Code Playgroud)

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

另一种选择是什么?nGrams,正如已经说过的,或者您也可以尝试使用query_string. 简单的例子,假设您有一个标准映射:

{
  "properties": {
    "suggest": {
      "type": "text"
    },
    "address": {
      "type": "text"
    },
    "id": {
      "type": "keyword"
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

然后使用query_string

{
  "query": {
        "query_string" : {
            "default_field" : "suggest",
            "query" : "west* Gardens*",
            "default_operator": "OR",
            "split_on_whitespace": "true",
            "fuzziness" : 2
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

它给了我结果,例如:

"address": "267, Westhill Gardens, Bromyard HR74HW",
"address": "5, West hill Gardens, Bromyard AAA",
"address": "1, West hill Bromyard HR74HW"
Run Code Online (Sandbox Code Playgroud)

但请注意,使用 * 通配符会导致更差的性能和内存消耗(一定要避免在术语开头使用 *),但另一方面它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"
            }
         }
      }
   }
}
Run Code Online (Sandbox Code Playgroud)

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

GET http://127.0.0.1:9200/sug/addresses/{documentId}/_termvector?fields=suggest
Run Code Online (Sandbox Code Playgroud)

之后的查询(这次是 Bool Query)非常简单:

{ 
  "query" : 
  { "bool" : 
    { "must" : [ 
        { "match" : { "suggest": { "query": "1, Westhil" } } }
    ]}
}
Run Code Online (Sandbox Code Playgroud)

}

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