2013-12-17 44 views
28

我有一个大型的名字数据库,主要来自苏格兰。我们目前正在生产一个原型来取代现有的一个搜索软件。这仍在制作中,我们的目标是让我们的结果尽可能地接近当前搜索的结果。ElasticSearch - 寻找人名

我希望有人能帮助我,我进入一个搜索弹性搜索,查询是“迈克尔Heaney”,我得到了一些野生的结果。目前的搜索返回两个主要的姓氏,这些是 - “Heaney”和“Heavey”都带有“Michael”的名字,我可以在Elastic Search中获得“Heaney”结果,但是我无法获得“Heavey”,ES也返回没有姓氏“迈克尔”的人,但我明白,这是由于它是模糊查询的一部分。我知道这是一个狭义的用例,因为它只有一个搜索,但得到这个结果并知道我可以如何获得它会有所帮助。

谢谢。

映射

{ 
    "jr": { 
    "_all": { 
     "enabled": true, 
     "index_analyzer": "index_analyzer", 
     "search_analyzer": "search_analyzer" 
    }, 
    "properties": { 
     "pty_forename": { 
      "type": "string", 
      "index": "analyzed", 
      "boost": 2, 
      "index_analyzer": "index_analyzer", 
      "search_analyzer": "search_analyzer", 
      "store": "yes" 
     }, 
     "pty_full_name": { 
      "type": "string", 
      "index": "analyzed", 
      "boost": 4, 
      "index_analyzer": "index_analyzer", 
      "search_analyzer": "search_analyzer", 
      "store": "yes" 
     }, 
     "pty_surname": { 
      "type": "string", 
      "index": "analyzed", 
      "boost": 4, 
      "index_analyzer": "index_analyzer", 
      "search_analyzer": "search_analyzer", 
      "store": "yes" 
     } 
    } 
    } 
}' 

指数设置

{ 
    "settings": { 
    "number_of_shards": 2, 
    "number_of_replicas": 0, 
    "analysis": { 
     "analyzer": { 
      "index_analyzer": { 
       "tokenizer": "standard", 
       "filter": [ 
        "standard", 
        "my_delimiter", 
        "lowercase", 
        "stop", 
        "asciifolding", 
        "porter_stem", 
        "my_metaphone" 
       ] 
      }, 
      "search_analyzer": { 
       "tokenizer": "standard", 
       "filter": [ 
        "standard", 
        "my_metaphone", 
        "synonym", 
        "lowercase", 
        "stop", 
        "asciifolding", 
        "porter_stem" 
       ] 
      } 
     }, 
     "filter": { 
      "synonym": { 
       "type": "synonym", 
       "synonyms_path": "synonyms/synonyms.txt" 
      }, 
      "my_delimiter": { 
       "type": "word_delimiter", 
       "generate_word_parts": true, 
       "catenate_words": false, 
       "catenate_numbers": false, 
       "catenate_all": false, 
       "split_on_case_change": false, 
       "preserve_original": false, 
       "split_on_numerics": false, 
       "stem_english_possessive": false 
      }, 
      "my_metaphone": { 
       "type": "phonetic", 
       "encoder": "metaphone", 
       "replace": false 
      } 
     } 
    } 
    } 
}' 

模糊

{ 
"from":0, "size":100, 
"query": { 
    "bool": { 
     "should": [ 
      { 
       "fuzzy": { 
        "pty_surname": { 
         "min_similarity": 0.2, 
         "value": "Heaney", 
         "prefix_length": 0, 
         "boost": 5 
        } 
       } 
      }, 
      { 
       "fuzzy": { 
        "pty_forename": { 
         "min_similarity": 1, 
         "value": "Michael", 
         "prefix_length": 0, 
         "boost": 1 
        } 
       } 
      } 
     ] 
    } 
    } 
} 

回答

28

首先,我重新创建你的https://www.found.no/play/gist/867785a709b4869c5543

如果你去那里,切换到“分析” -Tab看文字是如何转化:在播放当前配置

注意,例如该Heaney结束了切分作为[hn, heanei]search_analyzer和如[HN, heanei]index_analyzer。注意metaphone-term的情况差异。因此,那个不匹配。

fuzzy -query不执行查询时间文本分析。因此,您最终将Heaveyheanei进行比较。这有一个Damerau-Levenshtein distance长于您的参数允许。

你真正想要做的是使用match的模糊功能。匹配确实做查询时间文本分析,并具有模糊-参数。

至于fuzziness,这在Lucene 4中有所改变。之前,它通常被指定为浮点数。现在它应该被指定为允许的距离。有一个优秀的拉请求,以澄清:https://github.com/elasticsearch/elasticsearch/pull/4332/files

你之所以得到没有名字Michael人是因为你在做bool.should。这具有OR语义。一个匹配就足够了,但是得分方面,匹配得越多,它越好。

最后,将所有这些过滤合并到同一个术语中并不一定是最好的方法。例如,你无法知道并提高确切的拼写。您应该考虑的是使用multi_field以多种方式处理该字段。

Here's an example you can play with,用curl命令在下面重新创建它。但是,我完全不用这个“porter”stemmer。我只是为了展示multi_field的工作原理。使用匹配,模糊匹配和拼音匹配的组合应该会让你走得更远。 (确保你在拼音匹配时不允许模糊 - 或者你会得到无用的模糊匹配。:-)

#!/bin/bash 

export ELASTICSEARCH_ENDPOINT="http://localhost:9200" 

# Create indexes 

curl -XPUT "$ELASTICSEARCH_ENDPOINT/play" -d '{ 
    "settings": { 
     "analysis": { 
      "text": [ 
       "Michael", 
       "Heaney", 
       "Heavey" 
      ], 
      "analyzer": { 
       "metaphone": { 
        "type": "custom", 
        "tokenizer": "standard", 
        "filter": [ 
         "my_metaphone" 
        ] 
       }, 
       "porter": { 
        "type": "custom", 
        "tokenizer": "standard", 
        "filter": [ 
         "lowercase", 
         "porter_stem" 
        ] 
       } 
      }, 
      "filter": { 
       "my_metaphone": { 
        "encoder": "metaphone", 
        "replace": false, 
        "type": "phonetic" 
       } 
      } 
     } 
    }, 
    "mappings": { 
     "jr": { 
      "properties": { 
       "pty_surename": { 
        "type": "multi_field", 
        "fields": { 
         "pty_surename": { 
          "type": "string", 
          "analyzer": "simple" 
         }, 
         "metaphone": { 
          "type": "string", 
          "analyzer": "metaphone" 
         }, 
         "porter": { 
          "type": "string", 
          "analyzer": "porter" 
         } 
        } 
       } 
      } 
     } 
    } 
}' 


# Index documents 
curl -XPOST "$ELASTICSEARCH_ENDPOINT/_bulk?refresh=true" -d ' 
{"index":{"_index":"play","_type":"jr"}} 
{"pty_surname":"Heaney"} 
{"index":{"_index":"play","_type":"jr"}} 
{"pty_surname":"Heavey"} 
' 

# Do searches 

curl -XPOST "$ELASTICSEARCH_ENDPOINT/_search?pretty" -d ' 
{ 
    "query": { 
     "bool": { 
      "should": [ 
       { 
        "bool": { 
         "should": [ 
          { 
           "match": { 
            "pty_surname": { 
             "query": "heavey" 
            } 
           } 
          }, 
          { 
           "match": { 
            "pty_surname": { 
             "query": "heavey", 
             "fuzziness": 1 
            } 
           } 
          }, 
          { 
           "match": { 
            "pty_surename.metaphone": { 
             "query": "heavey" 
            } 
           } 
          }, 
          { 
           "match": { 
            "pty_surename.porter": { 
             "query": "heavey" 
            } 
           } 
          } 
         ] 
        } 
       } 
      ] 
     } 
    } 
} 
' 
+0

谢谢亚历克斯。让我把所有这些信息都收集起来,然后我会回报。答案看起来很彻底。 – Nate

+0

我们刚刚发表了一篇关于模糊搜索的文章,这也可能是有趣的:https://www.found.no/foundation/fuzzy-search/ –

+0

将书签。非常感谢您的帮助,我学到了很多东西。 – Nate