開源:國内首款完全由國人自主研發的開源雲平台 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