我正在我正在从事的项目中使用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.TextField
或corpus
字段上进行全文搜索。
为此,我使用SOLR查询,如下所示:
fullText
上面的查询使用通配符,它确实起作用并返回我预期的结果。但是我不知道这是否是正确的方法。许多论坛提到搜索查询开始时不支持corpus:*Thermodynamics*
。
另一个观察结果是:如果我只使用语料库中的第一个单词并使用*
进行搜索-它确实起作用。但是,这对于在语料库中稍后出现的单词(即不是在语料库中的第一个单词的所有单词)不起作用
我的印象是SOLR理解空格/换行符将被忽略。
所以-假设语料库具有文本:corpus: Thermodynamics*
。然后,SOLR查询Physics has a specialization for Thermodynamics and Heat
或corpus: Thermodynamics*
应该可以工作,因为本身已经有corpus: Thermodynamics
这个词,SOLR会理解忽略空白应该被忽略。
相反,我必须在搜索字词的开头和结尾都包含通配符Thermodynamics
。
请帮助我解释
1.为什么这种行为如此,尽管论坛声称SOLR不支持搜索词开头的*
。
2.我在*
字段上执行fullText的方式是否正确?
谢谢, 赤丹
答案 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”拆分为三个令牌foo
,bar
和baz
。任何查询都将执行相同的操作,并将令牌与令牌匹配。这就是为什么即使搜索的是bar baz foo
而不是前面相同的序列,也会得到匹配的原因。通常,您还希望至少附加一个LowercaseFilter
,以便进行不区分大小写的搜索-以及其他过滤器,具体取决于您的字段和域的用例。创建多个字段以执行不同的匹配,然后分别权衡它们,以获得对您的用户最有意义的文档评分。
没有这个分析链,我相信您实际上将获得与字符串字段相同的行为。
然后是通配符-如果存在通配符,则会跳过整个分析链。这意味着在文本搜索时使用通配符通常是一个坏主意。除非您尝试匹配单个令牌,否则它不会做您想做的事情(因为存在通配符时将跳过令牌生成器)。因此,您必须谨慎行事,而且您可能最终会遇到“为什么会这样”的情况。
另一种方法是使用NGramFilter,它将单词中的每个字母集分开(foo
变成f
,fo
,foo
,o
,oo
和o
)分成单独的令牌。通常,您只希望在建立索引时执行此操作,因此请为您的字段使用单独的分析链(您可以通过配置中的type
参数进行定义-如果未指定类型,则将使用相同的链进行索引和查询
建议使用前缀通配符(*foo
)的原因是,与检查后缀通配符(foo*
)相比,检查前缀通配符的开销很大。在后缀的情况下,您可以从foo
遍历索引,并继续进行直到遇到不是以foo
开头的内容,而对于*foo
,则必须有效地查看所有索引中的术语,因为没有排序顺序可以使它们反向。
输入Reverse Wildcard Filter-此过滤器的作用是,除了常规标记外,它还会索引反向标记(或仅反向标记)。然后在查询时调用过滤器,并且也反转查询令牌-有效索引oof
,然后在内部查询oof*
。这样,您就可以加快保持该字段的索引排序的速度,而不必查看每个标记。
此过滤器反转令牌以提供更快的前导通配符和前缀查询。没有通配符的令牌不会被撤销。