2011-11-23 49 views
5

我想在兩個字段中搜索我的索引,名爲「a」和「b」。我給出的搜索像Freud -- theories of psychology,我想執行以下查詢:如何結合使用OR的兩個Lucene查詢?

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

我該怎麼辦呢?到目前爲止,我有Lucene的構建使用MultiFieldQueryParser兩半(firstHalfsecondHalf),然後我用

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

combined結合他們允許其中只有「理論」被發現,不是「心理學」被返回的結果,我絕對想要這兩個詞。 Lucene似乎將「心理學理論」分解爲三個單詞,並將它們分別與OR結合。我如何防止這種情況?

firstHalf樣子:

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

其中analyzer只是一個StandardAnalyzer對象。

+0

只是告訴Lucene的不支持布爾邏輯是這樣,這應該= OR!在這種情況下,Action_ 2nd Edition中的_Lucene在95頁是錯誤的。:)所以現在我知道_why_我的查詢被破壞了,只是不知道如何修復它。 – dmn

+0

確定該查詢是正確的?查詢「心理學理論」意味着這三個詞中至少有一個必須出現在某個地方,但它們都不是必需的單詞。 –

+0

@KaiChan不要,我不得不修改這個來限制進去。我想我知道了。 :) – dmn

回答

2

標準分析儀將標記。所以查詢theories of psychology相當於theories OR of OR psychology

如果要搜索短語「心理學理論」,請使用PhraseQuery,否則請注意,默認QueryParser會將引號解釋爲表示短語(即將您的代碼更改爲"\"theories of psychology\"")。

是的,有一種感覺Lucene不使用布爾邏輯,但它是技術性的,在這裏沒有真正的相關性。

3

自己弄明白了,但現在代碼明顯更長;如果有人知道更優雅的解決方案,請發帖,我會很高興獎勵。 :)(雖然我會作出這種成方法不久......但在這裏發生了什麼事情的完整版...)

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

原來SHOULD沒有工作,我需要它來這裏的路上。希望有人認爲這有幫助,我不只是在公共場合自言自語;)

+1

這是我最近的經驗,在學習Lucene時,你應該避免QueryParser,並嘗試從直接的基礎查詢類型中將所有東西拼湊在一起。您將更好地理解Lucene,並且不會被查詢語法分散注意力。正如Xodarap提到的,你真正想要的是PhraseQuery。你現在所擁有的將以任何順序或位置將文件與「心理學」的「理論」相匹配,而不是確切的短語。 (實際上,StandardAnalyzer會過濾出「of」,所以即使PhraseQuery也不符合您的確切短語......但這是我們通常只接受的搜索限制。) – Jegschemesch

2

我寫下面類生成鏈式模糊查詢,其中一個術語必須在多個領域進行搜索。 聯合查詢可以通過調用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; 
    } 

} 

例子:

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