2012-01-08 5 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 생성자의 마지막 인수로 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

추 신 : 미리 각 주파수 벡터를 저장하도록 각 필드를 구성해야합니다! \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

관련 문제