2012-01-30 29 views
5

Apache Luceneを使用して検索可能な電話/ローカルビジネスディレクトリを作成しようとしています。Lucene:検索語としての複数単語のフレーズ

私には、通り名、会社名、電話番号などのフィールドがあります。私は、通り名が複数の単語(例: '三日月')を持つ通りで検索しようとすると、結果が返されます。しかし、「三日月」のように単語を1つだけ検索しようとすると、すべての結果が得られます。

私は次のようにデータのインデックスを作成しています:

String LocationOfDirectory = "C:\\dir\\index"; 

StandardAnalyzer analyzer = new StandardAnalyzer(Version.LUCENE_34); 
Directory Index = new SimpleFSDirectory(LocationOfDirectory); 

IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE.34, analyzer); 
IndexWriter w = new IndexWriter(index, config); 


Document doc = new Document(); 
doc.add(new Field("Street", "the crescent", Field.Store.YES, Field.Index.Analyzed); 

w.add(doc); 
w.close(); 

私の検索は、次のように動作します:

int numberOfHits = 200; 
String LocationOfDirectory = "C:\\dir\\index"; 
TopScoreDocCollector collector = TopScoreDocCollector.create(numberOfHits, true); 
Directory directory = new SimpleFSDirectory(new File(LocationOfDirectory)); 
IndexSearcher searcher = new IndexSearcher(IndexReader.open(directory); 

WildcardQuery q = new WildcardQuery(new Term("Street", "the crescent"); 

searcher.search(q, collector); 
ScoreDoc[] hits = collector.topDocs().scoreDocs; 

私は全体と最初のフレーズクエリのワイルドカードクエリを交換しようとしています文字列を空白に分割し、次のようにBooleanQueryでラップします。

String term = "the crescent"; 
BooleanQuery b = new BooleanQuery(); 
PhraseQuery p = new PhraseQuery(); 
String[] tokens = term.split(" "); 
for(int i = 0 ; i < tokens.length ; ++i) 
{ 
    p.add(new Term("Street", tokens[i])); 
} 
b.add(p, BooleanClause.Occur.MUST); 

しかし、これはうまくいかなかった。私は、StandardAnalyzerの代わりにKeywordAnalyzerを使ってみましたが、他のすべてのタイプの検索は機能しなくなりました。スペースを他の文字(+と@)で置き換えて、このフォームとの間でクエリを変換しようとしましたが、それでも動作しません。私は+と@は索引付けされていない特殊文字なので動作しないと思いますが、どこの文字がそのようなものかのリストを見つけることはできません。

私はやや怒っていますが、誰かが間違っていることを知っていますか?

おかげで、 のRik

+0

特殊文字がここで見つけることができます。http://lucene.apache.org/core/3_5_0/queryparsersynta x.html#N10180 – Oliver

答えて

5

私はQueryParserを使用せずにクエリを生成するための私の試みが働いていなかったことがわかったので、私は自分自身のクエリを作成しようと停止し、代わりにQueryParserを使用しました。私がオンラインで見たレコメンデーションでは、インデックス作成時に使用するQueryParserで同じAnalyzerを使用する必要があることがわかったので、QueryParserを構築するためにStandardAnalyzerを使用しました。

この例では、索引付け中にStandardAnalyzerが "the crescent"という単語から "the"という単語を削除して索引に含まれていないため、検索できません。

「Grove Road」の検索を選択した場合、すぐに使用できる機能に問題があります。つまり、「Grove」または「Road」を含むすべての結果が返されます。 "これは、デフォルトの操作がORの代わりにANDになるようにQueryParserを設定することで簡単に修正されます。最後に

は、正しい解決策は以下の通りであった:Hibernateは暗黙のうちに white spacesはので、ここで解決策が設定されているに基づいて単語を分割しますどの StandardAnalyzerを使用していますだってここに Analyzerを使用する必要はありません

int numberOfHits = 200; 
String LocationOfDirectory = "C:\\dir\\index"; 
TopScoreDocCollector collector = TopScoreDocCollector.create(numberOfHits, true); 
Directory directory = new SimpleFSDirectory(new File(LocationOfDirectory)); 
IndexSearcher searcher = new IndexSearcher(IndexReader.open(directory); 

StandardAnalyzer analyzer = new StandardAnalyzer(Version.LUCENE_35); 

//WildcardQuery q = new WildcardQuery(new Term("Street", "the crescent"); 
QueryParser qp = new QueryParser(Version.LUCENE_35, "Street", analyzer); 
qp.setDefaultOperator(QueryParser.Operator.AND); 

Query q = qp.parse("grove road"); 

searcher.search(q, collector); 
ScoreDoc[] hits = collector.topDocs().scoreDocs; 
+1

ストリート名からストップワードを削除するのが間違っています。 [Both Street](http://g.co/maps/r5rnc)のような名前を考えてみてください。より鮮明な例が見つかるはずです。それが理にかなっていない場合は、何かを削除するだけですか? –

11

は、あなたが戻ってあなたの文書を取得しない理由は、あなたが小文字にトークンを変換し、単語を停止削除StandardAnalyzerを、使用しているインデックスを作成しながら、ということです。したがって、あなたの例で索引付けされる唯一の用語は「三日月」です。ただし、ワイルドカードクエリは分析されないため、 'the'はクエリの必須部分として含まれます。同じことが、あなたのシナリオのフレーズクエリにも適用されます。

KeywordAnalyzerは、フィールドコンテンツ全体を1つのトークンとして扱うため、おそらくあなたのユースケースにはあまり適していません。ストリートフィールドにはSimpleAnalyzerを使用できます。これは、すべての文字以外の文字に入力を分割し、小文字に変換します。 WhitespaceAnalyzerLowerCaseFilterを使用することも考えられます。さまざまなオプションを試し、データとユーザーにとって最適なものを見つけ出す必要があります。

また、そのフィールドのアナライザを変更すると他の検索が中断される場合は、フィールドごとに異なるアナライザを使用できます(例:PerFieldAnalyzerWrapper)。

0

ストリートと正確な単語が一致するようにするには、フィールド "ストリート" NOT_ANALYZEDを設定します。これはストップワード "the"をフィルタリングしません。

doc.add(new Field("Street", "the crescent", Field.Store.YES, Field.Index.Not_Analyzed); 
+1

これは良い解決策ではありません。この方法では、この結果を得るには常にクエリに 'the'を含める必要があります。 –

+0

@Artur Nowak:あなたの答えを投票してください。適切なアナライザーがポイントです。 –

0

AnalyzeNOにそれが自動的に実行さMulti Phrase Search

@Column(name="skill") 
    @Field(index=Index.YES, analyze=Analyze.NO, store=Store.NO) 
    @Analyzer(definition="SkillsAnalyzer") 
    private String skill; 
関連する問題