SOLR中的FullText基于特定字段的子字符串

时间:2018-09-22 13:18:52

标签: solr lucene full-text-search

我正在我正在从事的项目中使用Apache Solr。 我已经完成所有设置,而且还可以执行SOLR查询。 但是-我对SOLR的一种行为感到困惑-即使在论坛上搜索后-也无法理解这种行为。

在我的Solr模式中,我有一个类型为field的{​​{1}}。 我正在尝试对其进行fullTextSearch。仅当我在搜索关键字之前和之后都包含通配符solr.TextField时,查询才会向我返回结果。如果我仅在结尾处添加它(例如:*),则它不起作用

但是,许多在线论坛都提到solr / lucene在搜索字词开头不支持searchWord*

请在*下找到。注意:我正在使用solr v 7.4.0

schema.xml

您可以看到我已将<?xml version="1.0" encoding="utf-8" ?> <schema name="blog_schema" version="1.4"> <types> <fieldType name="string" class="solr.StrField" /> <fieldType name="text" class="solr.TextField" /> <fieldType name="long" class="org.apache.solr.schema.LongPointField" docValues="true" /> <fieldType name="date" class="org.apache.solr.schema.DatePointField" docValues="true" sortMissingLast="true" omitNorms="true"/> </types> <fields> <field name="post_id" type="string" indexed="true" stored="true" required="true" /> <field name="title" type="string" indexed="true" stored="true" required="true" /> <field name="author" type="string" indexed="true" stored="true" required="true" /> <field name="corpus" type="text" indexed="true" stored="true" required="false" /> <field name="fullText" type="text" indexed="true" multiValued="true" /> <copyField source="*" dest="fullText" /> </fields> <uniqueKey>post_id</uniqueKey> </schema> corpus字段定义为类型fullText。这两个字段都有大量文本数据。

我打算在solr.TextFieldcorpus字段上进行全文搜索。 为此,我使用SOLR查询,如下所示: fullText

上面的查询使用通配符,它​​确实起作用并返回我预期的结果。但是我不知道这是否是正确的方法。许多论坛提到搜索查询开始时不支持corpus:*Thermodynamics*。 另一个观察结果是:如果我只使用语料库中的第一个单词并使用*进行搜索-它确实起作用。但是,这对于在语料库中稍后出现的单词(即不是在语料库中的第一个单词的所有单词)不起作用

我的印象是SOLR理解空格/换行符将被忽略。 所以-假设语料库具有文本:corpus: Thermodynamics*。然后,SOLR查询Physics has a specialization for Thermodynamics and Heatcorpus: Thermodynamics*应该可以工作,因为本身已经有corpus: Thermodynamics这个词,SOLR会理解忽略空白应该被忽略。 相反,我必须在搜索字词的开头和结尾都包含通配符Thermodynamics

请帮助我解释
1.为什么这种行为如此,尽管论坛声称SOLR不支持搜索词开头的*
2.我在*字段上执行fullText的方式是否正确?

谢谢, 赤丹

1 个答案:

答案 0 :(得分:1)

这里有很多事情在起作用,所以让我们从字段类型开始:

<fieldType name="text" class="solr.TextField" />

..这实际上并没有定义有用的字段类型。为此,您需要附加一个分词器和几个过滤器。令牌生成器将文本拆分为令牌,而令牌则产生匹配。这称为分析链。

<fieldType name="text" class="solr.TextField">
  <analyzer>
    <tokenizer class="solr.WhitespaceTokenizerFactory" />
    <filter class="solr.LowerCaseFilterFactory"/>
  </analyzer>
</fieldType>

空白令牌生成器会将“ foo bar baz”拆分为三个令牌foobarbaz。任何查询都将执行相同的操作,并将令牌与令牌匹配。这就是为什么即使搜索的是bar baz foo而不是前面相同的序列,也会得到匹配的原因。通常,您还希望至少附加一个LowercaseFilter,以便进行不区分大小写的搜索-以及其他过滤器,具体取决于您的字段和域的用例。创建多个字段以执行不同的匹配,然后分别权衡它们,以获得对您的用户最有意义的文档评分。

没有这个分析链,我相信您实际上将获得与字符串字段相同的行为。

然后是通配符-如果存在通配符,则会跳过整个分析链。这意味着在文本搜索时使用通配符通常是一个坏主意。除非您尝试匹配单个令牌,否则它不会做您想做的事情(因为存在通配符时将跳过令牌生成器)。因此,您必须谨慎行事,而且您可能最终会遇到“为什么会这样”的情况。

另一种方法是使用NGramFilter,它将单词中的每个字母集分开(foo变成ffofoooooo)分成单独的令牌。通常,您只希望在建立索引时执行此操作,因此请为您的字段使用单独的分析链(您可以通过配置中的type参数进行定义-如果未指定类型,则将使用相同的链进行索引和查询

建议使用前缀通配符(*foo)的原因是,与检查后缀通配符(foo*)相比,检查前缀通配符的开销很大。在后缀的情况下,您可以从foo遍历索引,并继续进行直到遇到不是以foo开头的内容,而对于*foo,则必须有效地查看所有索引中的术语,因为没有排序顺序可以使它们反向。

输入Reverse Wildcard Filter-此过滤器的作用是,除了常规标记外,它还会索引反向标记(或仅反向标记)。然后在查询时调用过滤器,并且也反转查询令牌-有效索引oof,然后在内部查询oof*。这样,您就可以加快保持该字段的索引排序的速度,而不必查看每个标记。

  

此过滤器反转令牌以提供更快的前导通配符和前缀查询。没有通配符的令牌不会被撤销。