2011-11-23 14 views
5

Chciałbym przeszukać mój indeks na dwóch polach nazwanych "a" i "b". Dano mi wyszukiwań jak Freud -- theories of psychology i chciałbym wykonać następujące zapytanie:Jak połączyć dwa zapytania Lucene za pomocą OR?

(a="Freud" AND b="theories of psychology") OR (b="Freud" AND a="theories of psychology") 

jaki sposób mogę to zrobić? Do tej pory mam Lucene konstruowania dwóch połówek (firstHalf i secondHalf) za pomocą MultiFieldQueryParser, potem połączyliśmy je z

BooleanQuery combined = new BooleanQuery(); 
combined.add(firstHalf, BooleanClause.Occur.SHOULD); 
combined.add(secondHalf, BooleanClause.Occur.SHOULD); 

Ale combined pozwala Wyniki zostać zwrócone gdzie tylko „teorie” zostanie znaleziony, a nie „psychologię” , gdzie zdecydowanie chcę obu terminów. Wygląda na to, że Lucene dzieli "teorie psychologiczne" na trzy słowa i łączy je indywidualnie z OR. Jak mogę temu zapobiec?

firstHalf wygląda następująco:

Query firstHalf = MultiFieldQueryParser.parse(Version.LUCENE_33, 
     new String[]{"Freud", "theories of psychology"}, 
     new String[]{"a", "b"}, 
     new BooleanClause.Occur[]{BooleanClause.Occur.MUST, BooleanClause.Occur.MUST}, 
     analyzer); 

gdzie analyzer tylko StandardAnalyzer przedmiot.

+0

właśnie powiedziano, że Lucene nie obsługuje logikę Boolean tak, i że powinni = lub!. W takim przypadku _Lucene w Action_ 2nd Edition jest źle na stronie 95. :) Więc teraz wiem, że moje zapytanie jest zepsute, po prostu nie wiem jak to naprawić. – dmn

+0

Czy na pewno zapytanie jest prawidłowe? Kwerenda "teorie psychologii" oznacza, że ​​przynajmniej jedno z tych trzech słów musi gdzieś wystąpić, ale żadne z nich nie jest słowem wymaganym. –

+0

@KaiChan Nope, musiałem to zmodyfikować, aby wprowadzić to ograniczenie. Myślę, że dostałem to. :) – dmn

Odpowiedz

2

Analizator standardowy będzie tokenizować. Tak więc zapytanie theories of psychology jest równoważne theories OR of OR psychology.

Jeśli chcesz wyszukać wyrażenie "teorie psychologii", użyj PhraseQuery, lub zauważ, że domyślny QueryParser będzie interpretował cytaty jako znaczące frazę (tj. Zmień kod na "\"theories of psychology\"").

I tak, istnieje sens, w którym Lucene nie używa logiki Boole'a, ale jest to techniczne i nieistotne tutaj.

3

Sam się o tym dowiedziałem, ale teraz kod jest znacznie dłuższy; jeśli ktoś zna bardziej eleganckie rozwiązanie, proszę napisać, a ja chętnie nagrodzę. :) (Chociaż będę czyni to w sposób krótko ... ale tutaj jest pełna wersja tego, co się dzieje ...)

QueryParser parser = new QueryParser(Version.LUCENE_33, "a", analyzer); 
parser.setDefaultOperator(QueryParser.AND_OPERATOR); 
Query a_0 = parser.parse("Freud"); 
parser = new QueryParser(Version.LUCENE_33, "b", analyzer); 
parser.setDefaultOperator(QueryParser.AND_OPERATOR); 
Query b_1 = parser.parse("theories of psychology"); 

BooleanQuery firstHalf = new BooleanQuery(); 
firstHalf.add(a_0, BooleanClause.Occur.MUST); 
firstHalf.add(b_1, BooleanClause.Occur.MUST); 

parser = new QueryParser(Version.LUCENE_33, "b", analyzer); 
parser.setDefaultOperator(QueryParser.AND_OPERATOR); 
Query b_0 = parser.parse("Freud"); 
parser = new QueryParser(Version.LUCENE_33, "a", analyzer); 
parser.setDefaultOperator(QueryParser.AND_OPERATOR); 
Query a_1 = parser.parse("theories of psychology"); 

BooleanQuery secondHalf = new BooleanQuery(); 
secondHalf.add(b_0, BooleanClause.Occur.MUST); 
secondHalf.add(a_1, BooleanClause.Occur.MUST); 

BooleanQuery combined = new BooleanQuery(); 
combined.add(firstHalf, BooleanClause.Occur.SHOULD); 
combined.add(secondHalf, BooleanClause.Occur.SHOULD); 

Okazuje się SHOULD działa tak, jak trzeba go tutaj. Mam nadzieję, że ktoś uzna to za pomocne i nie mówię po prostu publicznie;)

+1

To jest moje ostatnie doświadczenie, że ucząc Lucene, powinieneś unikać QueryParser i próbować złożyć wszystko razem z bezpośrednich bazowych typów Query. Dostaniesz lepsze zrozumienie Lucene i nie zostaniesz rozproszony przez składnię zapytań. Jak wspomina Xodarap, to, czego naprawdę chcesz tutaj, to PhraseQuery.To, co teraz masz, dopasuje dokumenty do "teorii" "psychologii" w dowolnej kolejności lub pozycji, a nie do dokładnej frazy. (W rzeczywistości StandardAnalyzer odfiltrowuje "z", więc nawet PhraseQuery nie będzie pasowało do twojej dokładnej frazy ... ale to ograniczenie wyszukiwania, które zwykle przeżywamy, po prostu zaakceptuj.) – Jegschemesch

2

Napisałem poniżej klasę, aby wygenerować powiązane zapytania rozmyte, w których termin musi być przeszukiwany na wielu polach. Zapytanie łączone można pobrać, wywołując metodę GetQuery().

public class QueryParam 
{ 
    public string[] Fields { get; set; } 
    public string Term { get; set; } 

    private QueryParam _andOperandSuffix; 
    private QueryParam _orOperandSuffix; 

    private readonly BooleanQuery _indexerQuery = new BooleanQuery();   

    public QueryParam(string term, params string[] fields) 
    { 
     Term = term; 
     Fields = fields; 
    } 

    public QueryParam And(QueryParam queryParam) 
    { 
     _andOperandSuffix = queryParam; 
     return this; 
    } 

    public QueryParam Or(QueryParam queryParam) 
    { 
     _orOperandSuffix = queryParam; 
     return this; 
    } 

    public BooleanQuery GetQuery() 
    {    
     foreach (var field in Fields) 
      _indexerQuery.Add(new FuzzyQuery(new Term(field, Term)), Occur.SHOULD); 

     if (_andOperandSuffix != null) 
      _indexerQuery.Add(_andOperandSuffix.GetQuery(),Occur.MUST); 

     if (_orOperandSuffix != null) 
      _indexerQuery.Add(_orOperandSuffix.GetQuery(), Occur.SHOULD); 

     return _indexerQuery; 
    } 

} 

Przykład:

var leftquery = new QueryParam("Freud", "a").And(new QueryParam("theories of psychology", "b")); 
var rightquery = new QueryParam("Freud", "b").And(new QueryParam("theories of psychology", "a")); 
var query = leftquery.Or(rightquery);    
Powiązane problemy