首页 > 解决方案 > SOLR中的全文基于特定字段的子字符串

问题描述

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

在我的 solr 架构中,我有一个field类型为solr.TextField. 我正在尝试对其进行fullTextSearch。仅当我* 在搜索关键字前后都包含通配符时,查询才会返回结果。如果我只在最后包含它,它就不起作用(例如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字段定义为具有 type solr.TextField。这两个字段都有大量的文本数据。

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

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

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

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

谢谢, 切坦

标签: solrlucenefull-text-search

解决方案


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

<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和之前的顺序不同。您通常还希望至少附加 a LowercaseFilter,以便获得不区分大小写的搜索 - 以及任何更多过滤器,具体取决于您的字段和域的用例。创建多个字段以执行不同的匹配,并分别权衡它们以获得对您的用户最有意义的文档评分。

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

然后是通配符 - 如果存在通配符,则跳过整个分析链。这意味着在文本中搜索时使用通配符通常是一个坏主意。除非您尝试匹配单个标记(因为存在通配符时将跳过标记器),否则它不会做您认为的事情。所以你必须小心翼翼地做这件事,你可能会更频繁地陷入“为什么会发生这种情况”。

另一种方法是使用 NGramFilter ,它将单词中的每组字母(foo变成f、、、、fofoo)拆分为单独的标记。您通常只想在索引时执行此操作,因此为您的字段使用单独的分析链(您通过配置中的参数定义 - 如果未给出类型,则将使用相同的链进行索引和查询。ooootype

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

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

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


推荐阅读