使用Apache Solr搜索名称

我只是冒险进入看似简单但非常复杂的搜索世界。对于应用程序,我需要构建一个搜索机制,以按名称搜索用户。 阅读了大量的帖子和文章,包括: 如何使用Lucene进行个人姓名(名字,姓氏)搜索? http://dublincore.org/documents/1998/02/03/name-representation/ 通过优先考虑用户关系来搜索社交网络的最佳方式是什么? http://www.gossamer-threads.com/lists/lucene/java-user/120417 Lucene索引和查询设计问题 - 搜索人 Lucene模糊搜索客户名称和部分地址 ......以及其他一些我现在无法找到的人。在我的机器上进行至少索引和基本搜索工作我已经为用户搜索设计了以下方案: 1)拥有第一个,第二个和第三个名称字段并使用Solr索引那些字段 2)使用edismax作为多列搜索的requestParser 3)使用标准化过滤器的组合,例如:音译,拉丁语到ascii convesrion等。 4)最后使用模糊搜索 很明显,对于这方面的新手,我不确定上述是否是最好的方法,并希望听到在这个领域比我更有想法的有经验的用户。 我需要能够通过以下方式匹配名称: 1)口音折叠:Jorn与Jörn匹配,反之亦然 2)替代拼写:卡尔与卡尔匹配,反之亦然 3)缩短的陈述(我相信我是用SynonymFilterFactory做的):Sue匹配Susanne等。 4)Levenstein匹配:Jonn匹配John等 5)Soundex匹配:Elin和Ellen 任何指导,批评或评论都是非常受欢迎的。如果可能的话请告诉我......或者我只是白日做梦。 :) 编辑 我还必须补充一点,我还有一个全名字段,以防有些人有长名字,作为其中一个帖子的例子:Jon Paul或Del Carmen也应该匹配Jon Paul Del Carmen 由于这是一个新项目,我可以以任何我认为合适的方式修改架构和架构,因此限制非常有限。     
已邀请:
听起来你正在为一个语料库提供一些你需要非常松散匹配的搜索? 如果您这样做,您将需要选择字段并设置不同的提升来对结果进行排名。 所以在solr中有单独的“复制”字段: 一个字段用于确切的全名(带过滤器) 带过滤器的多值字段ASCIIFolding,小写...... 带有SynonymFilterFactory的多值字段ASCIIFolding,小写... PhoneticFilterFactory(带Caverphone或Double-Metaphone) 另请参阅:更多非英语Soundex讨论 名称的同义词,我不知道是否有公共同义词db。 模糊搜索,我发现它没有用,它使用Levenshtein距离。 其他过滤器和索引获得更优越的“搜索相关”结果。 可以使用ASCIIFoldingFilterFactory处理名称中的Unicode字符 您正在为预期的用例预先描述解决方案。 如果您想获得高质量的结果,请计划调整您的搜索相关性 当尝试匹配同义词时,这种调整将特别有价值,例如MacDonald和McDonald(其具有比Carl和Karl更大的Levenshtein距离)。     
找到一个昵称db,不知道有多好: http://www.peacockdata2.com/products/pdnickname/ 请注意,它不是免费的。     
另一篇文章的答案非常好: 训练solr以识别昵称或名称变体
<fieldType name="name_en" class="solr.TextField" positionIncrementGap="100" autoGeneratePhraseQueries="true">
  <analyzer type="index">
    <tokenizer class="solr.WhitespaceTokenizerFactory"/>
    <filter class="solr.WordDelimiterFilterFactory" generateWordParts="1" generateNumberParts="1" catenateWords="1" catenateNumbers="1" catenateAll="0" splitOnCaseChange="1"/>
    <filter class="solr.LowerCaseFilterFactory"/>
    <filter class="solr.ASCIIFoldingFilterFactory"/>
  </analyzer>
  <analyzer type="query">
    <tokenizer class="solr.WhitespaceTokenizerFactory"/>
    <filter class="solr.WordDelimiterFilterFactory" generateWordParts="1" generateNumberParts="1" catenateWords="0" catenateNumbers="0" catenateAll="0" splitOnCaseChange="1"/>
    <filter class="solr.LowerCaseFilterFactory"/>
    <filter class="solr.ASCIIFoldingFilterFactory"/>
    <filter class="solr.SynonymFilterFactory" synonyms="english_names.txt" ignoreCase="true" expand="true"/>
  </analyzer>
</fieldType>
    
对于语音名称搜索,您也可以尝试使用Beider-Morse过滤器,如果您混合使用来自不同国家/地区的名称,它可以很好地运行。 如果要将其与typeahead功能一起使用,请将其与EdgeNGramFilter结合使用:
<fieldType name="phoneticNames" class="solr.TextField" positionIncrementGap="100" autoGeneratePhraseQueries="true">
  <analyzer type="index">
    <tokenizer class="solr.WhitespaceTokenizerFactory"/>
    <filter class="solr.BeiderMorseFilterFactory" nameType="GENERIC" ruleType="APPROX" concat="true" languageSet="auto"/>
    <filter class="solr.EdgeNGramFilterFactory" minGramSize="3" maxGramSize="15"/>
  </analyzer>
  <analyzer type="query">
    <tokenizer class="solr.WhitespaceTokenizerFactory"/>
    <filter class="solr.BeiderMorseFilterFactory" nameType="GENERIC" ruleType="APPROX" concat="true" languageSet="auto"/>
  </analyzer>
</fieldType>
    
我们创建了一个简单的“名称”字段类型,允许混合上面答案的“密钥”(例如,SOUNDEX)和“成对”部分。 这是概述: 在索引时,自定义类型的字段被索引到一组(子)字段中,这些字段具有用于高调用匹配不同类型变体的相应值 这是其实施的核心......
List<IndexableField> createFields(SchemaField field, String name) {
        Collection<FieldSpec> nameFields = deriveFieldsForName(name);
        List<IndexableField> docFields = new ArrayList<>();
        for (FieldSpec fs : nameFields) {
            docFields.add(new Field(fs.getName(), fs.getStringValue(),
                         fs.getLuceneField()));
        }
        docFields.add(createDocValues(field.getName(), new Name(name)));
        return docFields;
}
其核心是deriveFieldsForName(name),您可以在其中包含来自PhoneticFilters,LowerCaseFolding等的“键”。 在查询时,首先生成一个自定义的Lucene查询,该查询已被调整以进行调用,并使用与索引时间相同的字段 这是其实施的核心......
public Query getFieldQuery(QParser parser, SchemaField field, String val) {
        Name name = parseNameString(externalVal, parser.getParams());
        QuerySpec querySpec = buildQuery(name);
        return querySpec.accept(new SolrQueryVisitor(field.getName())); 
}
其核心是buildQuery(name)方法,该方法应该生成一个知道上面的deriveFieldsForName(name)的查询,因此对于给定的查询名称,它将找到好的候选名称。 然后,Solr的Rerank功能用于应用高精度重新评分算法来重新排序结果 以下是您查询中的内容...
&rq={!myRerank reRankQuery=$rrq} &rrq={!func}myMatch(fieldName, "John Doe")
myMatch的内容可能有成对的Levenstein或Jaro-Winkler实现。 注:我们自己的完整实现使用deriveFieldsForName,buildQuery和myMatch的专有代码(请参阅http://www.basistech.com/text-analytics/rosette/name-indexer/)来处理上面提到的更多种类的变体(例如,缺少空格,跨语言)。     

要回复问题请先登录注册