const int _removeDup_batchSize = 10000; // 利用 hashtable 进行局部去重的每批个数 // 从 dp2Kernel 端获取结果集 // parameters: // strStyle tobibliorecpath 将实体\期\订购\评注 记录路径转换为书目记录路径,并去重 int GetResultset(RmsChannel channel, string strResultsetName, DpResultSet resultset, out string strError) { strError = ""; m_biblioDbNameTable.Clear(); Hashtable temp_table = new Hashtable(); string strFormat = "id,cols,format:@coldef://parent"; // "id,xml"; SearchResultLoader loader = new SearchResultLoader(channel, null, strResultsetName, strFormat); loader.ElementType = "Record"; #if DETAIL_LOG this.WriteErrorLog("开始从 dp2kernel 获取结果集"); #endif int hashtable_removedup_loops = 0; // 利用 hashtable 去重的轮次。如果只有一轮,则可以免去最后的结果集文件去重 try { foreach (Record rec in loader) { this._app_down.Token.ThrowIfCancellationRequested(); { if (rec.RecordBody != null && rec.RecordBody.Result != null && rec.RecordBody.Result.ErrorCode != ErrorCodeValue.NoError) { #if NO strError = "获得结果集位置偏移 " + (lStart + j).ToString() + " 时出错,该记录已被忽略: " + rec.RecordBody.Result.ErrorString; this.AppendResultText(strError + "\r\n"); #endif continue; } string strBiblioRecPath = ""; #if NO // 从册记录XML中获得书目记录路径 // return: // -1 出错 // 1 成功 int nRet = GetBiblioRecPath( rec.Path, rec.RecordBody.Xml, out strBiblioRecPath, out strError); if (nRet == -1) return -1; #endif if (rec.Cols == null || rec.Cols.Length == 0) { #if NO strError = "获得结果集位置偏移 " + (lStart + j).ToString() + " 时出错: rec.Cols 为空"; this.AppendResultText(strError + "\r\n"); #endif continue; } // return: // -1 出错 // 1 成功 int nRet = GetBiblioRecPathByParentID( rec.Path, rec.Cols[0], out strBiblioRecPath, out strError); if (nRet == -1) return -1; // 缓冲并局部去重。局部去重可以减轻后面全局去重的压力 if (temp_table.Contains(strBiblioRecPath) == false) { temp_table.Add(strBiblioRecPath, null); if (temp_table.Count > _removeDup_batchSize) { FlushTable(temp_table, resultset); temp_table.Clear(); hashtable_removedup_loops++; } } //DpRecord record = new DpRecord(rec.Path); //item_paths.Add(record); } } } catch (Exception ex) { strError = ex.Message; return -1; } // if (bToBiblioRecPath == true) { // 最后一批 if (temp_table.Count > 0) { FlushTable(temp_table, resultset); temp_table.Clear(); hashtable_removedup_loops++; } resultset.Idle += new IdleEventHandler(biblio_paths_Idle); // 2016/1/23 原来这里是 -=,令人费解 try { #if DETAIL_LOG this.WriteErrorLog("开始排序结果集, count=" + resultset.Count); #endif // 归并后写入结果集文件 resultset.QuickSort(); resultset.Sorted = true; if (hashtable_removedup_loops > 1) { // 全局去重 #if DETAIL_LOG this.WriteErrorLog("开始对结果集去重, count=" + resultset.Count); #endif resultset.RemoveDup(); #if DETAIL_LOG this.WriteErrorLog("结束对结果集去重, count=" + resultset.Count); #endif } } finally { resultset.Idle -= new IdleEventHandler(biblio_paths_Idle); } } return 0; }
public IEnumerator GetEnumerator() { string strError = ""; string strRange = "0-9999999999"; long lTotalCount = 0; // 总命中数 long lExportCount = 0; string strTimeMessage = ""; DigitalPlatform.Stop stop = this.Stop; StopStyle old_style = StopStyle.None; if (stop != null) { old_style = stop.Style; stop.Style = StopStyle.EnableHalfStop; // API的间隙才让中断。避免获取结果集的中途,因为中断而导致 Session 失效,结果集丢失,进而无法 Retry 获取 stop.OnStop += stop_OnStop; } ProgressEstimate estimate = new ProgressEstimate(); try { int i_path = 0; foreach (string path in this.Paths) { ResPath respath = new ResPath(path); string strQueryXml = "<target list='" + respath.Path + ":" + "__id'><item><word>" + strRange + "</word><match>exact</match><relation>range</relation><dataType>number</dataType><maxCount>-1</maxCount></item><lang>chi</lang></target>"; cur_channel = Channels.CreateTempChannel(respath.Url); Debug.Assert(cur_channel != null, "Channels.GetChannel() 异常"); try { long lRet = cur_channel.DoSearch(strQueryXml, "default", out strError); if (lRet == -1) { strError = "检索数据库 '" + respath.Path + "' 时出错: " + strError; throw new Exception(strError); } if (lRet == 0) { strError = "数据库 '" + respath.Path + "' 中没有任何数据记录"; continue; } lTotalCount += lRet; // 总命中数 estimate.SetRange(0, lTotalCount); if (i_path == 0) { estimate.StartEstimate(); } if (stop != null) { stop.SetProgressRange(0, lTotalCount); } SearchResultLoader loader = new SearchResultLoader(cur_channel, stop, this.ResultSetName, this.FormatList, this.Lang); loader.BatchSize = this.BatchSize; foreach (KernelRecord record in loader) { if (stop != null) { stop.SetProgressValue(lExportCount + 1); } lExportCount++; yield return(record); } strTimeMessage = "总共耗费时间: " + estimate.GetTotalTime().ToString(); } finally { cur_channel.Close(); cur_channel = null; } // MessageBox.Show(this, "位于服务器 '" + respath.Url + "' 上的数据库 '" + respath.Path + "' 内共有记录 " + lTotalCount.ToString() + " 条,本次导出 " + lExportCount.ToString() + " 条。" + strTimeMessage); i_path++; } } finally { if (stop != null) { stop.Style = old_style; stop.OnStop -= stop_OnStop; } } }
// 获得读者记录, 为登录用途。注意,本函数不检查是否符合。 // 该函数的特殊性在于,它可以用多种检索入口,而不仅仅是条码号 // parameters: // strQueryWord 登录名 // 0) 如果以"RI:"开头,表示利用 参考ID 进行检索 // 1) 如果以"NB:"开头,表示利用姓名生日进行检索。姓名和生日之间间隔以'|'。姓名必须完整,生日为8字符形式 // 2) 如果以"EM:"开头,表示利用email地址进行检索。注意 email 本身应该是 email:xxxx 这样的形态。也就是说,整个加起来是 EM:email:xxxxx // 3) 如果以"TP:"开头,表示利用电话号码进行检索 // 4) 如果以"ID:"开头,表示利用身份证号进行检索 // 5) 如果以"CN:"开头,表示利用证件号码进行检索 // 6) 否则用证条码号进行检索 // return: // -2 当前没有配置任何读者库,或者可以操作的读者库 // -1 error // 0 not found // 1 命中1条 // >1 命中多于1条 int GetReaderRecXmlForLogin( RmsChannel channel, string strLibraryCodeList, string strQueryWord, int nMaxHitCount, string strFormatList, out List<KernelRecord> records, out string strError) { strError = ""; records = new List<KernelRecord>(); int nRet = 0; LibraryApplication app = this; string strFrom = "证条码"; string strMatch = "exact"; // 构造检索式 string strQueryXml = ""; strQueryWord = strQueryWord.Trim(); string strPrefix = ""; string strName = ""; SplitLoginName(strQueryWord, out strPrefix, out strName); bool bBarcode = false; // 注意如果这里增补新的prefix, 函数 SplitLoginName() 也要同步修改 // 没有前缀 if (strPrefix == "") { bBarcode = true; strFrom = "证条码"; strMatch = "exact"; } else if (strPrefix == "NB:") { bBarcode = false; strFrom = "姓名生日"; strMatch = "left"; strQueryWord = strName; } else if (strPrefix == "EM:") { bBarcode = false; strFrom = "Email"; strMatch = "exact"; strQueryWord = strName; // 2016/4/11 注 strName 内容应为 email:xxxxx } else if (strPrefix == "TP:") { bBarcode = false; strFrom = "电话"; strMatch = "exact"; strQueryWord = strName; } else if (strPrefix == "ID:") { bBarcode = false; strFrom = "身份证号"; strMatch = "exact"; strQueryWord = strName; } else if (strPrefix == "CN:") { bBarcode = false; strFrom = "证号"; strMatch = "exact"; strQueryWord = strName; } else if (strPrefix == "RI:") { bBarcode = false; strFrom = "参考ID"; strMatch = "exact"; strQueryWord = strName; } else { strError = "未知的登录名前缀 '" + strPrefix + "'"; return -1; } List<string> dbnames = new List<string>(); // 获得读者库名列表 // parameters: // strReaderDbNames 库名列表字符串。如果为空,则表示全部读者库 // return: // -1 出错 // >=0 dbnames 中包含的读者库名数量 nRet = GetDbNameList("", strLibraryCodeList, out dbnames, out strError); if (nRet == -1) return -1; if (dbnames.Count == 0) { if (app.ReaderDbs.Count == 0) strError = "当前尚没有配置读者库"; else strError = "当前没有可以操作的读者库"; return -2; } { int i = 0; foreach (string strDbName in dbnames) { if (string.IsNullOrEmpty(strDbName) == true) continue; Debug.Assert(String.IsNullOrEmpty(strDbName) == false, ""); // 最多100条 // 2007/4/5 改造 加上了 GetXmlStringSimple() string strOneDbQuery = "<target list='" + StringUtil.GetXmlStringSimple(strDbName + ":" + strFrom) // 2007/9/14 + "'><item><word>" + StringUtil.GetXmlStringSimple(strQueryWord) + "</word><match>" + strMatch + "</match><relation>=</relation><dataType>string</dataType><maxCount>" + nMaxHitCount + "</maxCount></item><lang>zh</lang></target>"; if (string.IsNullOrEmpty(strQueryXml) == false) { Debug.Assert(String.IsNullOrEmpty(strQueryXml) == false, ""); strQueryXml += "<operator value='OR'/>"; } strQueryXml += strOneDbQuery; i++; } if (i > 1) { strQueryXml = "<group>" + strQueryXml + "</group>"; } } if (String.IsNullOrEmpty(strQueryXml) == true) { strError = "尚未配置读者库"; return -1; } long lRet = channel.DoSearch(strQueryXml, "default", "", // strOuputStyle out strError); if (lRet == -1) { strError = "channel.DoSearch() error : " + strError; return -1; } // not found if (lRet == 0) { strError = "没有找到"; return 0; } long lHitCount = lRet; if (lHitCount > 1 && bBarcode == true) { strError = "系统错误: 证条码号为 '" + strQueryWord + "' 的读者记录多于一个"; return -1; } try { SearchResultLoader loader = new SearchResultLoader(channel, null, "default", strFormatList); foreach (KernelRecord record in loader) { records.Add(record); if (nMaxHitCount >= 0 && records.Count >= nMaxHitCount) break; } return records.Count; } catch (Exception ex) { strError = ex.Message; return -1; } }