我有一个包含多个字段的大型语料库的索引。这些字段中只有一个包含文本。 我需要根据这个字段从整个索引中提取唯一的单词。 有谁知道我如何用java中的Lucene做到这一点?
答案 0 :(得分:26)
如果您使用的是Lucene 4.0 api,则需要从索引阅读器中获取字段。然后,Fields提供了获取索引中每个字段的术语的方法。以下是如何执行此操作的示例:
Fields fields = MultiFields.getFields(indexReader);
Terms terms = fields.terms("field");
TermsEnum iterator = terms.iterator(null);
BytesRef byteRef = null;
while((byteRef = iterator.next()) != null) {
String term = new String(byteRef.bytes, byteRef.offset, byteRef.length);
}
最后,对于新版本的Lucene,您可以从BytesRef调用中获取字符串:
byteRef.utf8ToString();
而不是
new String(byteRef.bytes, byteRef.offset, byteRef.length);
如果您想获得文档频率,可以执行以下操作:
int docFreq = iterator.docFreq();
答案 1 :(得分:9)
您正在寻找term vectors(字段中所有单词的集合以及每个单词的使用次数,不包括停用词)。您将为索引中的每个文档使用IndexReader的getTermFreqVector(docid, field),并使用它们填充HashSet
。
替代方法是使用terms()并仅选择您感兴趣的字段的字词:
IndexReader reader = IndexReader.open(index);
TermEnum terms = reader.terms();
Set<String> uniqueTerms = new HashSet<String>();
while (terms.next()) {
final Term term = terms.term();
if (term.field().equals("field_name")) {
uniqueTerms.add(term.text());
}
}
这不是最佳解决方案,您正在阅读然后丢弃所有其他字段。 Lucene 4中有一个类Fields
,仅针对单个字段返回terms(field)。
答案 2 :(得分:3)
同样的结果,只是更清洁一点,就是使用LuceneDictionary
包中的lucene-suggest
。它通过返回BytesRefIterator.EMPTY
来处理不包含任何术语的字段。这将为您节省NPE:)
LuceneDictionary ld = new LuceneDictionary( indexReader, "field" );
BytesRefIterator iterator = ld.getWordsIterator();
BytesRef byteRef = null;
while ( ( byteRef = iterator.next() ) != null )
{
String term = byteRef.utf8ToString();
}
答案 3 :(得分:1)
从Lucene 7+开始,以上内容和一些相关链接已过时。
这是最新动态:
// IndexReader has leaves, you'll iterate through those
int leavesCount = reader.leaves().size();
final String fieldName = "content";
for(int l = 0; l < leavesCount; l++) {
System.out.println("l: " + l);
// specify the field here ----------------------------->
TermsEnum terms = reader.leaves().get(l).reader().terms(fieldName).iterator();
// this stops at 20 just to sample the head
for(int i = 0; i < 20; i++) {
// and to get it out, here -->
final Term content = new Term(fieldName, BytesRef.deepCopyOf(terms.next()));
System.out.println("i: " + i + ", term: " + content);
}
}
答案 4 :(得分:0)
使用TermsEnum
和terms.next()
的答案有一个微妙的错误。这是因为TermsEnum
已指向第一个字词,因此while(terms.next())
将导致跳过第一个字词。
而是使用for循环:
TermEnum terms = reader.terms();
for(Term term = terms.term(); term != null; terms.next(), term = terms.term()) {
// do something with the term
}
修改接受答案中的代码:
IndexReader reader = IndexReader.open(index);
TermEnum terms = reader.terms();
Set<String> uniqueTerms = new HashSet<String>();
for(Term term = terms.term(); term != null; terms.next(), term = terms.term()) {
if (term.field().equals("field_name")) {
uniqueTerms.add(term.text());
}
}