本例我們使用類庫和代碼均來自:
http://www.cnblogs.com/TerryLiang/archive/2011/04/17/2018962.html
使用C#來模擬搜索、索引建立、刪除、更新過程,Demo截圖如下:
一、准備工作:
先准備一個實體類Product:
public class Product { public string ID { get; set; } public string Name { get; set; } public String[] Features { get; set; } public float Price { get; set; } public int Popularity { get; set; } public bool InStock { get; set; } public DateTime Incubationdate_dt { get; set; } }
再為這個實體類創建一個反序列化類ProductDeserializer:
class ProductDeserializer : IObjectDeserializer<Product> { public IEnumerable<Product> Deserialize(SolrDocumentList result) { foreach (SolrDocument doc in result) { yield return new Product() { ID = doc["id"].ToString(), Name = doc["name"].ToString(), Features = (string[])((ArrayList)doc["features"]).ToArray(typeof(string)), Price = (float)doc["price"], Popularity = (int)doc["popularity"], InStock = (bool)doc["inStock"], Incubationdate_dt = (DateTime)doc["incubationdate_dt"] }; } } }
為項目引入EasyNet.Solr.dll。
二、創建搜索:
執行Solr客戶端初始化操作:
#region 初始化 static List<SolrInputDocument> docs = new List<SolrInputDocument>(); static OptimizeOptions optimizeOptions = new OptimizeOptions(); static ISolrResponseParser<NamedList, ResponseHeader> binaryResponseHeaderParser = new BinaryResponseHeaderParser(); static IUpdateParametersConvert<NamedList> updateParametersConvert = new BinaryUpdateParametersConvert(); static ISolrUpdateConnection<NamedList, NamedList> solrUpdateConnection = new SolrUpdateConnection<NamedList, NamedList>() { ServerUrl = "http://localhost:8080/solr/" }; static ISolrUpdateOperations<NamedList> updateOperations = new SolrUpdateOperations<NamedList, NamedList>(solrUpdateConnection, updateParametersConvert) { ResponseWriter = "javabin" }; static ISolrQueryConnection<NamedList> connection = new SolrQueryConnection<NamedList>() { ServerUrl = "http://localhost:8080/solr/" }; static ISolrQueryOperations<NamedList> operations = new SolrQueryOperations<NamedList>(connection) { ResponseWriter = "javabin" }; static IObjectDeserializer<Product> exampleDeserializer = new ProductDeserializer(); static ISolrResponseParser<NamedList, QueryResults<Product>> binaryQueryResultsParser = new BinaryQueryResultsParser<Product>(exampleDeserializer); #endregion
我們先模擬一個數據源,這里內置一些數據作為示例:
List<Product> products = new List<Product>(); Product juzi = new Product { ID = "SOLR1000", Name = "浙江桔子", Features = new String[] { "色香味兼優", "既可鮮食,又可加工成以果汁", "果實營養豐富"}, Price = 2.0f, Popularity = 100, InStock = true, Incubationdate_dt = new DateTime(2006, 1, 17, 0, 0, 0, DateTimeKind.Utc) }; products.Add(juzi); var doc = new SolrInputDocument(); doc.Add("id", new SolrInputField("id", juzi.ID)); doc.Add("name", new SolrInputField("name", juzi.Name)); doc.Add("features", new SolrInputField("features", juzi.Features)); doc.Add("price", new SolrInputField("price", juzi.Price)); doc.Add("popularity", new SolrInputField("popularity", juzi.Popularity)); doc.Add("inStock", new SolrInputField("inStock", juzi.InStock)); doc.Add("incubationdate_dt", new SolrInputField("incubationdate_dt", juzi.Incubationdate_dt)); docs.Add(doc); Product pingguo = new Product { ID = "SOLR1002", Name = "陝西蘋果", Features = new String[] { "味道甜美", "光澤鮮艷", "營養豐富" }, Price = 1.7f, Popularity = 50, InStock = true, Incubationdate_dt = new DateTime(2010, 1, 17, 0, 0, 0, DateTimeKind.Utc) }; products.Add(pingguo); var doc2 = new SolrInputDocument(); doc2.Add("id", new SolrInputField("id", pingguo.ID)); doc2.Add("name", new SolrInputField("name", pingguo.Name)); doc2.Add("features", new SolrInputField("features", pingguo.Features)); doc2.Add("price", new SolrInputField("price", pingguo.Price)); doc2.Add("popularity", new SolrInputField("popularity", pingguo.Popularity)); doc2.Add("inStock", new SolrInputField("inStock", pingguo.InStock)); doc2.Add("incubationdate_dt", new SolrInputField("incubationdate_dt", pingguo.Incubationdate_dt)); docs.Add(doc2); dataGridView1.DataSource = products;
同時將這些數據添加到List<SolrInputDocument>中,SolrInputDocument是TerryLiang編寫的文檔交換實體,可以在他提供的源代碼中看到。
1. 創建索引:
創建索引是指將原始數據傳遞給Solr,然后在Solr目錄下創建指定格式文件,這些文件能夠被Solr快速查詢,如下圖:
創建索引實際上就是用Update將數據POST給collection1,代碼如下:
var result = updateOperations.Update("collection1", "/update", new UpdateOptions() { OptimizeOptions = optimizeOptions, Docs = docs }); var header = binaryResponseHeaderParser.Parse(result); lbl_info.Text= string.Format("Update Status:{0} QTime:{1}", header.Status, header.QTime);
索引成功后我們可以在Solr管理界面查詢:
注意:每次使用管理器搜索時,右上角都會顯示搜索使用的URL:
http://localhost:8080/solr/collection1/select?q=*%3A*&wt=json&indent=true
這些參數的含義較為簡單可以查詢一些文檔獲取信息。
2. 創建查詢
查詢其實就是提交一個請求給服務器,等待服務器將結果返回的過程,可以使用任何語言只要能發起請求並接受結果即可,這里我們使用客戶端。
先創建一個ISolrQuery對象,傳入搜索關鍵字,關鍵字的構建方法可以從Solr管理界面推理出來:
假如我們要查詢name中帶“蘋果”的信息,我們需要在管理界面輸入:
如果想知道Solr是如何構建查詢的話可以勾選DebugQuery選項,得到調試信息:
意思是只在Name這個列中檢索。
所以我們代碼中需要這么寫:
ISolrQuery query = new SolrQuery("name:"+keyWord);
安全問題自行考慮。
但是如果要查詢全部就簡單多了:
ISolrQuery query = SolrQuery.All;
將查詢條件發送給服務器之后再把服務器返回的數據還原成對象顯示出來即完成了一次查詢操作,具體操作代碼如下:
ISolrQuery query = SolrQuery.All; if (!string.IsNullOrWhiteSpace(keyWord)) { query = new SolrQuery("name:"+keyWord); } var result = operations.Query("collection1", "/select", query, null); var header = binaryResponseHeaderParser.Parse(result); var examples = binaryQueryResultsParser.Parse(result); lbl_info.Text= string.Format("Query Status:{0} QTime:{1} Total:{2}", header.Status, header.QTime, examples.NumFound); dataGridView1.DataSource = examples.ToList();
3. 增量索引
實際上經常會有數據是新增或者改變的,那么我們就需要及時更新索引便於查詢出新數據,就需要增量索引。這和初次索引一樣,如果你想更新原有數據,那么將新數據再次提交一次即可,如果想增加提交不同數據即可。數據判斷標准為id,這是個配置項,可以在中D:\apache-tomcat-7.0.57\webapps\solr\solr_home\collection1\conf\schema.xml找到:
<field name="id" type="string" indexed="true" stored="true" required="true" multiValued="false" />
可以理解為主鍵。
代碼如下:
var docs = new List<SolrInputDocument>(); Product hetao = new Product { ID = "SOLR1003", Name = "陝西山核桃", Features = new String[] { "營養好吃", "微量元素豐富", "補腦" }, Price = 1.7f, Popularity = 50, InStock = true, Incubationdate_dt = new DateTime(2010, 1, 17, 0, 0, 0, DateTimeKind.Utc) }; var doc2 = new SolrInputDocument(); doc2.Add("id", new SolrInputField("id", hetao.ID)); doc2.Add("name", new SolrInputField("name", hetao.Name)); doc2.Add("features", new SolrInputField("features", hetao.Features)); doc2.Add("price", new SolrInputField("price", hetao.Price)); doc2.Add("popularity", new SolrInputField("popularity", hetao.Popularity)); doc2.Add("inStock", new SolrInputField("inStock", hetao.InStock)); doc2.Add("incubationdate_dt", new SolrInputField("incubationdate_dt", hetao.Incubationdate_dt)); docs.Clear(); docs.Add(doc2); var result = updateOperations.Update("collection1", "/update", new UpdateOptions() { OptimizeOptions = optimizeOptions, Docs = docs }); var header = binaryResponseHeaderParser.Parse(result); lbl_info.Text= string.Format("Update Status:{0} QTime:{1}", header.Status, header.QTime);
4. 刪除索引
和數據庫刪除一樣,當然按照主鍵進行刪除。傳入刪除Option同時帶入主鍵名和主鍵值發送給服務器即可。
具體操作代碼如下:
var result = updateOperations.Update("collection1", "/update", new UpdateOptions() { OptimizeOptions = optimizeOptions, DelById = new string[] { id } }); var header = binaryResponseHeaderParser.Parse(result); lbl_info.Text=string.Format("Update Status:{0} QTime:{1}", header.Status, header.QTime);
這樣就完成了一個最基本的創建索引,更新刪除索引和查詢的過程,本例查詢速度並沒有直接操作管理界面那么快,原因在於序列化和反序列化,延續上述提到的:任何語言只要能發起請求和接收響應即可以查詢,可以避免這個過程,提高查詢效率。