6

我想构建我自己的 - 这里不确定是哪一个 - 标记器(从 Lucene 的角度来看)或我自己的分析器。我已经编写了一个代码,用 word 标记我的文档(作为 List < String > 或 List < Word >,其中Word是一个类,只有一种具有 3 个 public String 的容器:word、pos、lemma - pos 代表部分词性标签)。

我不确定要索引什么,可能只有“ Word.lemma ”或类似“ Word.lemma + '#' + Word.pos ”的东西,可能我会根据部分从停用词列表中进行一些过滤演讲。

顺便说一句,这是我的误解:我不确定应该在哪里插入 Lucene API,

我应该将自己的标记器包装在新的标记器中吗?我应该重写 TokenStream 吗?我应该认为这是分析器而不是标记器的工作吗?还是我应该绕过所有内容并通过使用 IndexWriter、Fieldable 等直接在索引中添加我的单词来直接构建我的索引?(如果是这样,您是否知道有关在绕过分析过程时如何从头开始创建自己的索引的任何文档)

此致

编辑:可能是最简单的方法应该是 org.apache.commons.lang.StringUtils.join 我的Word -s,在我的个人标记器/分析器的出口有一个空格,并依靠 WhiteSpaceTokenizer 来提供 Lucene(和其他经典过滤器) ?

编辑:所以,我已经阅读了 Larsmans指出的EnglishLemmaTokenizer ...但我仍然感到困惑的是,我以完整的 *List < Word > * (Word类包装.form/. pos/.lemma),这个过程依赖于我用 Java 包装的外部二进制文件(这是必须做的/不能做的 - 它不是从消费者的角度来看,结果我得到了完整的列表)我仍然不明白我应该如何再次包装它以回到正常的 Lucene 分析过程。

我还将使用带有 TF.IDF 的 TermVector 功能,例如评分(可能是重新定义我自己的),我也可能对邻近搜索感兴趣,因此,在将它们提供给 Lucene 之前从它们的词性中丢弃一些词内置标记器或内部分析器可能看起来是个坏主意。而且我很难想到将 Word.form / Word.pos / Word.lemma(甚至其他 Word.anyOtherUnterestingAttribute)包装到 Lucene 方式的“正确”方式。

编辑: 顺便说一句,这是我写的一段代码,灵感来自@Larsmans:

class MyLuceneTokenizer extends TokenStream {

    private PositionIncrementAttribute posIncrement;
    private CharTermAttribute termAttribute;

    private List<TaggedWord> tagged;
    private int position;

    public MyLuceneTokenizer(Reader input, String language, String pathToExternalBinary) {
        super();

        posIncrement = addAttribute(PositionIncrementAttribute.class);
        termAttribute = addAttribute(CharTermAttribute.class); // TermAttribute is deprecated!

        // import com.google.common.io.CharStreams;            
        text = CharStreams.toString(input); //see http://stackoverflow.com/questions/309424/in-java-how-do-i-read-convert-an-inputstream-to-a-string
        tagged = MyTaggerWrapper.doTagging(text, language, pathToExternalBinary);
        position = 0;
    }

    public final boolean incrementToken()
            throws IOException {
        if (position > tagged.size() -1) {
            return false;
        }

        int increment = 1; // will probably be changed later depending upon any POS filtering or insertion @ same place...
        String form = (tagged.get(position)).word;
        String pos = (tagged.get(position)).pos;
        String lemma = (tagged.get(position)).lemma;

        // logic filtering should be here...
        // BTW we have broken the idea behing the Lucene nested filters or analyzers! 
        String kept = lemma;

        if (kept != null) {
            posIncrement.setPositionIncrement(increment);
            char[] asCharArray = kept.toCharArray();
            termAttribute.copyBuffer(asCharArray, 0, asCharArray.length);
            //termAttribute.setTermBuffer(kept);
            position++;
        }

        return true;
    }
}

class MyLuceneAnalyzer extends Analyzer {
    private String language;
    private String pathToExternalBinary;

    public MyLuceneAnalyzer(String language, String pathToExternalBinary) {
        this.language = language;
        this.pathToExternalBinary = pathToExternalBinary;
    }

    @Override
    public TokenStream tokenStream(String fieldname, Reader input) {
        return new MyLuceneTokenizer(input, language, pathToExternalBinary);
    }
}
4

2 回答 2

1

There are various options here, but when I tried to wrap a POS tagger in Lucene, I found that implementing a new TokenStream and wrapping that inside a new Analyzer was the easiest option. In any case, mucking with IndexWriter directly seems like a bad idea. You can find my code on my GitHub.

于 2012-05-18T09:02:36.663 回答
1

如果你想使用 UIMA,Salmon Run 有一个例子。但是在 Lucene contrib 模块中努力包含 UIMA 工作流,请参见此处此处

于 2012-09-10T07:38:06.400 回答