1

我目前正在为协调我们的数据进行开发工作。我注意到协调的完成很慢。
我对 NoSQL / MarkLogic 开发相对较新,并且不确定要遵循哪些最佳实践才能实现平稳、更快的协调。

以下是一些事实:

数据加载:

  1. 暂存中加载的数据来自使用关系数据库的 ERP 系统。数据被提取到 CSV 并加载到 MarkLogic
  2. 每个关系表数据都被提取到一个 CSV 文件中。每个表都以单独的实体表示。

后期协调:

  1. 227,826 条记录大约需要 66 分钟才能完成协调
  2. 1074151 条记录完成统一耗时约 4 小时 19 分钟

协调代码片段:

  1. 有许多日期计算逻辑(示例如下)

function getScheduleWindowEnd(businessUnit,targetDateString,schEndDateString)
   {
   	var scheduleWindowEnd = new String();
    var preferredDate = new Date(); 
    var startDayOfWeek = getBUStartDayOfWeek(businessUnit);
    
    if (fn.empty(targetDateString) || targetDateString == null || targetDateString == "" || 
       fn.empty(schEndDateString) || schEndDateString == null || schEndDateString == "")
    {
     tempScheduleWindowEnd = "";
     return "";
    }
    else
    {
      targetDateString = fn.replace(targetDateString, "/", "-") ;
      schEndDateString = fn.replace(schEndDateString,"/","-");

      var targetDate = xs.date(targetDateString);
      var schEndDate = xs.date(schEndDateString);
    
      // Get preferred date
      if (fn.empty(schEndDate)) 
      {
        preferredDate = targetDate;
      }
      else
      {
       preferredDate = schEndDate;
      }
      
      //get target day of week
      var scheduledDayOfWeek = xdmp.weekdayFromDate(preferredDate);
    
      if (scheduledDayOfWeek < startDayOfWeek)
      {
      scheduleWindowEnd = fn.string(addDays(preferredDate,(startDayOfWeek-scheduledDayOfWeek)));  
      }
      else
      {
      scheduleWindowEnd = fn.string(addDays(preferredDate,(startDayOfWeek-scheduledDayOfWeek+7)));
      }
      
      scheduleWindowEnd = fn.replace(fn.substring(scheduleWindowEnd, 1, 10), "-", "/");
      tempScheduleWindowEnd = scheduleWindowEnd;
    }
     
     return scheduleWindowEnd
   }

  1. 主实体从其他实体获取一些元素数据(在下面的示例中,Table2 是其他实体)

<StatusDescription>${fn.normalizeSpace(getUDCDescription("00", "SS", fn.normalizeSpace(hl.elementText(source, "WASRST", true))))}</StatusDescription>

function getUDCDescription(drsy,drrt,drky) {
     let udcRecord =  cts.search(cts.andQuery([
       cts.collectionQuery("ERPSystemSource"),
       cts.collectionQuery("Table2"),
       cts.elementWordQuery(xs.QName("DRSY"), drsy),
       cts.elementWordQuery(xs.QName("DRRT"), drrt),
       cts.elementWordQuery(xs.QName("DRKY"), drky)
     ]))
     
     let docXML = new String();
     for (const item of udcRecord) {
       docXML += hl.encodeXml(fn.normalizeSpace(hl.elementText(item, "DRDL01", true)))
     }
     return docXML;
   }

  1. 一些协调数据是一对一的(直接获取)。请参阅下面的示例:

        <Element1>${hl.elementText(source, "WADOCO", true)}</Element1>
        <Element2>${fn.normalizeSpace(hl.elementText(source, "WAMCU", true))}</Element2>

  1. 有许多 for 循环调用(未嵌套),大约 20 个调用。上面 #2 中的示例:
4

2 回答 2

2

如果可能,我强烈建议您考虑与 MarkLogic 代表一起解决这个问题。提高软件性能可能很复杂,最好与可以与您交流的人建立工作关系。

我总是问的第一个问题是:那么,您期望的 SLA 是多少?在您对自己认为的性能应该是什么样子有一个明确的期望之前,我无法告诉您这是慢还是快,或者您的期望是现实的还是不切实际的。

根据我的经验,性能问题往往属于以下两类之一:软件或基础设施瓶颈。由于从 200k 到 1m 记录的时间外推似乎是线性的,我希望您的瓶颈不是严重的软件问题。

我要做的第一件事是检查 MarkLogic 监控历史并确定您是否充分利用了您的基础设施。如果没有,请尝试增加协调工作负载的线程数和批处理大小,以便充分利用您的基础设施。

如果您正在充分利用您的基础架构,您可以升级您的基础架构,或者您可以开始考虑改进您的软件。

根据您的代码,您可以考虑以下几个建议来改进您的软件:

  1. 使您的 cts.search 调用未经过滤(如果可能)
  2. 尽可能限制 cts.search 调用。我觉得你可能在每份工作中做的不止一个。
  3. 如果您只需要从文档中提取一个元素,请考虑使用 cts.elementValues 代替 cts.search
  4. 规范化空间和其他字符串函数在大文本字符串上可能很繁重。如果您正在使用大字符串,请考虑是否可以减少使用它们的次数。
  5. 我建议为您拉入的每种类型的表在文档上实现一个唯一的 XML 命名空间,这样您就不需要集合查询。
于 2018-08-02T14:30:33.077 回答
0

除了 Rob 的建议之外,您可能还想检查和声中的收集器步骤。看起来您正在将多条记录折叠到一个实体实例中,如果您不迭代所有记录,那效果最好。迭代记录 uris 是默认的收集器实现。您可能希望将其替换为例如您正在创建的实体的某个唯一 id 上的 cts.values。

如果您确实是在迭代 uris,则可能是您重新创建同一个实体实例的次数与它所包含的记录一样多,这意味着浪费大量时间。您可以通过在从干净的数据库运行协调后查看您的最终数据库是否包含大量已删除的片段来检查这一点。

于 2018-08-09T14:00:55.373 回答