“-”字符的 Lucene 索引问题

Posted

技术标签:

【中文标题】“-”字符的 Lucene 索引问题【英文标题】:Lucene Index problems with "-" character 【发布时间】:2012-04-28 12:34:10 【问题描述】:

我在使用 Lucene 索引时遇到问题,该索引的索引词包含“-”字符。

它适用于某些包含“-”的单词,但不适用于所有单词,我找不到原因,为什么它不起作用。

我正在搜索的字段经过分析并包含带有和不带有“-”字符的单词的版本。

我正在使用分析器:org.apache.lucene.analysis.standard.StandardAnalyzer

这里是一个例子:

如果我搜索“gsx-*”我得到一个结果,索引字段包含 “铃木 GSX-R 1000 GSX-R1000 GSXR”

但如果我搜索“v-*”,我没有得到任何结果。预期结果的索引字段包含: “铃木 DL 1000 V-STROM DL1000V-STROMVSTROM V STROM”

如果我在没有“*”的情况下搜索“v-strom”,它可以工作,但如果我只搜索“v-str”,例如我不会得到结果。 (应该有结果,因为它是针对网上商店的实时搜索)

那么,两个预期结果之间有什么区别?为什么它适用于“gsx-”而不适用于“v-”?

【问题讨论】:

有趣,我使用 Solr 并驱动 V-Strom 650 :) 您是否真的检查过索引字段的内容,或者您​​只是希望它是这样的?如果不使用有史以来最强大的 Lucene 索引工具 - Luke:code.google.com/p/luke 是的,我显示的字段与我正在搜索的字段相同 【参考方案1】:

(基于 Lucene 4.7)StandardTokenizer 将带连字符的单词一分为二。例如,将“chat-room”转换为“chat”、“room”并分别索引这两个单词,而不是索引为一个完整的单词。单独的词用连字符连接是很常见的:“sport-mad”、“camera-ready”、“quick-thinking”等等。很大一部分是连字符的名称,例如“Emma-Claire”。在进行全词搜索或查询时,用户希望在这些连字符中找到单词。虽然在某些情况下它们是单独的单词,但这就是 lucene 将连字符保留在默认定义之外的原因。

要在StandardAnalyzer 中支持连字符,您必须在StandardTokenizerImpl.java 中进行更改,它是从jFlex 生成的类。

请参阅此link 以获取完整指南。 您必须在SUPPLEMENTARY.jflex-macro 中添加以下行,该行包含在StandardTokenizerImpl.jflex 文件中。

 MidLetterSupp = ( [\u002D]  ) 

在进行更改后,提供StandardTokenizerImpl.jflex 文件作为 jFlex 引擎的输入,然后单击生成。其输出将是StandardTokenizerImpl.java

并使用该类文件重建索引。

【讨论】:

【参考方案2】:

建议使用 ClassicAnalzer 索引包含产品代码(如“GSX-R1000”)的文本。它将将此视为一个单独的术语,并且不会拆分其部分。但是,例如文本“Europe/Berlin”将被 ClassicAnalzer 拆分为“Europe”和“Berlin”两个词。这意味着如果您有一个由 ClassicAnalyzer 索引的文本,其中包含短语

Europe/Berlin GSX-R1000

您可以搜索“欧洲”、“柏林”或“GSX-R1000”。

但请注意您用于搜索的分析器。我认为搜索 Lucene 索引的最佳选择是 KeywordAnalyzer。使用 KeywordAnalyzer,您还可以搜索文档中的特定字段,并且可以构建复杂的查询,例如:

(processid:4711) (berlin) 

此查询将搜索带有短语“berlin”的文档以及包含数字 4711 的字段“processid”。

但是,如果您在索引中搜索短语“europe/berlin”,您将得不到任何结果!这是因为 KeywordAnalyzer 没有更改您的搜索词组,但 ClassicAnalyzer 将词组“Europe/Berlin”分成了两个单独的词。这意味着您必须分别搜索“欧洲”和“柏林”。

要解决此冲突,您可以使用以下代码在适合您需要的搜索查询中翻译用户输入的搜索词:

QueryParser parser = new QueryParser("content", new ClassicAnalyzer());
Query result = parser.parse(searchTerm);
searchTerm = result.toString("content");

此代码将翻译 serach 短语

Europe/Berlin

进入

europe berlin

这将产生预期的文档集。

注意:这也适用于更复杂的情况。搜索词

Europe/Berlin GSX-R1000

将被翻译成:

(europe berlin) GSX-R1000

这将使用 KeyWordAnalyzer 正确搜索所有组合的短语。

【讨论】:

【参考方案3】:

ClassicAnalyzer 将“-”作为有用的非分隔符处理。据我了解 ClassicAnalyzer,它像 3.1 之前的 StandardAnalyzer 一样处理“-”,因为 ClassicAnalyzer 使用 ClassicTokenizer 将带有嵌入“-”的数字视为产品代码,因此整个事物被标记为一个术语。

当我在 Regenstrief Institute 时,我在升级 Luke 后注意到了这一点,因为 LOINC 标准医学术语(LOINC 由 RI 发起)由一个数字标识,后跟一个“-”和一个校验位,例如“1-8”或“2857-1”。我在 Luke 3.5.0 中使用 StandardAnalyzer 搜索诸如“45963-6”之类的 LOINC 失败,但使用 ClassicAnalyzer 成功(这是因为我们使用 2.9.2 Lucene.NET 构建了索引)。

【讨论】:

我刚刚尝试过,从 Lucene 4.0.0 开始,WhitespaceAnalyzer 不会删除连字符,但标准和经典会删除。【参考方案4】:

我相信,StandardAnalyzer 会将连字符视为空格。因此,它会将您的查询 "gsx-*" 变成 "gsx*""v-*" 变成空,因为 at 也消除了单字母标记。您在搜索结果中看到的字段内容是该字段的存储值,它完全独立于为该字段编制索引的术语。

所以你想要的是将“v-strom”作为一个整体作为一个索引词。 StandardAnalyzer 不适合这种文本。不妨试试WhitespaceAnalyzerSimpleAnalyzer。如果这仍然不能解决问题,您还可以选择将自己的分析仪放在一起,或者只是从这两个开始并用进一步的TokenFilters 组合它们。 the Lucene Analysis package Javadoc.中给出了很好的解释

顺便说一句,不需要在索引中输入所有变体,例如 V-strom、V-Strom 等。这个想法是让同一个分析器在索引中和解析时将所有这些变体标准化为相同的字符串查询。

【讨论】:

感谢您的帮助,我知道显示的值与搜索/索引字段无关,但为了测试,我显示了我正在搜索的字段。我还使用卢克进行测试和分析问题。所以我真正需要的是,客户可以输入 v- 并获得所有以 v- 开头的结果。我需要改变什么,它有效吗?我只需要正确的语法,这样我就可以更改客户的查询 我对 Solr 有点生疏,但我会先在您的架构中添加一个附加字段(例如 product_name),您应该只使用小写(字段类型 = 小写)。将此字段 (OR) 添加到您的搜索请求网址中,作为具有更高权重的附加参数。 product_name 这个字段应该是什么类型的语法/值?与实际索引字段中的内容相同?也可以更改索引字段的值,因为我可以将其更改为例如“V-STROM v-strom vstrom v strom V STROM”,值的更改可以提供解决方案吗?唯一固定的是,当客户在搜索字段中输入“v-str”或“v-”等时,应该能够找到结果。 @Zteve ADDITIONAL 字段应包含产品名称(您说过要作为前缀搜索的名称)并且类型为“小写”,这将自行处理您的所有其他问题。 嗯,是的,如果您可以接受任何可以分析到“strom”的内容,那么就是这样。但是如果通过查询“x-strom”你不想要“v-strom”的结果,那么就有问题了。最初的问题甚至不涉及“strom”部分。

以上是关于“-”字符的 Lucene 索引问题的主要内容,如果未能解决你的问题,请参考以下文章

通过将字段存储为字节而不是数十亿文档的字符串,将在 Lucene 索引中优化多少空间和处理

lucene中分词和索引的区别

Lucene的数值索引以及范围查询

Hi:Lucene!

1.Lucene简介

Lucene,内存中字符串的相关性/得分