2012-01-08 9 views
4

私はLucene 3.5.0を使用しており、各文書の用語ベクトルを出力したいと考えています。たとえば、すべてのドキュメントとそれぞれの特定のドキュメントの用語の頻度を知りたいとします。 私のインデックスコードは次のとおりです。Luceneで文書用語ベクトルを抽出する方法3.5.0

import java.io.FileFilter; 
import java.io.FileReader; 
import java.io.IOException; 

import java.io.File; 
import java.io.FileReader; 
import java.io.BufferedReader; 

import org.apache.lucene.index.IndexWriter; 
import org.apache.lucene.document.Field; 
import org.apache.lucene.document.Document; 
import org.apache.lucene.store.RAMDirectory; 
import org.apache.lucene.analysis.standard.StandardAnalyzer; 
import org.apache.lucene.store.Directory; 
import org.apache.lucene.store.FSDirectory; 
import org.apache.lucene.util.Version; 

public class Indexer { 
public static void main(String[] args) throws Exception { 
     if (args.length != 2) { 
     throw new IllegalArgumentException("Usage: java " + Indexer.class.getName() + " <index dir> <data dir>"); 
    } 

    String indexDir = args[0]; 
    String dataDir = args[1]; 
    long start = System.currentTimeMillis(); 
    Indexer indexer = new Indexer(indexDir); 
    int numIndexed; 
    try { 
     numIndexed = indexer.index(dataDir, new TextFilesFilter()); 
    } finally { 
     indexer.close(); 
    } 
    long end = System.currentTimeMillis(); 
    System.out.println("Indexing " + numIndexed + " files took " + (end - start) + " milliseconds"); 
} 

private IndexWriter writer; 

public Indexer(String indexDir) throws IOException { 
    Directory dir = FSDirectory.open(new File(indexDir)); 
    writer = new IndexWriter(dir, 
     new StandardAnalyzer(Version.LUCENE_35), 
     true, 
     IndexWriter.MaxFieldLength.UNLIMITED); 
} 

public void close() throws IOException { 
    writer.close(); 
} 

public int index(String dataDir, FileFilter filter) throws Exception { 
    File[] files = new File(dataDir).listFiles(); 
    for (File f: files) { 
     if (!f.isDirectory() && 
     !f.isHidden() && 
     f.exists() && 
     f.canRead() && 
     (filter == null || filter.accept(f))) { 
      BufferedReader inputStream = new BufferedReader(new FileReader(f.getName())); 
      String url = inputStream.readLine(); 
      inputStream.close(); 
      indexFile(f, url); 
     } 
    } 
    return writer.numDocs(); 
} 

private static class TextFilesFilter implements FileFilter { 
    public boolean accept(File path) { 
     return path.getName().toLowerCase().endsWith(".txt"); 
    } 
} 

protected Document getDocument(File f, String url) throws Exception { 
    Document doc = new Document(); 
    doc.add(new Field("contents", new FileReader(f))); 
    doc.add(new Field("urls", url, Field.Store.YES, Field.Index.NOT_ANALYZED)); 
    doc.add(new Field("filename", f.getName(), Field.Store.YES, Field.Index.NOT_ANALYZED)); 
    doc.add(new Field("fullpath", f.getCanonicalPath(), Field.Store.YES, Field.Index.NOT_ANALYZED)); 
    return doc; 
} 

private void indexFile(File f, String url) throws Exception { 
    System.out.println("Indexing " + f.getCanonicalPath()); 
    Document doc = getDocument(f, url); 
    writer.addDocument(doc); 
} 
} 

誰もがそれを行うためのプログラムを書くことで私を助けることができますか?ありがとう。

答えて

8

まず、ドキュメント内の用語の頻度のみを知るために用語ベクトルを格納する必要はありません。 LuceneはTF-IDF計算に使用するにもかかわらず、これらの数値を格納します。この情報にアクセスするには、IndexReader.termDocs(term)を呼び出して結果を反復処理します。

実際に用語ベクトルにアクセスする必要がある場合は、コンストラクタの最後の引数としてField.TermVector.YESを渡して、Luceneに格納するように指示する必要があります。次に、ベクトルを取り出すことができます。 IndexReader.getTermFreqVector()である。

+0

ありがとうございました。私の問題を解決しました – orezvani

+0

tf-idfの検索に役立ちますか? – orezvani

+0

申し訳ありませんが、どういう意味ですか? –

1

私はLuceneコア3.0.3を使用していますが、APIは非常に似ていると思います。この方法では、指定されたドキュメント番号のセットの用語頻度マップと、ストップワードを無視して、関心のあるフィールドのリストを合計します。

/** 
* Sums the term frequency vector of each document into a single term frequency map 
* @param indexReader the index reader, the document numbers are specific to this reader 
* @param docNumbers document numbers to retrieve frequency vectors from 
* @param fieldNames field names to retrieve frequency vectors from 
* @param stopWords terms to ignore 
* @return a map of each term to its frequency 
* @throws IOException 
*/ 
private Map<String,Integer> getTermFrequencyMap(IndexReader indexReader, List<Integer> docNumbers, String[] fieldNames, Set<String> stopWords) 
throws IOException { 
    Map<String,Integer> totalTfv = new HashMap<String,Integer>(1024); 

    for (Integer docNum : docNumbers) { 
     for (String fieldName : fieldNames) { 
      TermFreqVector tfv = indexReader.getTermFreqVector(docNum, fieldName); 
      if (tfv == null) { 
       // ignore empty fields 
       continue; 
      } 

      String terms[] = tfv.getTerms(); 
      int termCount = terms.length; 
      int freqs[] = tfv.getTermFrequencies(); 

      for (int t=0; t < termCount; t++) { 
       String term = terms[t]; 
       int freq = freqs[t]; 

       // filter out single-letter words and stop words 
       if (StringUtils.length(term) < 2 || 
        stopWords.contains(term)) { 
        continue; // stop 
       } 

       Integer totalFreq = totalTfv.get(term); 
       totalFreq = (totalFreq == null) ? freq : freq + totalFreq; 
       totalTfv.put(term, totalFreq); 
      } 
     } 
    } 

    return totalTfv; 
} 
+0

PS事前にターム頻度ベクトルを保存するように各フィールドを設定する必要があります。 \t @Field(インデックス= Index.TOKENIZED、termVector = TermVector.YES) \t公共ストリングgetAbstract(){ \t \tリターンthis.abstract_。 \t} –

+0

ありがとう、これらの数値の中にtf-idfの値を計算する方法はありますか? http://stackoverflow.com/questions/9189179/extract-tf-idf-vectors-with-lucene – orezvani

+0

はlucene 4.xでは動作しません – Umingo

関連する問題