18

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

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

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

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

这里有一个例子:

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

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

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

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

4

4 回答 4

18

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

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

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

于 2012-04-17T07:42:20.947 回答
4

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 构建了索引)。

于 2012-04-17T20:48:36.103 回答
3

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

要在 中支持连字符StandardAnalyzer,您必须更改StandardTokenizerImpl.javajFlex生成的类。

请参阅此链接以获取完整指南。

您必须添加文件SUPPLEMENTARY.jflex-macro包含的以下行StandardTokenizerImpl.jflex

 MidLetterSupp = ( [\u002D]  ) 

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

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

于 2018-10-12T15:10:41.900 回答
1

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

Europe/Berlin GSX-R1000

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

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

(processid:4711) (berlin) 

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

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

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

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 正确搜索所有组合的短语。

于 2016-07-14T06:21:40.600 回答