Lucene Index带有“ - ”字符的问题

时间:2012-04-17 07:05:16

标签: java lucene indexing escaping character

我在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”,例如我没有得到结果。 (应该有结果,因为它是用于网上商店的实时搜索)

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

4 个答案:

答案 0 :(得分:16)

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

所以你想要的是“v-strom”作为一个整体成为一个索引术语。 StandardAnalyzer不适合此类文字。也许可以使用WhitespaceAnalyzerSimpleAnalyzer。如果仍然没有削减它,你也可以选择将你自己的分析器组合在一起,或者只是从那两个故事开始,然后用TokenFilters组合它们。 the Lucene Analysis package Javadoc.

给出了一个非常好的解释 BTW没有必要输入索引中的所有变体,比如V-strom,V-Strom等。这个想法是让同一个分析器在索引和解析时将所有这些变体规范化为相同的字符串查询。

答案 1 :(得分:4)

ClassicAnalyzer处理' - '作为有用的非分隔符。据我了解ClassicAnalyzer,它处理' - '就像3.1之前的StandardAnalyzer一样,因为ClassicAnalyzer使用ClassicTokenizer来处理带有嵌入式' - '的数字作为产品代码,所以整个事情被标记为一个术语。

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

答案 2 :(得分:2)

(基于Lucene 4.7)StandardTokenizer将带连字符的单词分为两个。例如,将“聊天室”分为“聊天室”,“房间”并分别索引这两个词,而不是将其作为一个整体进行索引。将单独的单词与连字号联系起来是很常见的:“运动狂”,“准备使用相机”,“快速思考”等等。连字符的名称很大,例如“ Emma-Claire”。在进行全字搜索或查询时,用户希望在这些连字符中找到单词。尽管在某些情况下它们是单独的单词,但这就是为什么lucene会将连字符保留在默认定义之外的原因。

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

请参阅link以获取完整指南。

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

 MidLetterSupp = ( [\u002D]  ) 

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

然后使用该类文件重建索引。

答案 3 :(得分:1)

建议ClassicAnalzer索引包含“GSX-R1000”等产品代码的文本。它会认为这是一个单独的术语,并没有将其部分分开。但是,例如,“欧洲/柏林”文本将由ClassicAnalzer分为“欧洲”和“柏林”。这意味着如果您有包含短语

的ClassicAnalyzer索引的文本
Europe/Berlin GSX-R1000

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

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

(processid:4711) (berlin) 

此查询将使用短语“berlin”搜索文档,但也会搜索包含编号4711的字段“processid”。

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

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

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

此代码将翻译serach pharse

Europe/Berlin

进入

europe berlin

将导致预期的文档集。

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

Europe/Berlin GSX-R1000

将被翻译成:

(europe berlin) GSX-R1000

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