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>
您可以看到我已将 corpus
和 fullText
字段定义为类型 solr.TextField
。这两个字段都有很多文本数据。
我打算对 corpus
或 fullText
字段进行全文搜索。
为此,我使用 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" 拆分为三个标记,foo
、bar
和 baz
。任何查询都会执行相同的操作,并为令牌匹配令牌。这就是为什么你会得到一个匹配,即使搜索是 bar baz foo
而不是与之前相同的序列。您通常还希望至少附加一个 LowercaseFilter
,以便您进行不区分大小写的搜索 - 以及任何更多过滤器,具体取决于您的领域和域的用例。创建多个字段以执行不同的匹配,并分别权衡它们以获得对您的用户最有意义的文档评分。
如果没有这个分析链,我相信您实际上会得到与字符串字段相同的行为。
然后是通配符 - 如果存在通配符,则跳过整个分析链。这意味着在搜索文本时使用通配符通常不是一个好主意。它不会像你想的那样做,除非你试图匹配单个标记(因为当存在通配符时 Tokenizer 将被跳过)。因此,您必须谨慎行事,而且您最终可能会 "why did this happen" 的次数更多。
另一种方法是使用 NGramFilter,它将单词中的每组字母拆分(foo
变为 f
、fo
、foo
、o
、oo
和 o
) 到单独的标记中。你通常只想在索引时这样做,所以为你的字段使用单独的分析链(你通过配置中的 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.
我在我正在处理的项目中使用 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>
您可以看到我已将 corpus
和 fullText
字段定义为类型 solr.TextField
。这两个字段都有很多文本数据。
我打算对 corpus
或 fullText
字段进行全文搜索。
为此,我使用 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" 拆分为三个标记,foo
、bar
和 baz
。任何查询都会执行相同的操作,并为令牌匹配令牌。这就是为什么你会得到一个匹配,即使搜索是 bar baz foo
而不是与之前相同的序列。您通常还希望至少附加一个 LowercaseFilter
,以便您进行不区分大小写的搜索 - 以及任何更多过滤器,具体取决于您的领域和域的用例。创建多个字段以执行不同的匹配,并分别权衡它们以获得对您的用户最有意义的文档评分。
如果没有这个分析链,我相信您实际上会得到与字符串字段相同的行为。
然后是通配符 - 如果存在通配符,则跳过整个分析链。这意味着在搜索文本时使用通配符通常不是一个好主意。它不会像你想的那样做,除非你试图匹配单个标记(因为当存在通配符时 Tokenizer 将被跳过)。因此,您必须谨慎行事,而且您最终可能会 "why did this happen" 的次数更多。
另一种方法是使用 NGramFilter,它将单词中的每组字母拆分(foo
变为 f
、fo
、foo
、o
、oo
和 o
) 到单独的标记中。你通常只想在索引时这样做,所以为你的字段使用单独的分析链(你通过配置中的 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.