在应用程序中,我收到一个文本,在该文本上应用过滤器,并且我希望将此过滤后的结果存储到lucene Document对象中。我不在乎原始文本。

String stringToProcess = "...";
TokenStream stream = analyzer.tokenStream(null, new StringReader(stringToProcess));
TokenStream procStream = new CustomFilter(stream, opts);

Document luceneDocument = new Document();
FieldType ft = new FieldType(TextField.TYPE_STORED);
ft.setOmitNorms(false);
ft.setStoreTermVectors(true);
luceneDocument.add(new Field("content", procStream, ft));


这引发:

Exception in thread "main" java.lang.IllegalArgumentException: TokenStream fields cannot be stored


如果将TextField.TYPE_STORED更改为TYPE_NOT_STORED,也不例外。但是,该字段的内容为nullField有一个构造函数,它显然接受TokenStream对象。

我可以使用procStream.incrementToken().getAttribute(ChatTermAttribute.class)手动提取令牌。

我的问题:如何将TokenStream传递给Field对象?

最佳答案

您不能只传递TokenStream并存储字段。

TokenStream是经过分析的可索引令牌的流。字段的存储内容是预分析字符串。您没有将该字符串提供给字段,因此它没有任何适合存储的内容,因此是例外。

取而代之的是,在Analyzer中设置IndexWriterConfig并让其为您分析该字段将更为典型。我猜想您这样做而不是让IndexWriter处理的原因是因为您要将那个CustomFilter添加到开箱即用的分析器中。相反,只需创建自己的自定义Analyzer。分析仪很简单。只需复制要使用的分析仪的源,然后将自定义过滤器添加到createComponents中的链中。说您使用StandardAnalyzer,然后您将更改复制的增量令牌方法,如下所示:



@Override
protected TokenStreamComponents createComponents(final String fieldName) {
  final StandardTokenizer src = new StandardTokenizer();
  src.setMaxTokenLength(maxTokenLength);
  TokenStream tok = new StandardFilter(src);
  tok = new LowerCaseFilter(tok);
  tok = new StopFilter(tok, stopwords);
  tok = new CustomFilter(tok, opts); //Just adding this line
  return new TokenStreamComponents(src, tok) {
    @Override
    protected void setReader(final Reader reader) {
      src.setMaxTokenLength(StandardAnalyzer.this.maxTokenLength);
      super.setReader(reader);
    }
  };
}


然后,您可以像下面那样创建字段:

new Field("content", stringToProcess, ft);




好的,所以我假设这有点XY problem。需要说明的是,创建自定义分析器很可能是更好的解决方案,实际上您可以将TokenStream传递给Field并存储它,您只需要提供存储字符串和tokenstream。看起来像这样:

Field myField = new Field("content", stringToProcess, ft);
myField.setContentStream(procStream);

08-04 09:59