Solr 不在查询中连接单词

Solr is not concatenating words in a query

我在使用 Solr 时遇到问题。我希望它连接搜索查询中的单词。例如,我希望能够搜索 "data link" 并让它找到包含 "datalink" 的文档(Google 可以做到这一点——那么为什么这对 Solr 如此困难?)。

以下是 schema.xml 中的索引和查询分析器设置:

<fieldType name="text_en_splitting" class="solr.TextField" positionIncrementGap="100" autoGeneratePhraseQueries="true">
  <analyzer type="index">
    <tokenizer class="solr.WhitespaceTokenizerFactory"/>
    <filter class="solr.StopFilterFactory"
            ignoreCase="true"
            words="lang/stopwords_en.txt"
            />
    <filter class="solr.WordDelimiterFilterFactory"
            generateWordParts="1" 
            generateNumberParts="1" 
            catenateWords="0" 
            catenateNumbers="0" 
            catenateAll="0" 
            splitOnCaseChange="1"
            />
    <filter class="solr.LowerCaseFilterFactory"/>
    <filter class="solr.KeywordMarkerFilterFactory" protected="protwords.txt"/>
    <filter class="solr.PorterStemFilterFactory"/>
  </analyzer>
  <analyzer type="query">
    <tokenizer class="solr.WhitespaceTokenizerFactory"/>
    <filter class="solr.SynonymFilterFactory" 
            synonyms="synonyms.txt" 
            ignoreCase="true" 
            expand="true"
            />
    <filter class="solr.StopFilterFactory"
            ignoreCase="true"
            words="lang/stopwords_en.txt"
            />
    <filter class="solr.WordDelimiterFilterFactory"
            generateWordParts="1" 
            generateNumberParts="1" 
            catenateWords="1" 
            catenateNumbers="0" 
            catenateAll="0" 
            splitOnCaseChange="1"
            />
    <filter class="solr.LowerCaseFilterFactory"/>
    <filter class="solr.KeywordMarkerFilterFactory" protected="protwords.txt"/>
    <filter class="solr.PorterStemFilterFactory"/>
  </analyzer>
</fieldType>

这是我搜索时 debugQuery 的输出 "data link":

"rawquerystring": "\"data link\"\n",
"querystring": "\"data link\"\n",
"parsedquery": "PhraseQuery(text:\"data link\")",
"parsedquery_toString": "text:\"data link\"",

这是我搜索 "data-link" 时 debugQuery 的输出——这也没有命中 "datalink",即使它似乎存在于 MultiPhraseQuery 中?有人可以解释一下吗?

"rawquerystring": "\"data-link\"\n",
"querystring": "\"data-link\"\n",
"parsedquery": "MultiPhraseQuery(text:\"(data datalink) link\")",
"parsedquery_toString": "text:\"(data datalink) link\"",

这是一个非常复杂的基础,但这里发生的大部分事情似乎是由于 WordDelimiterFilter 及其参数 generateWordPartsconcatentateWords。在索引中你正在生成部分,但不是连接,但在查询中你正在做这两个部分。

索引时

  1. "Data Link":不管怎样,这将作为两个单独的词被索引。 WordDelimiterFilter 不会再猜测什么已经是两个单独的词。
  2. "Data-Link":这是模棱两可的,可能是一两个词。由于您的索引分析指定 generateWordParts,因此索引为 "data link".

搜索时

  1. "Data Link"":这是两个独立的词,就像索引时一样,查询时 WordDelimiterFilter这个不改,还是两个字

  2. "Data-Link": 搜索分析的配置与索引分析不同,所以这两个都被搜索为 "data link" 和 "datalink".

结果?

您对 "data-link" 的搜索确实搜索了词条 "datalink",但您索引的值只会被索引为 "datalink",如果它们在首先,因为你在索引时从不激活 concatenateWords

您可以选择做的一件事是 select concatenateWords generateWordParts,并为字段,无论是在索引时还是在搜索时。我选择的另一种选择是在 schema.xml 中使用 <copyField/> 来复制生成单词部分的字段和连接单词的字段之间的值。至少,我发现尝试在单个字段中同时进行连接和部分操作会对短语搜索造成严重破坏,因为当无法清楚地计算术语时,单个术语的位置编号会出现问题。

但是,如果您希望在搜索 data [=110= 时可以找到 datalink 一词的文档],那么 WordDelimiterFilter 将无济于事,因为它永远不会将 datalink 视为两个词的候选者,或者数据link作为一个词的候选。它的专长在于由连字符和撇号等引起的歧义情况。

相反,您可能需要构建自己的逻辑查询。 (逻辑运算符在 Standard/Lucene 查询处理程序和 Extended-Dismax 查询处理程序中工作,但不在 Dismax 查询处理程序中工作。)这种查询会很快变得复杂,但是像 (+data +link) OR datalink 这样的东西是一个很好的查询第一步。如果包含三个术语,则很难知道哪些可能会被串联起来,因此 datalinkcisco OR (+datalink +cisco) OR (+data +linkcisco) OR (+data +link +cisco) 之类的查询可能会开始发挥作用。 (用四个术语想象一下!)

这会变得非常复杂,速度非常快,如果只有少数情况的术语可能只在某些时候连接,您可以尝试使用 SynonymFilter。这允许使用如下规则建立同义词文件:

data link => datalink

这样 "data link" 的所有实例都将作为 "datalink" 被索引或查询(根据配置)。这可以规范化特定的搜索词,而无需打开我们根本不相信用户知道空间所属位置的蠕虫罐头。

SynonymFilters 可以用于其他事情。例如,如果您从搜索索引中过滤掉标点符号,"C++" 和 "C" 可能最终看起来等同于 Solr。使用同义词规则:

C++ => cplusplus

这最终完全不同。 (当然,没有人会搜索 cplusplus,但是如果您将相同的转换应用于索引文档中的 "C++" 和用户查询中的 ,那么他们永远不会知道 "cplusplus" 是实际匹配的值。)

要允许 data linkdatalink 匹配,您必须将 ShingleFilter 添加到索引器和查询链中:

https://cwiki.apache.org/confluence/display/solr/Filter+Descriptions#FilterDescriptions-ShingleFilter

您可以将其与 WordDelimiterFilter 结合使用。

要减少生成但可能无用的令牌数量,您可以添加 LengthFiltermin=2 以及一些合理的最大值。例如,WDF 可以从 "iPhone6s" 生成:"i"、"Phone"、“6”、"s"(以及更多取决于配置)。

此外,RemoveDuplicateTokensFilter 可以添加到该链的最后:

https://cwiki.apache.org/confluence/display/solr/Filter+Descriptions#FilterDescriptions-RemoveDuplicatesTokenFilter