在前面的系列我們一直在介紹有關(guān)索引建立的問(wèn)題,現在是該利用這些索引來(lái)進(jìn)行搜索的時(shí)候了,Lucene良好的架構使得我們只需要很少的幾行代碼就可以為我們的應用加上搜索的功能,首先讓我們來(lái)認識一下搜索時(shí)最常用的幾個(gè)類(lèi).
查詢(xún)特定的某個(gè)概念
當我們搜索完成的時(shí)候會(huì )返回一個(gè)按Sorce排序的結果集Hits. 這里的Score就是接近度的意思,象Google那樣每個(gè)頁(yè)面都會(huì )有一個(gè)分值,搜索結果按分值排列. 如同你使用Google一樣,你不可能查看所有的結果, 你可能只查看第一個(gè)結果所以Hits返回的不是所有的匹配文檔本身, 而僅僅是實(shí)際文檔的引用. 通過(guò)這個(gè)引用你可以獲得實(shí)際的文檔.原因很好理解, 如果直接返回匹配文檔,數據量太大,而很多的結果你甚至不會(huì )去看, 想想你會(huì )去看Google 搜索結果10頁(yè)以后的內容嗎?
下面用一個(gè)例子來(lái)簡(jiǎn)要介紹一下Search
先建立索引
namespace dotLucene.inAction.BasicSearch protected String[] unindexed = {"Java Development with Ant", "JUnit in Action"};
protected String[] unstored = {
"we have ant and junit",
"junit use a mock,ant is also",
};
protected String[] text1 = {
"ant junit",
"junit mock"
};
protected String[] text3 = {
"/Computers/Ant", "/Computers/JUnit"
};
[SetUp]
protected void Init()
{
string indexDir = "index";
dir = FSDirectory.GetDirectory(indexDir, true);
AddDocuments(dir);
}
for (int i = 0; i < keywords.Length; i++)
{
Document doc = new Document();
doc.Add(Field.Keyword("isbn", keywords[i]));
doc.Add(Field.UnIndexed("title", unindexed[i]));
doc.Add(Field.UnStored("contents", unstored[i]));
doc.Add(Field.Text("subject", text1[i]));
doc.Add(Field.Text("pubmonth", text2[i]));
doc.Add(Field.Text("category", text3[i]));
writer.AddDocument(doc);
}
writer.Optimize();
writer.Close();
}
protected virtual Analyzer GetAnalyzer()
{
PerFieldAnalyzerWrapper analyzer = new PerFieldAnalyzerWrapper(
new SimpleAnalyzer());
analyzer.AddAnalyzer("pubmonth", new WhitespaceAnalyzer());
analyzer.AddAnalyzer("category", new WhitespaceAnalyzer());
return analyzer;
}
}
}
這里用到了一些有關(guān)Analyzer的知識,將放在以后的系列中介紹.
查詢(xún)特定的某個(gè)概念
然后利用利用TermQery來(lái)搜索一個(gè)Term(你可以把它理解為一個(gè)Word)
[Test]
public void Term()
{
IndexSearcher searcher = new IndexSearcher(directory);
Term t = new Term("subject", "ant");
Query query = new TermQuery(t);
Hits hits = searcher.Search(query);
Assert.AreEqual(1, hits.Length(), "JDwA");
t = new Term("subject", "junit");
hits = searcher.Search(new TermQuery(t));
Assert.AreEqual(2, hits.Length());
searcher.Close();
}
利用QueryParse簡(jiǎn)化查詢(xún)語(yǔ)句
顯然對于各種各樣的查詢(xún)(與或關(guān)系,等等各種復雜的查詢(xún),在下面將介紹),你不希望一一對應的為它們寫(xiě)出相應的XXXQuery. Lucene已經(jīng)為你考慮到了這點(diǎn), 通過(guò)使用QueryParse這個(gè)類(lèi), 你只需要寫(xiě)出我們常見(jiàn)的搜索語(yǔ)句, Lucene會(huì )在內部自動(dòng)做一個(gè)轉換.
這個(gè)過(guò)程有點(diǎn)類(lèi)似于數據庫搜索, 我們已經(jīng)習慣于使用SQL查詢(xún)語(yǔ)句,其實(shí)在數據庫的內部是要做一個(gè)轉換的, 因為數據庫不認得SQL語(yǔ)句,它只認得查詢(xún)語(yǔ)法樹(shù).
讓我們來(lái)看一個(gè)例子.
[Test]
public void TestQueryParser()
{
IndexSearcher searcher = new IndexSearcher(directory);
Query query = QueryParser.Parse("+JUNIT +ANT -MOCK",
"contents",
new SimpleAnalyzer());
Hits hits = searcher.Search(query);
Assert.AreEqual(1, hits.Length());
Document d = hits.Doc(0);
Assert.AreEqual("Java Development with Ant", d.Get("title"));
query = QueryParser.Parse("mock OR junit",
"contents",
new SimpleAnalyzer());
hits = searcher.Search(query);
Assert.AreEqual(2, hits.Length(), "JDwA and JIA");
}
由以上的代碼可以看出我們不需要為每種特定查詢(xún)而去設定XXXQuery 通過(guò)QueryParse類(lèi)的靜態(tài)方法Parse就可以很方便的將可讀性好的查詢(xún)口語(yǔ)轉換成Lucene內部所使用的各種復雜的查詢(xún)語(yǔ)句. 有一點(diǎn)需要注意:在Parse方法中我們使用了SimpleAnalyzer, 這時(shí)候會(huì )將查詢(xún)語(yǔ)句做一些變換,比如這里將JUNIT 等等大寫(xiě)字母變成了小寫(xiě)字母,所以才能搜索到(因為我們在建立索引的時(shí)候使用的是小寫(xiě)),如果你將StanderAnalyzer變成WhitespaceAnalyzer就會(huì )搜索不到.具體原理以后再說(shuō).
+A +B表示A和B要同時(shí)存在,-C表示C不存在,A OR B表示A或B二者有一個(gè)存在就可以..具體的查詢(xún)規則如下:
其中title等等的field表示你在建立索引時(shí)所采用的屬性名.
聯(lián)系客服