Lucene查询(搜索)语法示例
本文是我們名為“ Apache Lucene基礎知識 ”的學院課程的一部分。
在本課程中,您將了解Lucene。 您將了解為什么這樣的庫很重要,然后了解Lucene中搜索的工作方式。 此外,您將學習如何將Lucene Search集成到您自己的應用程序中,以提供強大的搜索功能。 在這里查看 !
目錄
1.簡介 2.查詢類1.簡介
在本課程的這一課中,我們將研究Lucene提供的基本查詢機制。 您可能會在入門課程中記得,Lucene不會將要搜索的原始文本發送到索引。 它為此使用Query對象。 在本課程中,我們將看到所有關鍵要素,它們將人類書面搜索短語轉換為諸如Queries類的代表性結構。
2.查詢類
Query類是一個公共抽象類,它代表對索引的查詢。 在本節中,我們將看到最重要的Query子類,您可以使用它們來執行高度定制的查詢。
2.1術語查詢
這是您可以針對Lucene索引執行的最簡單直接的查詢。 您只需搜索在特定Field包含單個單詞的Documents 。
基本的TermQuery構造函數定義如下: public TermQuery(Term t) 。 您從第一節課中記得, Term由兩部分組成:
因此,如果您想創建一個TermQuery來查找所有在"content" Field中包含"good"字樣的Documents ,則可以按照以下方法進行操作
TermQuery termQuery = new TermQuery(new Term("content","good"));我們可以使用它在先前創建的索引中搜索單詞“ static”:
String q = "static"Directory directory = FSDirectory.open(indexDir);IndexReader indexReader = DirectoryReader.open(directory);IndexSearcher searcher = new IndexSearcher(indexReader);Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_46);TermQuery termQuery = new TermQuery(new Term("content",q));TopDocs topDocs =searcher.search(termQuery, maxHits);ScoreDoc[] hits = topDocs.scoreDocs;for (ScoreDoc hit : hits) {int docId = hit.doc;Document d = searcher.doc(docId);System.out.println(d.get("fileName") + " Score :" + hit.score); }System.out.println("Found " + hits.length);輸出為:
C:\\Users\\nikos\\Desktop\\LuceneFolders\\LuceneHelloWorld\\SourceFiles\\Product.java Score :0.29545835 C:\\Users\\nikos\\Desktop\\LuceneFolders\\LuceneHelloWorld\\SourceFiles\\SimpleSearcher.java Score :0.27245367 C:\\Users\\nikos\\Desktop\\LuceneFolders\\LuceneHelloWorld\\SourceFiles\\PropertyObject.java Score :0.24368995 C:\\Users\\nikos\\Desktop\\LuceneFolders\\LuceneHelloWorld\\SourceFiles\\SimpleIndexer.java Score :0.14772917 C:\\Users\\nikos\\Desktop\\LuceneFolders\\LuceneHelloWorld\\SourceFiles\\TestSerlvet.java Score :0.14621398 C:\\Users\\nikos\\Desktop\\LuceneFolders\\LuceneHelloWorld\\SourceFiles\\ShoppingCartServlet.java Score :0.13785185 C:\\Users\\nikos\\Desktop\\LuceneFolders\\LuceneHelloWorld\\SourceFiles\\MyServlet.java Score :0.12184498 Found 7如您所見,我的七個源文件中包含"static"關鍵字。 就是這樣。 自然,如果您嘗試在查詢字符串中添加另一個單詞,則搜索將返回0個結果。 例如,如果您將查詢字符串設置為:
String q = "private static"輸出將是:
Found 0現在,我知道我的許多源文件中都存在"private static" 。 但是,您可能還記得,我們在索引過程中使用了StandarAnalyzer處理從文件中檢索的純文本。 StandardAnalyzer將文本拆分為單個單詞,因此每個Term包含一個單詞。 您可以選擇不標記索引的Field 。 但是我建議您在包含元數據的Fields中執行此操作,而不是在包含其內容的字段中,這些字段包含有關我們文檔的信息(例如標題或作者)。 例如,如果您選擇不對名稱為'author'且值為'James Wilslow'的Field進行標記化并編制索引,則Field 'author'將僅包含一個整體值為'James Wilslow' Term 。 如果您對Field進行了標記化,則它將包含兩個Terms ,一個的值為'James' ,另一個的值為'Wilslow' 。
2.2短語查詢
使用PhraseQuery您可以搜索包含特定單詞序列(又名短語)的Documents 。
您可以這樣創建一個PhraseQuery :
PhraseQuery phraseQuery = new PhraseQuery();然后,您可以向其添加Terms 。 例如,如果您要搜索在其“內容”字段中包含短語“ private static”的Documents ,則可以這樣做:
PhraseQuery phraseQuery = new PhraseQuery();phraseQuery.add(new Term("content","private")); phraseQuery.add(new Term("content","static"));TopDocs topDocs =searcher.search(phraseQuery, maxHits);ScoreDoc[] hits = topDocs.scoreDocs;for (ScoreDoc hit : hits) {int docId = hit.doc;Document d = searcher.doc(docId);System.out.println(d.get("fileName") + " Score :" + hit.score); }System.out.println("Found " + hits.length);輸出將是:
C:\\Users\\nikos\\Desktop\\LuceneFolders\\LuceneHelloWorld\\SourceFiles\\Product.java Score :0.54864377 C:\\Users\\nikos\\Desktop\\LuceneFolders\\LuceneHelloWorld\\SourceFiles\\PropertyObject.java Score :0.45251375 C:\\Users\\nikos\\Desktop\\LuceneFolders\\LuceneHelloWorld\\SourceFiles\\SimpleSearcher.java Score :0.45251375 C:\\Users\\nikos\\Desktop\\LuceneFolders\\LuceneHelloWorld\\SourceFiles\\TestSerlvet.java Score :0.27150828 C:\\Users\\nikos\\Desktop\\LuceneFolders\\LuceneHelloWorld\\SourceFiles\\ShoppingCartServlet.java Score :0.25598043 C:\\Users\\nikos\\Desktop\\LuceneFolders\\LuceneHelloWorld\\SourceFiles\\MyServlet.java Score :0.22625688 C:\\Users\\nikos\\Desktop\\LuceneFolders\\LuceneHelloWorld\\SourceFiles\\SimpleIndexer.java Score :0.22398287 Found 7僅當“ Field "static"連續且以該順序準確包含單詞"private"和"static" , Document才進入結果。
因此,如果您以上述方式更改上述代碼:
phraseQuery.add(new Term("content","private")); phraseQuery.add(new Term("content","final"));你會得到 :
Found 0這是因為盡管我的源文件包含兩個詞,但它們不是連續的。 要改變這種行為一點點,你可以添加一個slop到PhraseQuery 。 當您增加1的坡度時,您最多可以在詞組中的詞之間插入一個詞。 添加坡度2時,短語中的單詞之間最多允許2個單詞。
有趣的是: “實際上,坡度是一個編輯距離,其單位對應于查詢短語中詞條移動的位置。 例如,要切換兩個單詞的順序需要兩個步驟(第一個步驟將單詞彼此放在首位),因此要允許對短語進行重新排序,斜率必須至少為兩個。
因此,如果我們這樣做:
PhraseQuery phraseQuery = new PhraseQuery();phraseQuery.add(new Term("content","private")); phraseQuery.add(new Term("content","final"));phraseQuery.setSlop(2);我們的搜索輸出將給出:
C:\\Users\\nikos\\Desktop\\LuceneFolders\\LuceneHelloWorld\\SourceFiles\\Product.java Score :0.38794976 C:\\Users\\nikos\\Desktop\\LuceneFolders\\LuceneHelloWorld\\SourceFiles\\PropertyObject.java Score :0.31997555 C:\\Users\\nikos\\Desktop\\LuceneFolders\\LuceneHelloWorld\\SourceFiles\\SimpleSearcher.java Score :0.31997555 C:\\Users\\nikos\\Desktop\\LuceneFolders\\LuceneHelloWorld\\SourceFiles\\TestSerlvet.java Score :0.19198532 C:\\Users\\nikos\\Desktop\\LuceneFolders\\LuceneHelloWorld\\SourceFiles\\ShoppingCartServlet.java Score :0.18100551 C:\\Users\\nikos\\Desktop\\LuceneFolders\\LuceneHelloWorld\\SourceFiles\\MyServlet.java Score :0.15998778 C:\\Users\\nikos\\Desktop\\LuceneFolders\\LuceneHelloWorld\\SourceFiles\\SimpleIndexer.java Score :0.15837982重要的是要提到包含更接近查詢確切短語的短語的文檔將獲得更高的分數。
2.3布爾查詢
BooleanQuery是一種更具表現力和功能的工具,因為您可以將多個查詢與布爾子句結合在一起。 可以用BooleanClauses填充BoleanQuery。 BooleanClause包含一個Query ,以及Query在布爾搜索中應具有的角色。
更具體地說,布爾子句可以在查詢中扮演以下角色:
如果僅使用SHOULD子句進行布爾查詢,則結果至少匹配其中一個子句。 這看起來像經典的OR布爾運算符,但正確使用它并不是那么簡單。
現在讓我們看一些例子。 讓我們找到包含單詞“ string”但不包含單詞“ int”的源文件。
TermQuery termQuery = new TermQuery(new Term("content","string")); TermQuery termQuery2 = new TermQuery(new Term("content","int"));BooleanClause booleanClause1 = new BooleanClause(termQuery, BooleanClause.Occur.MUST); BooleanClause booleanClause2 = new BooleanClause(termQuery2, BooleanClause.Occur.MUST_NOT);BooleanQuery booleanQuery = new BooleanQuery(); booleanQuery.add(booleanClause1); booleanQuery.add(booleanClause2);TopDocs topDocs =searcher.search(booleanQuery, maxHits);結果如下:
C:\\Users\\nikos\\Desktop\\LuceneFolders\\LuceneHelloWorld\\SourceFiles\\SimpleEJB.java Score :0.45057273 C:\\Users\\nikos\\Desktop\\LuceneFolders\\LuceneHelloWorld\\SourceFiles\\PropertyObject.java Score :0.39020744 C:\\Users\\nikos\\Desktop\\LuceneFolders\\LuceneHelloWorld\\SourceFiles\\ShoppingCartServlet.java Score :0.20150226 C:\\Users\\nikos\\Desktop\\LuceneFolders\\LuceneHelloWorld\\SourceFiles\\TestSerlvet.java Score :0.13517183 Found 4現在,讓我們嘗試查找包含單詞“ nikos”和短語“ httpservletresponse response”的所有文檔。 在以下代碼片段中,您可以看到如何避免創建BooleanClause實例,從而使您的代碼更緊湊。
TermQuery termQuery = new TermQuery(new Term("content","nikos"));PhraseQuery phraseQuery = new PhraseQuery(); phraseQuery.add(new Term("content","httpservletresponse")); phraseQuery.add(new Term("content","response"));BooleanQuery booleanQuery = new BooleanQuery();booleanQuery.add(phraseQuery,BooleanClause.Occur.MUST); booleanQuery.add(termQuery,BooleanClause.Occur.MUST);TopDocs topDocs =searcher.search(booleanQuery, maxHits);結果如下:
C:\\Users\\nikos\\Desktop\\LuceneFolders\\LuceneHelloWorld\\SourceFiles\\ShoppingCartServlet.java Score :0.3148332 Found 1讓我們找到所有包含單詞“ int”或單詞“ nikos”的文檔。您可能會想到,必須以某種方式使用SHOULD規范:
TermQuery termQuery = new TermQuery(new Term("content","int")); TermQuery termQuery2 = new TermQuery(new Term("content","nikos"));BooleanQuery booleanQuery = new BooleanQuery();booleanQuery.add(termQuery,BooleanClause.Occur.SHOULD); booleanQuery.add(termQuery2,BooleanClause.Occur.SHOULD);TopDocs topDocs =searcher.search(booleanQuery, maxHits);這雖然不太困難,但是創建更復雜的析取查詢有點棘手。 如何正確使用它并不總是那么簡單。
例如,讓我們嘗試查找所有包含單詞“ nikos”和短語“ httpservletresponse response”或單詞“ int”的文檔。 可以這樣寫:
TermQuery termQuery = new TermQuery(new Term("content","nikos"));PhraseQuery phraseQuery = new PhraseQuery(); phraseQuery.add(new Term("content","httpservletresponse")); phraseQuery.add(new Term("content","response"));BooleanQuery booleanQuery = new BooleanQuery();booleanQuery.add(phraseQuery,BooleanClause.Occur.MUST); booleanQuery.add(termQuery,BooleanClause.Occur.MUST); booleanQuery.add(new TermQuery(new Term("content","int")),BooleanClause.Occur.SHOULD);TopDocs topDocs =searcher.search(booleanQuery, maxHits);但是查詢將無法提供所需的結果。 請記住,如我們所構造的那樣,該查詢的結果必須同時包含單詞"nikos"并且必須同時包含短語"httpservletresponse response" 。 但這不是您想要的。 您需要包含nikos單詞和短語"httpservletresponse response"文檔,但也想要獨立包含單詞"int"文檔,無論它們是否包含其他子句。 公平地說,上述布爾查詢有點錯誤。 因為在直接的布爾語法中,您永遠不會寫類似的內容:A AND B ORC。您應該寫(A AND B)ORC。或者A AND(B OR C)。 看到不同?
因此,您應該編寫所需的查詢,例如:(“ nikos”和“ httpservletresponse response”)或“ int”。
您可以將BooleanQueries組合在一起。 使用上面嚴格的語法,很難想象這將如何進行:
TermQuery termQuery = new TermQuery(new Term("content","nikos"));PhraseQuery phraseQuery = new PhraseQuery(); phraseQuery.add(new Term("content","httpservletresponse")); phraseQuery.add(new Term("content","response"));// (A AND B) BooleanQuery conjunctiveQuery = new BooleanQuery(); conjunctiveQuery.add(termQuery,BooleanClause.Occur.MUST); conjunctiveQuery.add(phraseQuery,BooleanClause.Occur.MUST);BooleanQuery disjunctiveQuery = new BooleanQuery();// (A AND B) OR C disjunctiveQuery.add(conjunctiveQuery,BooleanClause.Occur.SHOULD); disjunctiveQuery.add(new TermQuery(new Term("content","int")),BooleanClause.Occur.SHOULD);TopDocs topDocs =searcher.search(disjunctiveQuery, maxHits);這是使用BooleanQuery類構造布爾查詢時可以遵循的快速指南:
- X和Y
- X或Y
- BooleanQuery bool = new BooleanQuery(); bool.add(X,BooleanClause.Occur.SHOULD); bool.add(Y,BooleanClause.Occur.SHOULD);
- X AND(不是Y)
- BooleanQuery bool = new BooleanQuery(); bool.add(X,BooleanClause.Occur.MUST); bool.add(Y,BooleanClause.Occur.MUST_NOT);
- (X和Y)或Z
- BooleanQuery conj = new BooleanQuery();conj.add(X,BooleanClause.Occur.MUST); conj.add(Y,BooleanClause.Occur.MUST);BooleanQuery disj = new BooleanQuery(); disj.add(conj,BooleanClause.Occur.SHOULD) disj.add(Z,BooleanClause.Occur.SHOULD)
- (X或Y)和Z
- BooleanQuery conj = new BooleanQuery();conj.add(X,BooleanClause.Occur.SHOULD); conj.add(Y,BooleanClause.Occur.SHOULD);BooleanQuery disj = new BooleanQuery(); disj.add(conj,BooleanClause.Occur.MUST) disj.add(Z,BooleanClause.Occur.MUST)
- X或(非Z)
- BooleanQuery neg = new BooleanQuery();neg.add(Z,BooleanClause.Occur.MUST_OT);BooleanQuery disj = new BooleanQuery();
disj.add(neg,BooleanClause.Occur.SHOULD)
disj.add(X,BooleanClause.Occur.SHOULD)
上面的代碼可用于創建越來越復雜的布爾查詢。
2.4通配符查詢
顧名思義,您可以使用WildcardQuery類使用“ *”或“?”執行通配符查詢。 字符。 例如,如果您要o搜索包含以'ni'開頭的詞條,然后是其他任何字符序列的文檔,則可以搜索'ni *'。 如果要搜索以“ jamie”開頭(后跟(任意)一個字符)的術語,則可以搜索“ jamie?”。 就那么簡單。 自然地, WildcardQueries效率低下,因為搜索可能要經過很多不同的術語才能找到匹配項。 通常,最好避免將通配符放在單詞的開頭,例如“ * abcde”。
讓我們來看一個例子:
Query wildcardQuery = new WildcardQuery(new Term("content","n*os")); TopDocs topDocs =searcher.search(wildcardQuery, maxHits);和
Query wildcardQuery = new WildcardQuery(new Term("content","niko?")); TopDocs topDocs =searcher.search(wildcardQuery, maxHits);2.5 RegexpQuery
使用RegexpQuery ,您可以執行快速的正則表達式查詢,并通過Lucene的快速自動機實現對其進行評估。 這是一個例子
Query regexpQuery = new RegexpQuery(new Term("content","n[a-z]+"));TopDocs topDocs =searcher.search(regexpQuery, maxHits);2.6 TermRangeQuery
當對字符串術語執行范圍查詢時,此查詢子類很有用。 例如,您可以搜索“ abc”和“ xyz”兩個詞之間的字詞。 字的比較是使用Byte.compareTo(Byte)執行的。 您可能會發現這對于在文檔的元數據(例如標題甚至日期)中進行范圍查詢特別有用(如果使用日期,請小心使用DateTools )。
您可以在這里找到上周創建的所有文檔:
Calendar c = Calendar.getInstance(); c.add(Calendar.DATE, -7); Date lastWeek = c.getTime();Query termRangeQuery = TermRangeQuery.newStringRange("date", DateTools.dateToString(new Date(), DateTools.Resolution.DAY),DateTools.dateToString(lastWeek, DateTools.Resolution.DAY),true,true);當然,在為“日期”字段建立索引時必須小心。 您還必須將DateTools.dateToString應用于它,并指定該字段不進行分析(因此不會被標記化并拆分為單詞)。
2.7 NumberRangeQuery
這用于執行數字范圍查詢。 想象一下,您有一個“ wordcount”字段,用于存儲該文檔的單詞數,并且您要檢索的單詞數在2000至10000之間:
Query numericRangeQuery = NumericRangeQuery.newIntRange("wordcount",2000,10000,true,true);布爾參數規定范圍內包括上限和下限。
2.8模糊查詢
這是一個非常有趣的查詢子類。 該查詢根據鄰近度量(例如眾所周知的Damerau-Levenshtein距離)評估字詞。 這將找到詞典順序接近的單詞。 如果您想執行大量的詞典應用程序,例如詞典或“您要說的”單詞建議功能,則可以使用SpellChecker API 。
讓我們看看如何執行不幸的“字符串”拼寫錯誤的模糊查詢搜索:
Query fuzzyQuery = new FuzzyQuery(new Term("content","srng"));翻譯自: https://www.javacodegeeks.com/2015/09/lucene-query-search-syntax-examples.html
總結
以上是生活随笔為你收集整理的Lucene查询(搜索)语法示例的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux安装硬盘分区工具(linux
- 下一篇: 合肥市物价局房价备案官网(合肥市物价局房