2

我试图弄清楚我应该怎么做才能索引包含“。”的关键字。.

例如:this.name

我想索引这些术语:这个和我的索引中的名称。

我使用标准分析仪。我尝试扩展 WhitespaceTokensizer 或扩展 TokenFilter,但我不确定我的方向是否正确。

如果我使用 StandardAnalyser,我将获得“this.name”作为关键字,这不是我想要的,但分析器会为我正确完成其余的工作。

4

4 回答 4

7

您可以在 StandardTokenizer 前面放置一个 CharFilter,它将句点和下划线转换为空格。MappingCharFilter 将起作用。

这是添加到精简的 StandardAnalyzer 的 MappingCharFilter(请参阅此处的原始 4.1 版本):

import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.charfilter.MappingCharFilter;
import org.apache.lucene.analysis.charfilter.NormalizeCharMap;
import org.apache.lucene.analysis.core.LowerCaseFilter;
import org.apache.lucene.analysis.core.StopAnalyzer;
import org.apache.lucene.analysis.core.StopFilter;
import org.apache.lucene.analysis.standard.StandardFilter;
import org.apache.lucene.analysis.standard.StandardTokenizer;
import org.apache.lucene.analysis.util.StopwordAnalyzerBase;
import org.apache.lucene.util.Version;

import java.io.IOException;
import java.io.Reader;

public final class MyAnalyzer extends StopwordAnalyzerBase {
  private int maxTokenLength = 255;
  public MyAnalyzer() {
    super(Version.LUCENE_41, StopAnalyzer.ENGLISH_STOP_WORDS_SET);
  }

  @Override
  protected TokenStreamComponents createComponents
      (final String fieldName, final Reader reader) {
    final StandardTokenizer src = new StandardTokenizer(matchVersion, reader);
    src.setMaxTokenLength(maxTokenLength);
    TokenStream tok = new StandardFilter(matchVersion, src);
    tok = new LowerCaseFilter(matchVersion, tok);
    tok = new StopFilter(matchVersion, tok, stopwords);
    return new TokenStreamComponents(src, tok) {
      @Override
      protected void setReader(final Reader reader) throws IOException {
        src.setMaxTokenLength(MyAnalyzer.this.maxTokenLength);
        super.setReader(reader);
      }
    };
  }

  @Override
  protected Reader initReader(String fieldName, Reader reader) {
    NormalizeCharMap.Builder builder = new NormalizeCharMap.Builder();
    builder.add(".", " ");
    builder.add("_", " ");
    NormalizeCharMap normMap = builder.build();
    return new MappingCharFilter(normMap, reader);
  }
}

这是一个快速测试来证明它是有效的:

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.BaseTokenStreamTestCase;

public class TestMyAnalyzer extends BaseTokenStreamTestCase {
  private Analyzer analyzer = new MyAnalyzer();

  public void testPeriods() throws Exception {
    BaseTokenStreamTestCase.assertAnalyzesTo
    (analyzer, 
     "this.name; here.i.am; sentences ... end with periods.",
     new String[] { "name", "here", "i", "am", "sentences", "end", "periods" } );
  }

  public void testUnderscores() throws Exception {
    BaseTokenStreamTestCase.assertAnalyzesTo
        (analyzer,
         "some_underscore_term _and____ stuff that is_not in it",
         new String[] { "some", "underscore", "term", "stuff" } );
  }
}
于 2013-03-06T06:51:51.400 回答
0

您被此处记录的行为所吸引:

但是,后面没有空格的点被视为标记的一部分。

StandardTokenizer引入了一些比您可能不想要的更复杂的解析规则。尤其是这个,旨在防止对 URL、IP、标识符等进行标记化。更简单的实现可能会满足您的需求,例如LetterTokenizer.

如果这不能真正满足您的需求(结果很可能是把婴儿和洗澡水一起扔出去),那么您可能需要修改StandardTokenizer自己,Lucene 文档明确鼓励这样做:

许多应用程序都有特定的标记器需求。如果此分词器不适合您的应用程序,请考虑将此源代码目录复制到您的项目并维护您自己的基于语法的分词器。

于 2013-03-05T22:41:29.710 回答
0

Sebastien Dionne:我不明白如何拆分单词,我必须逐个 char 解析文档吗?

Sebastien Dionne:我仍然想知道如何将令牌拆分为多个部分,并将它们全部索引


您可能必须编写自定义分析器。

Analyzer 是 Tokenizer 和可能的 TokenFilter 实例链的组合。

Tokenizer :接收您可能作为 java.io.Reader 传递的输入文本。它
只是分解文本。不改变,只是分解。

TokenFilter : 接受 Tokenizer 发出的令牌,添加/删除/更改令牌并一一发出相同的令牌,直到全部完成。

如果它根据要求用多个令牌替换一个令牌,则将所有令牌缓冲,将它们一一发送到索引器。

您可以查看以下资源,不幸的是,您可能需要注册试用会员资格。

通过编写自定义分析器,您可以按照自己的方式分解文本。您甚至可以使用一些现有的组件,例如 LowercaseFilter。幸运的是,如果您无法在内置或 Web 上找到它,则可以使用 Lucene 提供一些可以满足您的目的的分析器。

编写自定义过滤器:Lucene in Action 2

于 2013-03-06T02:49:31.500 回答
0

如果我理解正确,您需要使用删除点的标记器 - 也就是说,任何包含点的名称都应在该点拆分(“here.i.am”变为“here”+“i”+“是”)。

于 2013-03-05T22:23:58.553 回答