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

FullText in SOLR based on substring of specific field

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

在我的 solr 架构中,我有一个 field,其类型是 solr.TextField。 我正在尝试对其进行 fullTextSearch。只有在搜索关键字前后都包含通配符 * 时,查询 returns 才会显示结果。如果我只在最后包含它,它就不起作用(例如:searchWord*

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

请在schema.xml下方查找。注意:我使用的是 solr v 7.4.0

<?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>

您可以看到我已将 corpusfullText 字段定义为类型 solr.TextField。这两个字段都有很多文本数据。

我打算对 corpusfullText 字段进行全文搜索。 为此,我使用 SOLR 查询如下: corpus:*Thermodynamics*

上面的查询使用了通配符,它​​确实有效,returns 我得到了预期的结果。但我不明白这是否是正确的做法。许多论坛提到不支持搜索查询开头的 *。 另一个观察是:如果我只使用语料库中的第一个词并使用 corpus: Thermodynamics* 搜索它 - 它确实有效。然而,这不适用于语料库中较晚出现的词(即所有不是语料库中第一个词的词)

我的印象是 SOLR 会理解 whitespace/newline 将被忽略。 所以 - 假设语料库有文本:Physics has a specialization for Thermodynamics and Heat。然后 SOLR 查询 corpus: Thermodynamics*corpus: Thermodynamics 应该可以工作,因为 Thermodynamics 本身就是一个词,SOLR 会理解忽略应该忽略的空白。 相反,我需要在搜索词的开头和结尾都包含通配符 *

请帮我解释一下
1. 尽管论坛声称 SOLR 不支持搜索词开头的 *,但为什么会出现这种行为。
2. 我在 corpus 字段上做全文的方式是否正确?

谢谢, 车坛

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

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

.. 这并没有真正定义有用的字段类型。为此,您需要附加一个分词器和几个过滤器。 tokenizer 将文本拆分为标记,而标记是产生匹配的东西。这叫做分析链。

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

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

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

然后是通配符 - 如果存在通配符,则跳过整个分析链。这意味着在搜索文本时使用通配符通常不是一个好主意。它不会像你想的那样做,除非你试图匹配单个标记(因为当存在通配符时 Tokenizer 将被跳过)。因此,您必须谨慎行事,而且您最终可能会 "why did this happen" 的次数更多。

另一种方法是使用 NGramFilter,它将单词中的每组字母拆分(foo 变为 ffofoooooo) 到单独的标记中。你通常只想在索引时这样做,所以为你的字段使用单独的分析链(你通过配置中的 type 参数定义 - 如果没有给出类型,相同的链将用于索引和查询.

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

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

This filter reverses tokens to provide faster leading wildcard and prefix queries. Tokens without wildcards are not reversed.