2012-04-10 7 views
0

私はLuceneでPrefixQueryを使ってオートコンプリートをしようとしています。私は私が思うものについて簡単なテストをしましたが、それはしません。私はいくつかの単純な文字列のインデックスを作成しており、KeywordAnalyzerを使ってそれらがトークン化されていないことを確認していますが、検索結果はまだ一致しません。プレフィックスマッチを取得するためにフィールドをインデックス付けして検索するにはどうすればよいですか?Luceneのフィールドでプレフィックスクエリを使用する方法は?

ここで私が試した単体テストです。 autocompleteメソッドとsingleTermメソッドを除くすべてが渡されます。

package com.sample.index; 

import org.apache.lucene.analysis.Analyzer; 
import org.apache.lucene.analysis.KeywordAnalyzer; 
import org.apache.lucene.analysis.PerFieldAnalyzerWrapper; 
import org.apache.lucene.analysis.standard.StandardAnalyzer; 
import org.apache.lucene.document.Document; 
import org.apache.lucene.document.Field; 
import org.apache.lucene.index.IndexReader; 
import org.apache.lucene.index.IndexWriter; 
import org.apache.lucene.index.IndexWriterConfig; 
import org.apache.lucene.queryParser.ParseException; 
import org.apache.lucene.queryParser.QueryParser; 
import org.apache.lucene.search.IndexSearcher; 
import org.apache.lucene.search.PrefixQuery; 
import org.apache.lucene.search.Query; 
import org.apache.lucene.search.TopDocs; 
import org.apache.lucene.store.RAMDirectory; 
import org.apache.lucene.util.Version; 
import org.junit.Before; 
import org.junit.Test; 

import java.io.IOException; 
import java.util.HashMap; 

import static junit.framework.Assert.assertEquals; 
import static junit.framework.Assert.assertFalse; 
import static junit.framework.Assert.assertTrue; 

public class TestIndexStuff { 
    public static final String FIELD_AUTOCOMPLETE = "autocomplete"; 
    public static final String FIELD_NORMAL = "normal"; 
    private IndexSearcher searcher; 
    private PerFieldAnalyzerWrapper analyzer; 

    @Before 
    public void init() throws IOException { 
     RAMDirectory idx = new RAMDirectory(); 

     HashMap<String, Analyzer> fieldAnalyzers = new HashMap<String, Analyzer>(); 
     fieldAnalyzers.put(FIELD_AUTOCOMPLETE, new KeywordAnalyzer()); 
     analyzer = new PerFieldAnalyzerWrapper(new StandardAnalyzer(Version.LUCENE_35), fieldAnalyzers); 
     IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_35, analyzer); 

     IndexWriter writer = new IndexWriter(idx, config); 
     addDocs(writer); 
     writer.close(); 

     searcher = new IndexSearcher(IndexReader.open(idx)); 
    } 

    private void addDocs(IndexWriter writer) throws IOException { 
     for (String text : new String[]{"Fred Rogers", "Toni Reed Preckwinkle", "Randy Savage", "Kathryn Janeway", "Madonna", "Fred Savage"}) { 
      Document doc = new Document(); 
      doc.add(new Field(FIELD_NORMAL, text, Field.Store.YES, Field.Index.ANALYZED)); 
      doc.add(new Field(FIELD_AUTOCOMPLETE, text, Field.Store.YES, Field.Index.NOT_ANALYZED)); 
      writer.addDocument(doc); 
     } 

    } 

    @Test 
    public void prefixParser() throws ParseException { 
     Query prefixQuery = new QueryParser(Version.LUCENE_35, FIELD_AUTOCOMPLETE, analyzer).parse("Fre*"); 
     assertTrue(prefixQuery instanceof PrefixQuery); 

     Query normalQuery = new QueryParser(Version.LUCENE_35, FIELD_AUTOCOMPLETE, analyzer).parse("Fred"); 
     assertFalse(normalQuery instanceof PrefixQuery); 
    } 

    @Test 
    public void normal() throws ParseException, IOException { 
     Query query = new QueryParser(Version.LUCENE_35, FIELD_NORMAL, analyzer).parse("Fred"); 
     TopDocs topDocs = searcher.search(query, 10); 
     assertEquals(2, topDocs.totalHits); 
    } 

    @Test 
    public void autocomplete() throws IOException, ParseException { 
     Query query = new QueryParser(Version.LUCENE_35, FIELD_AUTOCOMPLETE, analyzer).parse("Fre*"); 
     TopDocs topDocs = searcher.search(query, 10); 
     assertEquals(2, topDocs.totalHits); 
    } 

    @Test 
    public void singleTerm() throws ParseException, IOException { 
     Query query = new QueryParser(Version.LUCENE_35, FIELD_AUTOCOMPLETE, analyzer).parse("Mado*"); 
     TopDocs topDocs = searcher.search(query, 10); 
     assertEquals(1, topDocs.totalHits); 
    } 
} 

編集:@jpountzに感謝を変更した後、完全なテストを表示するには、この後のを読んでいる人のために改訂されたコードを追加します。大文字と小文字を区別せずに、小文字にインデックスを付けることにしました。また、検索用語で始まるものと一致する必要があるので、中間の用語が一致しないようにユニットテストを追加しました。

package com.sample.index; 

import org.apache.lucene.analysis.Analyzer; 
import org.apache.lucene.analysis.KeywordAnalyzer; 
import org.apache.lucene.analysis.PerFieldAnalyzerWrapper; 
import org.apache.lucene.analysis.standard.StandardAnalyzer; 
import org.apache.lucene.document.Document; 
import org.apache.lucene.document.Field; 
import org.apache.lucene.index.IndexReader; 
import org.apache.lucene.index.IndexWriter; 
import org.apache.lucene.index.IndexWriterConfig; 
import org.apache.lucene.queryParser.ParseException; 
import org.apache.lucene.queryParser.QueryParser; 
import org.apache.lucene.search.IndexSearcher; 
import org.apache.lucene.search.PrefixQuery; 
import org.apache.lucene.search.Query; 
import org.apache.lucene.search.TopDocs; 
import org.apache.lucene.store.RAMDirectory; 
import org.apache.lucene.util.Version; 
import org.junit.Before; 
import org.junit.Test; 

import java.io.IOException; 
import java.util.HashMap; 

import static junit.framework.Assert.assertEquals; 
import static junit.framework.Assert.assertFalse; 
import static junit.framework.Assert.assertTrue; 

public class TestIndexStuff { 
    public static final String FIELD_AUTOCOMPLETE = "autocomplete"; 
    public static final String FIELD_NORMAL = "normal"; 
    private IndexSearcher searcher; 
    private PerFieldAnalyzerWrapper analyzer; 

    @Before 
    public void init() throws IOException { 
     RAMDirectory idx = new RAMDirectory(); 

     HashMap<String, Analyzer> fieldAnalyzers = new HashMap<String, Analyzer>(); 
     fieldAnalyzers.put(FIELD_AUTOCOMPLETE, new KeywordAnalyzer()); 
     analyzer = new PerFieldAnalyzerWrapper(new StandardAnalyzer(Version.LUCENE_35), fieldAnalyzers); 
     IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_35, analyzer); 

     IndexWriter writer = new IndexWriter(idx, config); 
     addDocs(writer); 
     writer.close(); 

     searcher = new IndexSearcher(IndexReader.open(idx)); 
    } 

    private void addDocs(IndexWriter writer) throws IOException { 
     for (String text : new String[]{"Fred Rogers", "Toni Reed Preckwinkle", "Randy Savage", "Kathryn Janeway", "Madonna", "Fred Savage"}) { 
      Document doc = new Document(); 
      doc.add(new Field(FIELD_NORMAL, text, Field.Store.YES, Field.Index.ANALYZED)); 
      doc.add(new Field(FIELD_AUTOCOMPLETE, text.toLowerCase(), Field.Store.YES, Field.Index.NOT_ANALYZED)); 
      writer.addDocument(doc); 
     } 

    } 

    @Test 
    public void prefixParser() throws ParseException { 
     Query prefixQuery = new QueryParser(Version.LUCENE_35, FIELD_AUTOCOMPLETE, analyzer).parse("Fre*"); 
     assertTrue(prefixQuery instanceof PrefixQuery); 

     Query normalQuery = new QueryParser(Version.LUCENE_35, FIELD_AUTOCOMPLETE, analyzer).parse("Fred"); 
     assertFalse(normalQuery instanceof PrefixQuery); 
    } 

    @Test 
    public void normal() throws ParseException, IOException { 
     Query query = new QueryParser(Version.LUCENE_35, FIELD_NORMAL, analyzer).parse("Fred"); 
     TopDocs topDocs = searcher.search(query, 10); 
     assertEquals(2, topDocs.totalHits); 
    } 

    @Test 
    public void autocomplete() throws IOException, ParseException { 
     Query query = new QueryParser(Version.LUCENE_35, FIELD_AUTOCOMPLETE, analyzer).parse("Fre*"); 
     TopDocs topDocs = searcher.search(query, 10); 
     assertEquals(2, topDocs.totalHits); 
    } 

    @Test 
    public void beginningOnly() throws ParseException, IOException { 
     Query query = new QueryParser(Version.LUCENE_35, FIELD_AUTOCOMPLETE, analyzer).parse("R*"); 
     TopDocs topDocs = searcher.search(query, 10); 
     assertEquals(1, topDocs.totalHits); 
    } 

    @Test 
    public void singleTerm() throws ParseException, IOException { 
     Query query = new QueryParser(Version.LUCENE_35, FIELD_AUTOCOMPLETE, analyzer).parse("Mado*"); 
     TopDocs topDocs = searcher.search(query, 10); 
     assertEquals(1, topDocs.totalHits); 
    } 
} 

答えて

3

デフォルトでは、QueryParserは特別なクエリ(特にプレフィックスクエリ)の条件を小文字にします。無効にするには、QueryParser.setLowercaseExpandedTermsをご覧ください。

テストを修正するために

QueryParser qp = new QueryParser(Version.LUCENE_35, FIELD_AUTOCOMPLETE, analyzer); 
    qp.setLowercaseExpandedTerms(false); 
    Query query = qp.parse("Mado*"); 

Query query = new QueryParser(Version.LUCENE_35, FIELD_AUTOCOMPLETE, analyzer).parse("Mado*"); 

を交換してください。

+0

それでした。ありがとうございました! – user605331

関連する問題