2013-07-17 141 views
0

我目前在爲Lucene/Solr指定過濾器時遇到問題。我提出的每個解決方案都打破了其他解決方案讓我從一個例子開始。假設我們有以下5個文件:使用複雜過濾器的Lucene Solr

  • DOC1 = [類型:汽車,銷往:假的,老闆約翰]
  • DOC2 = [類型:自行車,產品編號:1,老闆布萊恩]
  • doc3的= [類型:汽車,銷售:真,所有者:麥克]
  • DOC4 = [類型:自行車,產品編號:2,所有者:約什]
  • doc5 = [類型:汽車,銷售:假的,所有者:約翰]

所以我需要構造下面的過濾器R查詢器:

  1. 給我類型的所有文件:已售出汽車:假的只是,如果它是一類不同的是這輛車,包括在結果中。所以基本上我想要文檔1,2,4,5我不想要的唯一文檔是doc3,因爲它已經售出:true。爲了更準確地說:

    for each document d in solr/lucene 
    if d.type == Car { 
        if d.sold == false, then add to result 
        else ignore 
    } 
    else { 
        add to result 
    } 
    return result 
    
  2. 過濾程序,因爲是所有文檔(類型:Car和出售:假)或(類型:自行車和產品編號:1)。所以爲此我會得到1,2,5。

  3. 獲取所有文件,如果類型:汽車然後只與賣出:假,否則讓我從業主約翰,布賴恩,喬希文件。因此,對於這個查詢我應該得到1,2,4,5

注:你不知道文檔中的所有類型。這裏顯而易見的是由於文件數量很少。

所以我的解決方案是:

  1. (型:汽車)OR((類型:汽車)AND(出售:假)這工作得很好,並預期
  2. ((型:汽車)或((類型:汽車)和(銷售:虛假))和((類型:自行車)或((類型:自行車)和(產品ID:1)))此解決方案不起作用
  3. (所有者:約翰)或(所有者:布賴恩)或(所有者:喬希))和((類型:汽車)或((類型:汽車)和(銷售:假))這不起作用,我可以做到((所有者:約翰)或(所有者:布賴恩)或(所有者:喬希))和((版本:* OR(--type:Car ))或((類型:汽車)和(銷售:假))。我不明白這是如何工作的,因爲邏輯上它應該工作,但Solr/Lucene以某種方式做某事。
+0

你能給的那種解決方案的一個例子,你沒試過嗎?我想象一下,如果用查詢過濾器包裝器包裝每個子查詢作爲TermQuery與Occur.MUST的簡單布爾查詢(如果聽起來像mumbo-jumbo,讓我知道,我會把它變成一個完整的答案) 。 – joshlf

+0

@ joshlf13,請盡興。 –

+0

@ joshlf13我把我的解決方案,如果它仍然適用,請把你的解決方案。 – Ammar

回答

0

我的建議是使用編程Lucene(也就是直接在Java中使用Java Lucene API)而不是發出將被解釋的文本查詢。這會給你更細緻的控制。

你要做的是使用QueryWrapperFilter API構造一個Lucene過濾器對象。 QueryWrapperFilter是一個過濾器,它接受一個Lucene查詢,並過濾掉任何與該查詢不匹配的文檔。

爲了使用QueryWrapperFilter,您需要構建一個與您感興趣的術語相匹配的查詢。要做到這一點,最好的辦法是使用TermQuery

TermQuery tq = new TermQuery(new Term("fieldname", "value")); 

正如你可能已經猜到了,你會想與期望的值來代替「字段名」與字段的名稱,而「價值」。例如,從您在OP中的示例中,您可能想要執行諸如new Term("type", "Car")之類的操作。

這隻匹配一個單詞。您將需要多個TermQueries,並將它們結合起來創建一個更大的查詢。要做到這一點,最好的辦法是BooleanQuery

BooleanQuery bq = new BooleanQuery(); 
bq.add(tq, BooleanQuery.Occur.MUST); 

你可以叫bq.add多次,你想要的 - 一次,你必須每個TermQuery。第二個參數指定查詢的嚴格程度。它可以指定出現子查詢MUST,出現SHOULD,或應出現NOT(這些是BooleanQuery.Occur枚舉的三個值)。

在添加了每個子查詢之後,此BooleanQuery表示完全查詢,它將僅匹配您要求的文檔。但是,它仍然不是過濾器。現在,我們需要把它喂QueryWrapperFilter,這將給我們帶回一個過濾器對象:

QueryWrapperFilter qwf = new QueryWrapperFilter(bq); 

應該這樣做。然後,如果你想運行在只有通過該過濾器允許文檔的查詢,你只要把你的新的查詢(稱之爲q)和你的過濾器,並創建一個FilteredQuery:

FilteredQuery fq = new FilteredQuery(q, qwf); 
+0

我如何在Solr的上下文中使用它?我有一個查詢的SolrQuery對象。有沒有辦法將SolrQuery轉換爲Query,以便它可以在'FilteredQuery fq = new FilteredQuery(q,qwf)中作爲'q';' – Ammar

+0

我試圖找到(和失敗,不幸)如何使用Lucene Solr的。我認爲這會很直接,但我猜不是。 – joshlf

1

好了,才能得到什麼,但一輛出售的汽車,你可以使用-(type:Car sold:true)

這可以合併到其他查詢中,但是您需要小心如此孤獨的否定查詢。一般來說,Lucene不能很好地處理它們,Solr也有一些奇怪的細節。特別是,A -B更像是「得到所有A但禁止B」而不是「得到所有A和除B之外的所有」。與A or -B類似的問題,請參閱this question瞭解更多信息。

要解決這個問題,你需要圍繞負帶有額外的括號,以確保它是由Solr的理解爲一個獨立的負查詢,如:(-(type:Car AND sold:true))

所以:

  1. -(type:Car AND sold:true)(這不會讓你說的結果,但按我的評論,我真的不明白你的既定結果)

  2. (type:Bike AND productID:1) (-(type:Car AND sold:true))(實際上,你在DESCRIPTIO寫了這n個問題!)

  3. (-(type:Car AND sold:false)) owner:(John Brian Josh)

+0

這個答案的問題是,你認爲你知道文檔的所有類型。如果想讓我的答案只知道問題中提到的類型。所以對於你的答案,他們假設我知道類型。 – Ammar

+0

它按你所描述的做。如上所述,列出的第一個查詢將只允許那些未售出的文件,並且是Car類型的文件。還有什麼可能包括在內。如果你想要任何類型的文件都沒有售出,那麼根本就沒有包含類型的好處。只要'sold:false'應該足夠了(或者如果你的數據標準化程度很差,而且你可以使用孤獨的負面查詢,那麼你可能不得不使用'-sold:true') – femtoRgon

+0

你引發了一個很好的論點,即我可以說 - 銷售:假,並得到我想要的。但是,我不能認爲另一種類型(讓我們說type:Airplane)沒有售出:false。在此查詢中,我想將文檔的類型附加到其特定字段。有趣的一點,但我仍然無法做出這樣的假設。 – Ammar