【问题标题】:Lucene: how to preserve whitespaces etc when tokenizing stream?Lucene:标记流时如何保留空格等?
【发布时间】:2012-02-09 21:06:28
【问题描述】:

我正在尝试对各种文本流进行“翻译”。更具体地说,我需要对输入流进行标记,在专门的字典中查找每个术语并输出标记的相应“翻译”。但是,我还想保留输入中的所有原始空格、停用词等,以便输出以与输入相同的方式格式化,而不是最终成为翻译流。所以如果我的输入是

Term1:Term2 停用词!第三学期 第四学期

然后我希望输出看起来像

Term1': Term2' 停用词!第三学期' 第四学期'

(其中 Termi'Termi 的翻译)而不是简单的

Term1' Term2' Term3' Term4'

目前我正在做以下事情:

PatternAnalyzer pa = new PatternAnalyzer(Version.LUCENE_31,
                             PatternAnalyzer.WHITESPACE_PATTERN,
                             false, 
                             WordlistLoader.getWordSet(new File(stopWordFilePath)));
TokenStream ts = pa.tokenStream(null, in);
CharTermAttribute charTermAttribute = ts.getAttribute(CharTermAttribute.class);

while (ts.incrementToken()) { // loop over tokens
     String termIn = charTermAttribute.toString(); 
     ...
}

但是,这当然会丢失所有空格等。如何修改它以便能够将它们重新插入输出中?非常感谢!

============更新!

我尝试将原始流拆分为“单词”和“非单词”。它似乎工作正常。不过,不确定这是否是最有效的方法:

public ArrayList splitToWords(String sIn) {

if (sIn == null || sIn.length() == 0) {
    return null;
}

char[] c = sIn.toCharArray();
ArrayList<Token> list = new ArrayList<Token>(); 
int tokenStart = 0;
boolean curIsLetter = Character.isLetter(c[tokenStart]);
for (int pos = tokenStart + 1; pos < c.length; pos++) {
    boolean newIsLetter = Character.isLetter(c[pos]);
    if (newIsLetter == curIsLetter) {
        continue;
    }
    TokenType type = TokenType.NONWORD;
    if (curIsLetter == true)
    {
        type = TokenType.WORD;
    }

    list.add(new Token(new String(c, tokenStart, pos - tokenStart),type));
    tokenStart = pos;

    curIsLetter = newIsLetter;
}
TokenType type = TokenType.NONWORD;
if (curIsLetter == true)
{
    type = TokenType.WORD;
}
list.add(new Token(new String(c, tokenStart, c.length - tokenStart),type));

return list;

}

【问题讨论】:

  • 你在翻译一段文字,但这与 Lucene 有什么关系?!
  • @milan 实际翻译是通过搜索由 Lucene 索引的字典完成的
  • 我对任何生成带有“缺失标记”的标记流的标记器进行了包装。它是一个更大的项目的一部分,还没有开源,所以如果你想要的话,请告诉我。

标签: lucene tokenize stop-words


【解决方案1】:

嗯,它并没有真正失去空格,你仍然有你的原始文本:)

所以我认为你应该使用 OffsetAttribute,它将每个术语的 startOffset() 和 endOffset() 包含到你的原始文本中。这就是 lucene 使用的方法,例如,从原始文本中突出显示搜索结果的 sn-ps。

我写了一个快速测试(使用 EnglishAnalyzer)来演示: 输入是:

Just a test of some ideas. Let's see if it works.

输出是:

just a test of some idea. let see if it work.

// just for example purposes, not necessarily the most performant.
public void testString() throws Exception {
  String input = "Just a test of some ideas. Let's see if it works.";
  EnglishAnalyzer analyzer = new EnglishAnalyzer(Version.LUCENE_35);
  StringBuilder output = new StringBuilder(input);
  // in some cases, the analyzer will make terms longer or shorter.
  // because of this we must track how much we have adjusted the text so far
  // so that the offsets returned will still work for us via replace()
  int delta = 0;

  TokenStream ts = analyzer.tokenStream("bogus", new StringReader(input));
  CharTermAttribute termAtt = ts.addAttribute(CharTermAttribute.class);
  OffsetAttribute offsetAtt = ts.addAttribute(OffsetAttribute.class);
  ts.reset();
  while (ts.incrementToken()) {
    String term = termAtt.toString();
    int start = offsetAtt.startOffset();
    int end = offsetAtt.endOffset();
    output.replace(delta + start, delta + end, term);
    delta += (term.length() - (end - start));
  }
  ts.close();

System.out.println(output.toString());

}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-03-21
    • 2020-10-29
    • 2011-06-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多