Solr 通配符搜索不正确的结果

Solr wildcard search incorrect result

我在进行通配符查询时得到了一些意想不到的结果。我正在使用 solr 6.6.0。 solr ui 中的 edismax 处理程序。以下查询 return 在没有通配符的情况下按预期结果 - firstNames:James,但是当我添加通配符时没有找到结果。 对于 firstNames 字段,我使用默认的 fieldType text_en 和默认的分词器和过滤器。当我 运行 对 firstNames:Stephen 和 firstNames:Stephen* 的完全相同的查询时,我在通配符搜索和非通配符搜索中都得到了结果。下面是我的字段 xml inside schema.xml:

  <field name="firstNames" type="text_en" multiValued="true" indexed="true" stored="true"/>
  <fieldType name="text_en" class="solr.TextField" positionIncrementGap="100">
    <analyzer type="index">
      <tokenizer class="solr.StandardTokenizerFactory"/>
      <filter class="solr.StopFilterFactory" words="lang/stopwords_en.txt" ignoreCase="true"/>
      <filter class="solr.LowerCaseFilterFactory"/>
      <filter class="solr.EnglishPossessiveFilterFactory"/>
      <filter class="solr.KeywordMarkerFilterFactory" protected="protwords.txt"/>
      <filter class="solr.PorterStemFilterFactory"/>
    </analyzer>
    <analyzer type="query">
      <tokenizer class="solr.StandardTokenizerFactory"/>
      <filter class="solr.SynonymFilterFactory" expand="true" ignoreCase="true" synonyms="synonyms.txt"/>
      <filter class="solr.StopFilterFactory" words="lang/stopwords_en.txt" ignoreCase="true"/>
      <filter class="solr.LowerCaseFilterFactory"/>
      <filter class="solr.EnglishPossessiveFilterFactory"/>
      <filter class="solr.KeywordMarkerFilterFactory" protected="protwords.txt"/>
      <filter class="solr.PorterStemFilterFactory"/>
    </analyzer>
  </fieldType>
  1. 不要删除停用词。这是 1970 年代的 space 节省技巧。它使某些词无法搜索,因此像“vitamin a”这样的查询永远不会起作用,因为“a”是停用词。这是一个博客 post 列出了 100% 停用词的电影片名。

https://observer.wunderwood.org/2007/05/31/do-all-stopword-queries-matter/

  1. 不要对词干使用通配符。这将显示词干上的匹配项,而不是表面词。您想要一个仅包含小写过滤器的单独字段。

  2. 不要在人名上使用词干提取。例如,您不想将“Steve Jobs”改为“steve job”或将“william golding”改为“william gold”。

  3. 更好的是,使用 ICU 折叠过滤器而不是小写。

https://lucene.apache.org/solr/guide/8_7/filter-descriptions.html#icu-folding-filter

当您进行通配符查询时,未调用分析链(好吧,这是一个小谎言 - 它是,但只有 MultiTermAware 的组件 - 通常意味着 LowercaseFilter 是唯一仍然处于活动状态的东西)。

由于您有一个词干过滤器和附加的所有格过滤器,James 上的结尾 s 被删除。由于这只发生在索引时间(请记住,当您使用通配符时,分析链通常会在查询时跳过),令牌 jame 存储在索引中。

当您进行查询 firstNames:James* 时,您要求 Solr“查找包含以 James 开头的标记的任何文档。由于存储的是标记 jame,因此没有匹配 james.

的标记

当您使用 Stephen 尝试此操作时,词干提取或所有格过滤器都不会删除单词的结尾,因此 Stephen* 会查找任何以 stephen 开头的标记,并且自那以后存在令牌(没有任何改变),返回匹配项。

解决方案取决于您的用例;不需要在名称字段上使用词干提取或所有格过滤器,因为这对名称没有实际意义(相反,您可以应用自己的逻辑来匹配类似的名称)。另一种选择是改用 ngramfilter,为令牌的每个前缀和中缀版本有效地生成一个令牌(fooffoooo).

关于停用词,对“我必须使用停用词吗”这个问题的回答不是“是”或“否”。这是“为什么不”,而是根据您的数据智能地进行。 对于药物数据库,“a”、“b”、“c”……不应出现在停用词定义文件中。 对于 100% 停用词数据库的电影片名,标题字段不能使用停用词,但也许描述字段应该。