2013-04-18 60 views
4

鑑於這一文本的文檔,在一個名爲內容字段建立索引:Lucene的查詢失敗混合MUST/MUST_NOT

The dish ran away with the spoon. 

以下查詢失敗,該文件匹配:

+Content:dish +(-Content:xyz) <-- no results! 

查詢應視爲必須包含「碟」,不得包含「xyz」。這是失敗的「不可」部分。

我知道+ - 組合看起來很滑稽,但它語法應該是正確的,特別是考慮到以下變化各項工作:

+Content:dish +(-Content:xyz +Content:spoon) <-- this works 
+Content:dish -Content:xyz      <-- this works 

那麼,爲什麼不呢+(-Content:xyz)工作?這是設計,還是一個錯誤,或者我只是想念一些東西?我使用的是Lucene.Net,但我認爲普通的Lucene的行爲是一樣的。

回答

9

Lucene不是以全部視圖開始的,比如SQL數據庫。 Lucene從沒有匹配的文檔開始,並根據搜索到的子句找到事物。這就是爲什麼:

-Content:xyz 

在它自己並沒有真正的工作。它知道不要帶入內容:xyz,但沒有提供任何文件來匹配。你的查詢也是如此,因爲它被放置在一個子查詢中。

-Content:xyz首先被評估,它沒有得到它自己的文檔。所以,那麼你必須,有效

+Content:dish +(no documents) 

它想-作爲AND NOT,而不是一個簡單的NOT(雖然不採取暗示的+/-和AND/OR/NOT語法不一定映射到很有用彼此直接)。

如果您希望能夠執行一個孤獨的負面查詢,那麼您需要首先引入所有文檔。該MatchAllDocsQuery是實現這一目標的最佳途徑,是這樣的:

BooleanQuery query = new BooleanQuery(); 
query.add(new BooleanClause(new MatchAllDocsQuery(), BooleanClause.Occur.SHOULD)); 
query.add(new BooleanClause(new TermQuery(new Term("Content","xyz")), BooleanClause.Occur.MUST_NOT)); 

將是一個SQL樣式的查詢相當於只用一個否定的WHERE子句。

當然,這不是的情況下真的有必要你所列出的時間:

+Content:dish -Content:xyz 

已經完全夠用。

+0

現在對我有意義。謝謝! – Keith

+0

僅供參考MatchAllDocsQuery的字符串表示形式爲'*:*'。我上面的例子應該改爲以下它的工作:'+內容:菜+(+ *:* - 內容:xyz)' – Keith

+1

@凱斯嗯,不,它**應該被改爲等效: '內容:菜 - 內涵:xyz',但是,是的,這將工作(緩慢)。無法回想一下對'*:*'的支持是什麼樣子的(不管它是在Solr中,哪些版本支持它,它是否被.Net impl支持)。 – femtoRgon