Solr部分和全字符串匹配

Scr*_*ead 23 lucene search solr

我试图允许搜索Solr中的部分字符串,所以如果有人搜索"ppopota",他们会得到与搜索"hippopotamus"相同的结果.我上下阅读文档,觉得我已经筋疲力尽了.到目前为止,我有以下内容:

定义新字段类型:

<fieldtype name="testedgengrams" class="solr.TextField">
   <analyzer>
     <tokenizer class="solr.LowerCaseTokenizerFactory"/>
     <filter class="solr.EdgeNGramFilterFactory" minGramSize="2" maxGramSize="15" side="front"/>
  </analyzer>
</fieldtype>
Run Code Online (Sandbox Code Playgroud)

定义"testsgengrams"类型的字段:

<field name="text_ngrams" type="testedgengrams" indexed="true" stored="false"/>
Run Code Online (Sandbox Code Playgroud)

将text_ngrams的内容复制到文本中:

<copyField source="text_ngrams" dest="text"/>
Run Code Online (Sandbox Code Playgroud)

唉,这不起作用.我错过了什么?

Mau*_*fer 18

您正在使用EdgeNGramFilterFactory生成令牌"hi","hip","hipp"等,因此它与"ppopota"不匹配.请改用NGramFilterFactory.


Aar*_*son 11

启用部分单词搜索

您必须编辑本地schema.xml文件(通常在solr/config下)以添加以下任一项:

  1. NGramFilterFactory
  2. EdgeNGramFilterFactory

这是我的样子: 样本solr schema.xml

这是要粘贴的行:

<filter class="solr.EdgeNGramFilterFactory" minGramSize="2" maxGramSize="15" side="front"/>
Run Code Online (Sandbox Code Playgroud)

EdgeNGram

我选择了EdgeN选项.它不允许在单词的中间进行搜索,但它允许从单词的开头开始进行部分单词搜索.这减少了你不想要的误报/匹配,表现更好,并且通常不会被用户遗漏.另外,我喜欢minGramSize = 2,所以你必须输入至少2个字符.有些人将此设置为3.

设置本地并运行后,您必须编辑websolr使用的schema.xml,否则即使您为模型配置了全文搜索,也会获得默认行为,即需要输入全字.

把它提升到一个新的水平

加速索引的5种方法

如果您使用Heroku,则编辑websolr schema.xml的特殊说明

  1. 转到您的应用程序的Heroku在线仪表板
  2. 转到资源选项卡,然后单击Websolr加载项
  3. 单击"索引"下的默认链接
  4. 单击"高级配置"链接
  5. 从本地粘贴schema.xml,包括您选择的Ngram tokenizer的配置(如上所述).保存.
  6. 复制"配置Heroku应用程序"框中的链接,然后将其粘贴到终端中以在heroku配置中设置WEBSOLR_URL链接.
  7. 单击"索引状态"链接以获取漂亮的统计信息,并查看您是快速还是慢速运行.
  8. 重塑一切

heroku run rake sunspot:reindex [5000]

  • 不要使用heroku run rake sunspot:solr:reindex - 它已弃用,不接受任何参数而且速度慢
  • 默认批量大小为50,大多数人建议使用1000,但我已经看到显着更快的结果(每秒1000行而不是大约500 rps)将其提升到5000+

  • 但这个问题与Heroku有什么关系?O_O (2认同)

wor*_*hit 9

好吧我用字段名称做同样的事情

name_de
Run Code Online (Sandbox Code Playgroud)

我设法使用像这样的copyField来使用这个东西:

schema.xml中

<schema name="solr-magento" version="1.2">
    <types>
       ...
        <fieldType name="type_name_de_partial" class="solr.TextField">
            <analyzer type="index">
                <tokenizer class="solr.WhitespaceTokenizerFactory"/>
                <filter class="solr.NGramFilterFactory" minGramSize="3" maxGramSize="1000" side="front" />
                <filter class="solr.NGramFilterFactory" minGramSize="3" maxGramSize="1000" side="back" />
                <filter class="solr.StopFilterFactory" ignoreCase="true" words="stopwords.txt" enablePositionIncrements="true"/>
                <filter class="solr.LowerCaseFilterFactory"/>
                <filter class="solr.TrimFilterFactory" />
                <filter class="solr.RemoveDuplicatesTokenFilterFactory"/>
                <filter class="solr.SnowballPorterFilterFactory" language="German" protected="protwords_de.txt"/>
            </analyzer>
            <analyzer type="query">
                <tokenizer class="solr.StandardTokenizerFactory"/>
                <filter class="solr.WordDelimiterFilterFactory" generateWordParts="1" generateNumberParts="1" catenateWords="0" catenateNumbers="0" catenateAll="0" splitOnCaseChange="1"/>
                <filter class="solr.LowerCaseFilterFactory"/>
                <filter class="solr.TrimFilterFactory" />
                <filter class="solr.SynonymFilterFactory" synonyms="synonyms.txt" ignoreCase="true" expand="true"/>
                <filter class="solr.SnowballPorterFilterFactory" language="German" protected="protwords_de.txt"/>
            </analyzer>
        </fieldType>
    </types>

    ...

    <fields>
        ...
        <field name="name_de_partial" type="type_name_de_partial" indexed="true" stored="true"/>
    </fields>

    ....

    <copyField source="name_de" dest="name_de_partial" />
</schema>
Run Code Online (Sandbox Code Playgroud)

然后在solrconfig.xml中创建搜索条件

<requestHandler name="magento_de" class="solr.SearchHandler">
    <lst name="defaults">
        <str name="defType">dismax</str>
        <str name="echoParams">explicit</str>
        <str name="tie">0.01</str>                                          <!-- Tie breaker -->
        <str name="qf">name_de_partial^1.0 name_de^3.0</str>                <!-- Phrase Fields -->
        <str name="pf">name_de_partial^1.0 name_de^3.0</str>                <!-- Phrase Fields -->
        <str name="mm">3&lt;90%</str>                                       <!-- Minimum 'Should' Match [id 1..3 must much all, else 90proc] -->
        <int name="ps">100</int>                                            <!-- Phrase Slop -->
        <str name="q.alt">*:*</str>
        ..
    </lst>
    <arr name="last-components">
        <str>spellcheck</str>
    </arr>
</requestHandler>
Run Code Online (Sandbox Code Playgroud)

有了这个solr,在字段name_de_partial中搜索pow 1.0,在name_de中搜索pow 3.0

因此,如果引擎在name_de中找到特定的查询字,那么它将被放在列表的顶部.如果他也在name_de_partial中找到了某些东西,那么它也会被计算并被放入结果中.

并且字段name_de_partial正在使用特定的solr过滤器,因此它可以使用查询"hip"或"ppie"或"ippi"找到单词"hippie"而无需swet.


And*_*e85 6

如果在索引和查询时设置EdgeNGramFilterFactory或NGramFilterFactory,并结合q.op = AND(如果使用dismax,则默认mm = 100%),您将遇到一些问题.

尝试仅在索引时定义NGramFilterFactory:

<fieldType name="testedgengrams" class="solr.TextField">
    <analyzer type="index">
        <tokenizer class="solr.LowerCaseTokenizerFactory"/>
        <filter class="solr.NGramFilterFactory" minGramSize="3" maxGramSize="15"/>
    </analyzer>
    <analyzer type="query">
        <tokenizer class="solr.LowerCaseTokenizerFactory"/>
    </analyzer>
</fieldType>
Run Code Online (Sandbox Code Playgroud)

或者尝试设置q.op = OR(如果使用dismax,则设置为mm = 1)

  • 谢谢,解决了我遇到的一个问题。 (2认同)