2012-01-30 24 views
5

Apache Lucene'yi kullanarak aranabilir bir telefon/yerel işletme dizini oluşturmaya çalışıyorum.Lucene: Arama terimleriyle ilgili çok sözcüklü deyimler

Sokak adı, işletme adı, telefon numarası vb. Için alanlarım var. Karşılaştığım sorun, cadde adında birden çok kelimeye (örneğin, 'hilal') sahip olduğu caddede arama yapmaya çalıştığımda sorun yok. sonuçlar geri döndü. Ama sadece bir kelime ile arama yapmaya çalışırsam, örneğin 'hilal', istediğim tüm sonuçları alırım.

aşağıdaki ile veri indeksleme ediyorum:

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(); 

Benim aramalar

böyle çalışır: Bir ifade sorgusu için joker sorgusu takas denedi

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; 

, ilk tamamı ile dize ve sonra beyaz alan üzerinde dize kadar bölme ve bunun gibi bir BooleanQuery onları sarma:

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); 

Ancak, bu işe yaramadı. StandardAnalyzer yerine bir KeywordAnalyzer kullanmayı denedim, ancak diğer tüm arama türleri de çalışmayı bıraktı. Boşlukları diğer karakterlerle (+ ve @) değiştirmeyi ve sorguları bu formata dönüştürmeyi denedim, ancak bu hala çalışmıyor. Bence işe yaramıyor çünkü + ve @ indekslenmemiş özel karakterler. Ama hangi karakterlerin olduğu gibi bir liste bulamıyorum.

Biraz kızmaya başlıyorum, yanlış yaptığımı bilen var mı?

sayesinde Rik

+0

Özel karakter burada bulabilirsiniz gerçekleştirir olacak x.html # N10180. – Oliver

cevap

5

Bir QueryParser kullanmadan bir sorgu oluşturmak için benim girişimi çalışma değildi bulundu, bu yüzden kendi sorguları oluşturmak için çalışıyorum durdu ve bunun yerine bir QueryParser kullanılır. Çevrimiçi gördüğüm tüm öneriler, QueryParser'de indeksleme sırasında kullandığınız aynı Analyzer'ı kullanmanız gerektiğini gösterdi, bu yüzden QueryParser'ı oluşturmak için bir StandardAnalyzer kullandım.

Bu örnek, StandardAnalyzer'ın indeksleme sırasında "hilal" sözcüğünü "hilal" sözcüğünden kaldırması ve dolayısıyla dizinde bulunmadığı için arama yapamayacağı için bu örnek üzerinde çalışır.

Ancak, "Grove Road" için arama yapmayı seçersek, kutudan çıkar çıkmaz işlevle ilgili bir sorunla karşılaşırız; yani, sorgu, "Grove" VEYA "Road" içeren tüm sonuçları döndürür ". Bu, QueryParser'ı kurarak kolayca giderilir, böylece varsayılan işlem VEYA yerine VEYA olur. Sonunda

doğru çözümdü aşağıdadır: Hazırda örtülü white spaces işte çözüm ayarlanır dayalı kelimeleri bölünmüş olan StandardAnalyzer kullanır coz burada herhangi bir Analyzer kullanmanın gerek yoktur

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

Durma adlarını sokak adlarından kaldırma yanlış. [Her İki Sokak] gibi adlar düşünün (http://g.co/maps/r5rnc). Eminim daha canlı örnekler bulabilirsin. Neden mantıklı değilse bir şeyi kaldırsın? –

11

geri belgelerinizi almak indeksleme yaparken küçük harfe belirteçleri dönüştürür ve kelimeleri durdurmak kaldırır, hangi StandardAnalyzer kullandığınız olmasıdır yok sebebi. Yani örneğiniz için endekslenen tek terim “hilal” dir. Ancak joker karakter sorguları analiz edilmez, bu nedenle '', 'sorgunun zorunlu kısmı olarak eklenir. Aynı senaryoda ifade sorguları için de geçerlidir. tek göstergesi olarak bütün alanı içeriğinde alır çünkü

KeywordAnalyzer, muhtemelen kullanım durumu için çok uygun değildir. Sokak alanı için SimpleAnalyzer'u kullanabilirsiniz - girişi tüm harf olmayan karakterlere böler ve sonra bunları küçük harfe dönüştürür. Ayrıca LowerCaseFilter ile WhitespaceAnalyzer kullanmayı düşünebilirsiniz. Farklı seçenekleri denemeniz ve verileriniz ve kullanıcılarınız için en iyi olanı bulmanız gerekir. Bu alan aralarında diğer aramalar için analizörü değişen eğer

Ayrıca, (PerFieldAnalyzerWrapper ile örneğin) alan başına farklı çözümleyicilerin kullanabilirsiniz. Tam bir kelime sokak maç istiyorsanız

0

, siz "" dur sözcüğü filtrelemeyin hangi NOT_ANALYZED Alan "Sokak" ayarlayabilirsiniz.

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

Bu iyi bir çözüm değil - bu şekilde, bu sonucu elde etmek için her zaman sorgudaki '' öğesini '' içermeniz gerekir. –

+0

@Artur Nowak: Cevabınızı artırın. Uygun bir Analizör noktasıdır. –

0

http://lucene.apache.org/core/3_5_0/queryparsersynta: AnalyzeNO için otomatik Multi Phrase Search

@Column(name="skill") 
    @Field(index=Index.YES, analyze=Analyze.NO, store=Store.NO) 
    @Analyzer(definition="SkillsAnalyzer") 
    private String skill; 
İlgili konular