開源:國內首款完全由國人自主研發的開源雲平台 BDC 4.0 -- 新增了雲索引、雲檢索、雲中文分詞
BDC 4.0下載地址: http://pan.baidu.com/share/link?shareid=579097387&uk=1614272889
BDC 4.0 雲平台分布是雲索引、雲檢索 雲中文分詞配置說明
一、索引檢索配置
首先配置一些基本參數和路徑
在配置節:<WebSystem.Framework.Key>
下配置以下配置項:
1、<KeyInfo Key="PhysicaPath" Value="E:\sousuo\"/>
表示中文分詞所在的目錄,將壓縮文件中的App_Data 文件夾拷貝到 所配置的目錄中
★注;沒這個次庫索引、檢索都無法正常執行
2、<KeyInfo Key="SEARCHIDX" Value="E:\sousuo\index\"/>
表示全文索引存儲的目錄
3、<KeyInfo Key="SNAPSHOT" Value="E:\sousuo\snapshot\"/>
表示快照文件存儲的目錄
4、<KeyInfo Key="BuildIndexRate" Value="5"/>
表示索引頻率(分鍾整數),建議范圍 3 - 10,Value越大索引周期越長,但是IO效率將越高,
(2G以下內存建議使用 5分鍾以下,太大高並發將導致內存溢出)
5、<KeyInfo Key="StartDocId" Value="0"/>
表示索引文檔編號起始值(整數), 在索引的時候會自動增長,每次服務停止會自動記錄下最后的編號,
考慮到分布式索引和檢索,建議每個節點的間隔編號以4000000 為間隔,比如:
此節點起始編號是 0,那么下一個節點是 4000000,再下一個節點是 8000000
也就是說,每個節點建議最多索引 400萬網頁,當然要是你機器足夠好,也可以適當調整。
★注;單個節點機最多索引 10000000(1千萬)網頁
二、集群配置
BDC雲平台在具體架設硬件集群的時候最好是將硬件划分邏輯層
如下圖:
1號節點機 2號節點機 3號節點機
| | |
---------------- ---------------- ----------------
4 5 6 7 8 9 10 11 12
-------
13 14 15 ... ... ... ... ... ... ... ...
以此類推,這么做的好處就在於每個節點上下及不多,有效的減少了節點間的網絡通信、有效的減少了上下層節點之間的Map - Reduce的計算時間和數據傳輸
在配置節:<WebSystem.Framework.Distributed 中進行配置
具體配置及參數說明請參見:
國內首款完全由國人自主研發的開源雲平台 BDC 3.0 詳解
http://blog.csdn.net/tengyunjiawu_com/article/details/8565766
★注;BDC 3.0在集群配置上與 BDC 4.0沒有做改動
基於 BDC 4.0的分布式集群的雲尋覓索引、檢索范例代碼 下載地址
http://pan.baidu.com/share/link?shareid=580846343&uk=1614272889
范例代碼:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using WebSystem.Framework; using System.Net; using WebSystem.Framework.Distributed; using System.Windows.Forms; using System.IO; using System.Reflection; //using BoInterFace; using Bo; using System.Runtime.Remoting; using System.Diagnostics; using WebSystem.FrameWork.SearchEngine.Search; using System.Threading; using System.Collections; using WebSystem.FrameWork.SearchEngine.Index; using Business.Processing.Business.BO.Core; using WebSystem.FrameWork.FenCi; using System.Runtime.Serialization.Formatters.Binary; using WebSystem.FrameWork.AlgorithmDataStructure.Sort; using testbo; namespace Bwsyq.Distributed.Cluster.Demo { class Program : ContextBoundObject { static void Main(string[] args) { GInvertedIndex ii = new GInvertedIndex(); var sw = Stopwatch.StartNew(); int exectype = 0; RemoteFactory rf = new RemoteFactory(); Thebegin: Console.WriteLine("請輸入需執行的項:\n"); Console.WriteLine("1:分發業務邏輯程序 \n"); Console.WriteLine("2:由指定IP開始的節點及所有子節點中性能最優節點執行的BO對象的方法,\n如果IP是根IP那么就由整個集群中性能最優的節點執行BO對象的方法 \n"); Console.WriteLine("3:獲取某個目錄下的指定擴展名的文件列表 \n"); Console.WriteLine("4:獲取CPU性能指標和內存可用指標 \n"); Console.WriteLine("5:創建遠程非透明代理對象,並調用其方法 \n"); Console.WriteLine("6:分發普通文件 \n"); Console.WriteLine("7:建立遠程全文索引 \n"); Console.WriteLine("8:執行遠程全文檢索 \n"); Console.WriteLine("9:建立遠程全文索引(無快照) \n"); Console.WriteLine("10:執行遠程全文檢索(無快照) \n"); Console.WriteLine("11:建立遠程網頁全文索引 \n"); Console.WriteLine("12:執行遠程網頁全文檢索 \n"); Console.WriteLine("13:建立遠程網頁全文索引(無快照) \n"); Console.WriteLine("14:執行遠程網頁全文檢索(無快照) \n"); Console.WriteLine("15:執行遠程集群網頁全文檢索(無快照) \n"); Console.WriteLine("16:執行遠程指定IP節點的中文分詞 \n"); Console.WriteLine("17:執行指定IP開始的節點及所有子節點中性能最優節點的中文分詞,\n如果IP是根IP那么就由整個集群中性能最優的節點執行中文分詞方法 \n"); Console.WriteLine("18:獲取全局自增長流水號(整數) \n"); Console.WriteLine("Other Key:退出 \n"); try { exectype = Console.ReadLine().ToInt(); } catch (Exception e) { return; } switch (exectype) { case 1: rf = new RemoteFactory(); //將業務邏輯程序 TestBo.dll 分發到 192.168.1.4 及其所有下層節點機中,並加載等待調用 //注:分發之后可以隨時更新覆蓋 rf.DistributionBoFile(@"D:\clienttest\TestBo.dll", "192.168.1.4"); goto Thebegin; case 2: foreach (IPAddress ip in Api.LocalIps()) { Console.Write(ip.ToString() + "\n"); } Console.Write(Api.IsLocalIpAddress("192.168.1.4") + "\n"); goto Thebegin; case 3: string[] fs = Api.GetDirectoryFiles(Application.StartupPath + Path.DirectorySeparatorChar, "dll"); string s = ""; if (fs != null) { foreach (string f in fs) { Assembly asm = Assembly.LoadFrom(f); string assemblyName = asm.FullName; foreach (Type t in asm.GetTypes()) { if (t.IsClass) { if (Api.IsInherit(t, typeof(ContextBoundObject))) { string typeName = t.FullName; s = s + typeName + "|" + assemblyName + "|" + typeName + "Service" + "\n"; } } } Console.Write(f + "\n"); } } goto Thebegin; case 4: Console.Write(Api.GetCPUIndex() + "|" + Api.GetMemoryIndex()); goto Thebegin; case 5: TestBo TestBo = (TestBo)rf.CreateTheBestRemoteObject(typeof(TestBo), "192.168.1.103"); Console.WriteLine(TestBo.GetHttpContext(null, "", "")); goto Thebegin; case 6: rf = new RemoteFactory(); rf.DistributionFile(@"D:\clienttest\Business.Processing.xml", "127.0.0.2"); goto Thebegin; case 7: //如果你的內容存儲在數據庫中,那么全文索引可以采用這種方案 //這個索引的同時還會存儲快照 rf = new RemoteFactory(); bool r = false; for (int i = 0; i < 100000; i++) //索引十萬筆數據小試一下,大約10分鍾 { //參數說明: // 數據庫名(必填)、表名(必填)、Key字段名(必填)、Key字段值(必填)、正文(必填)、希望真正執行索引的節點IP r = rf.DistributionDataBaseFullTextIndex("DB001", "T0001", "F0001", Api.uuid(false), "我是一個兵,來自老百姓", "127.0.0.2"); } if (r) Console.WriteLine("遠程索引成功!"); else Console.WriteLine("遠程索引失敗!"); goto Thebegin; case 8: //如果你存儲在數據庫中的內容已經做了全文索引 //這個檢索出來的結果回包括:查詢語句所在的庫、表、Key字段名、Key字段值、索引內容、索引內容的動態摘要 rf = new RemoteFactory(); string queryString = Console.ReadLine(); //參數說明:搜索語句、頁號、每頁條數、希望真正執行檢索的節點IP DataBaseSearchResults dbsrs = rf.DistributionDataBaseFullTextSearch(queryString, 1, 10, "127.0.0.2"); if (dbsrs.DataBaseSearchResultEntityList.Count > 0) { Console.WriteLine("查詢串:" + dbsrs.QueryString); Console.WriteLine("查詢串分詞結果:" + dbsrs.SearchWords.ToValue()); Console.WriteLine("頁號:" + dbsrs.PageNumber); Console.WriteLine("每頁條數:" + dbsrs.PageSize); Console.WriteLine("總頁數:" + dbsrs.PageCount); Console.WriteLine("總條數:" + dbsrs.SearchCount); Console.WriteLine("搜索總用時(豪秒):" + dbsrs.ElapsedMilliseconds); Console.WriteLine("搜索IO用時(豪秒):" + dbsrs.ioMilliseconds); Console.WriteLine("搜索排序用時(豪秒):" + dbsrs.SortMilliseconds); foreach (DataBaseSearchResultEntity dbsre in dbsrs.DataBaseSearchResultEntityList) { Console.WriteLine("DataBaseName:" + dbsre.DataBaseName); Console.WriteLine("TableName:" + dbsre.TableName); Console.WriteLine("KeyFieldName:" + dbsre.KeyFieldName); Console.WriteLine("KeyFieldValue:" + dbsre.KeyFieldValue); Console.WriteLine("Context:" + dbsre.Context); Console.WriteLine("ContextDynamicSummary(動態摘要):" + dbsre.ContextDynamicSummary); } } goto Thebegin; case 9: //如果你的內容存儲在數據庫中,那么全文索引可以采用這種方案 //這個索引的同時不會存儲快照 //索引后返回一個唯一的ID rf = new RemoteFactory(); long recordDocId = 0; for (int i = 0; i < 100000; i++) //索引十萬筆數據小試一下,大約10分鍾 { //參數說明: // 數據庫名(必填)、表名(必填)、Key字段名(必填)、Key字段值(必填)、正文(必填)、希望真正執行索引的節點IP recordDocId = rf.DistributionDataBaseFullTextIndexNoSnapShot("DB001", "T0001", "F0001", Api.uuid(false), "我是一個兵,來自老百姓", "127.0.0.2"); if (recordDocId == 0) Console.WriteLine("遠程索引(無快照)失敗!"); else Console.WriteLine("遠程索引(無快照)成功,全文索引編號:" + recordDocId); } goto Thebegin; case 10: //如果你存儲在數據庫中的內容已經做了全文索引 //這個檢索出來的結果包括索引的時候生成的 ID列表 rf = new RemoteFactory(); queryString = Console.ReadLine(); //參數說明:搜索語句、頁號、每頁條數、希望真正執行檢索的節點IP DataBaseSearchResultsNoSnapShot dbsrsnss = rf.DistributionDataBaseFullTextSearchNoSnapShot(queryString, 10000, 10, "127.0.0.2"); if (dbsrsnss.RecordDocIds.Count > 0) { Console.WriteLine("查詢串:" + dbsrsnss.QueryString); Console.WriteLine("查詢串分詞結果:" + dbsrsnss.SearchWords.ToValue()); Console.WriteLine("頁號:" + dbsrsnss.PageNumber); Console.WriteLine("每頁條數:" + dbsrsnss.PageSize); Console.WriteLine("總頁數:" + dbsrsnss.PageCount); Console.WriteLine("總條數:" + dbsrsnss.SearchCount); Console.WriteLine("搜索總用時(豪秒):" + dbsrsnss.ElapsedMilliseconds); Console.WriteLine("搜索IO用時(豪秒):" + dbsrsnss.ioMilliseconds); Console.WriteLine("搜索排序用時(豪秒):" + dbsrsnss.SortMilliseconds); foreach (long RecordDocId in dbsrsnss.RecordDocIds) { Console.WriteLine("全文索引編號:" + RecordDocId); } } goto Thebegin; case 11: //如果你的內容是抓取后的網頁或文本,那么全文索引可以采用這種方案 //這個索引的同時會存儲快照 rf = new RemoteFactory(); r = false; for (int i = 0; i < 1000000; i++) //索引100萬筆數據小試一下,大約2小時 { //參數說明: // 鏈接(必填)、網頁Html內容、網站的IP地址、網站web服務器類型、標題(必填)、正文(必填)、 // 時間(必填)、網頁的權重(0-100)、希望真正執行索引的節點IP // ★網頁的權重 一旦指定所對應的網頁所有的關鍵詞都會增加相應的權重 r = rf.DistributionWebFullTextIndex("http://www.yunxunmi.com/" + i + ".html", "<body>雲尋覓搜索引擎</body>", "127.0.0.1", "IIS", "雲尋覓搜索引擎官網", "雲尋覓搜索引擎", DateTime.Now, 100, "127.0.0.2"); } if (r) Console.WriteLine("遠程索引網頁成功!"); else Console.WriteLine("遠程索引網頁失敗!"); goto Thebegin; case 12: //如果你的網頁或文本已經做了全文索引 //這個檢索出來的結果回包括:鏈接、網頁Html內容、標題、正文、網站的IP地址、 //網站web服務器類型、網頁權重、標題動態摘要、正文動態摘要 rf = new RemoteFactory(); queryString = Console.ReadLine(); //參數說明:搜索語句、頁號、每頁條數、希望真正執行檢索的節點IP WebSearchResults wsrs = rf.DistributionWebFullTextSearch(queryString, 1, 10, "127.0.0.2"); if (wsrs.WebSearchResultEntityList.Count > 0) { Console.WriteLine("查詢串:" + wsrs.QueryString); Console.WriteLine("查詢串分詞結果:" + wsrs.SearchWords.ToValue()); Console.WriteLine("頁號:" + wsrs.PageNumber); Console.WriteLine("每頁條數:" + wsrs.PageSize); Console.WriteLine("總頁數:" + wsrs.PageCount); Console.WriteLine("總條數:" + wsrs.SearchCount); Console.WriteLine("搜索總用時(豪秒):" + wsrs.ElapsedMilliseconds); Console.WriteLine("搜索IO用時(豪秒):" + wsrs.ioMilliseconds); Console.WriteLine("搜索排序用時(豪秒):" + wsrs.SortMilliseconds); foreach (WebSearchResultEntity wsre in wsrs.WebSearchResultEntityList) { Console.WriteLine("Url:" + wsre.Url); Console.WriteLine("Html:" + wsre.Html); Console.WriteLine("Title:" + wsre.Title); Console.WriteLine("Context:" + wsre.Context); Console.WriteLine("WebSiteIpAddress:" + wsre.WebSiteIpAddress); Console.WriteLine("WebServer:" + wsre.WebServer); Console.WriteLine("WebPageWeights(網頁權重):" + wsre.WebPageWeights); Console.WriteLine("TitleDynamicSummary(標題動態摘要):" + wsre.TitleDynamicSummary); Console.WriteLine("ContextDynamicSummary(正文動態摘要):" + wsre.ContextDynamicSummary); } } goto Thebegin; case 13: //如果你的內容是抓取后的網頁或文本,那么全文索引可以采用這種方案 //這個索引的同時不會存儲快照 //索引后返回一個唯一的文檔ID rf = new RemoteFactory(); long WebDocId = 0; for (int i = 0; i < 2000000; i++) //索引200萬筆數據小試一下,大約4小時 { //參數說明: // 鏈接(必填)、標題(必填)、正文(必填)、網頁的權重(0-100)、希望真正執行索引的節點IP // ★網頁的權重 一旦指定所對應的網頁所有的關鍵詞都會增加相應的權重 WebDocId = rf.DistributionWebFullTextIndexNoSnapShot("http://www.yunxunmi.com/" + i + ".html", "雲尋覓搜索引擎官網", "雲尋覓搜索引擎", 10, "127.0.0.2"); if (WebDocId == 0) Console.WriteLine("遠程索引網頁(無快照)失敗!"); else Console.WriteLine("遠程索引網頁(無快照)成功,全文索引編號:" + WebDocId); } goto Thebegin; case 14: //如果你的網頁或文本已經做了全文索引 //無快照 //這個檢索出來的結果包括索引的時候生成的文擋ID列表 queryString = Console.ReadLine(); queryString = string.IsNullOrEmpty(queryString) ? "雲尋覓搜索引擎" : queryString; for (int j = 0; j < 100; j++) { rf = new RemoteFactory(); //參數說明:搜索語句、頁號、每頁條數、希望真正執行檢索的節點IP WebSearchResultsNoSnapShot wsrsnss = rf.DistributionWebFullTextSearchNoSnapShot(queryString, 10, 10, "192.168.1.6"); Console.WriteLine("查詢串:" + wsrsnss.QueryString); Console.WriteLine("查詢串分詞結果:" + wsrsnss.SearchWords.ToValue()); Console.WriteLine("頁號:" + wsrsnss.PageNumber); Console.WriteLine("每頁條數:" + wsrsnss.PageSize); Console.WriteLine("總頁數:" + wsrsnss.PageCount); Console.WriteLine("總條數:" + wsrsnss.SearchCount); Console.WriteLine("搜索總用時(豪秒):" + wsrsnss.ElapsedMilliseconds); Console.WriteLine("搜索IO用時(豪秒):" + wsrsnss.ioMilliseconds); Console.WriteLine("搜索排序用時(豪秒):" + wsrsnss.SortMilliseconds); foreach (long webDocId in wsrsnss.WebDocIds) { Console.WriteLine("網頁全文索引編號:" + webDocId); } } goto Thebegin; case 15: //★★★★★★★★★★★★★★★★★ // 這里是集群搜索 //搜索指定IP以及其下層所有節點(並行) //★★★★★★★★★★★★★★★★★ //如果你的網頁或文本已經做了全文索引 //這個檢索出來的結果包括索引的時候生成的文擋ID列表 //★注;無論搜索結果有多少,只返回最多1000條數據 queryString = Console.ReadLine(); queryString = string.IsNullOrEmpty(queryString) ? "雲尋覓搜索引擎" : queryString; for (int j = 0; j < 100; j++) //執行100次搜索檢測一下看內存是否溢出 { rf = new RemoteFactory(); //參數說明:搜索語句、頁號、每頁條數、希望真正執行檢索的節點IP WebSearchResultsNoSnapShot cwsrsnss = rf.DistributionClustersWebFullTextSearchNoSnapShot(queryString, 2, 10, "192.168.1.4"); if (cwsrsnss.WebDocIds.Count > 0) { Console.WriteLine("查詢串:" + cwsrsnss.QueryString); Console.WriteLine("查詢串分詞結果:" + cwsrsnss.SearchWords.ToValue()); Console.WriteLine("頁號:" + cwsrsnss.PageNumber); Console.WriteLine("每頁條數:" + cwsrsnss.PageSize); Console.WriteLine("總頁數:" + cwsrsnss.PageCount); Console.WriteLine("總條數:" + cwsrsnss.SearchCount); Console.WriteLine("搜索總用時(豪秒):" + cwsrsnss.ElapsedMilliseconds); Console.WriteLine("搜索平均IO用時(豪秒):" + cwsrsnss.ioMilliseconds); Console.WriteLine("搜索平均排序用時(豪秒):" + cwsrsnss.SortMilliseconds); foreach (long webDocId in cwsrsnss.WebDocIds) { Console.WriteLine("集群網頁全文索引編號:" + webDocId); } } } goto Thebegin; case 16: //由指定IP的節點來執行中文分詞 string mContext = Console.ReadLine(); rf = new RemoteFactory(); try { if (String.IsNullOrEmpty(mContext)) goto Thebegin; List<string> ls = new List<string>(); //參數說明: // 要分詞的正文內容、分詞類型(CutType.Max:最大分詞、CutType.Min最小分詞、CutType.MinAndMax最小+最大分詞、CutType.MinAndMaxAndMiddle最小+中間+最大分詞)、 // 正文是否 html內容如果 true 程序會自動對 html進行解析提取正文后在分詞、 // 希望真正執行中文分詞的節點IP foreach (DictionaryEntry de in rf.SpecifyIpRemoteFenCi(mContext, CutType.Max, false, "127.0.0.2")) { ls.Add(de.Key.ToString()); Console.WriteLine("分詞結果->詞匯:" + de.Key.ToString() + " 權重:" + de.Value.ToString()); } Console.WriteLine("分詞結果:" + ls.ToValue()); } catch { goto Thebegin; } goto Thebegin; case 17: //由指定IP的節點及其下層所有節點中性能最優的節點機來執行中文分詞 mContext = Console.ReadLine(); rf = new RemoteFactory(); try { if (String.IsNullOrEmpty(mContext)) goto Thebegin; List<string> ls = new List<string>(); //參數說明: // 要分詞的正文內容、分詞類型(CutType.Max:最大分詞、CutType.Min最小分詞、CutType.MinAndMax最小+最大分詞、CutType.MinAndMaxAndMiddle最小+中間+最大分詞)、 // 正文是否 html內容如果 true 程序會自動對 html進行解析提取正文后在分詞、 // 希望真正執行中文分詞的節點IP foreach (DictionaryEntry de in rf.TheBestRemoteFenCi(mContext, CutType.Max, false, "127.0.0.2")) { ls.Add(de.Key.ToString()); Console.Write("分詞結果->詞匯:" + de.Key.ToString() + " 權重:" + de.Value.ToString() + "\n"); } Console.Write("分詞結果:" + ls.ToValue() + "\n"); } catch { goto Thebegin; } goto Thebegin; case 18: //全局自增長流水號(整數), 每次調用就會返回指定IP節點的下一個流水號,這個完全是系統額外提供的函數,系統本身並不使用。 //這個是線程安全的,支持大規模並發。服務停止后系統會保存最后的流水號,作為下次的起始值。 rf = new RemoteFactory(); int iSerialNumber = 0; try { iSerialNumber = rf.OverallSituationSinceTheGrowthSerialNumber("127.0.0.2"); } catch { Console.WriteLine("遠程調用全局自增長流水號失敗!"); } goto Thebegin; default: break; } } } }
參考范例網站: http://sousuo.yunxunmi.com/當然目前的版本即便是單機性能也比測試網站性能強至少 10倍!
在30台PC上做了一周時間的測試,每台機器索引了200萬的數據,共6000萬模擬網頁數據。
任意檢索不超過 1秒, 發現目前在雲檢索的性能、相關性等方面上還有很多值得進一步優化的,因此希望大家多提寶貴意見,謝謝!
有任何疑問或建議請聯系QQ群: 204725117