在MarkLogic中检索没有范围索引的元素值

时间:2018-07-06 12:20:49

标签: marklogic

我在MarkLogic中遇到以下情况。我有一个包含大量文档的数据库,每个文档包含数百个字段。现在说,对于一个字段,我想从一大套文档中检索所有值(使用cts:search)。我有什么选择?

很显然,我可以在这里使用范围索引。但是,当我浏览数据集时,这意味着我必须将范围索引应用于我的所有字段,这似乎...。此外,我对每条查询都花一点时间非常满意。

因此,我尝试运行一个简单的cts:search查询:cts:search(//Cost, cts:collection-query("myCollection))。该函数返回我感兴趣的元素的值(和元素),并且当我查找少于10k的文档时效果很好。但是,当我浏览一个包含100万个文档的集合时,出现一个XDMP-EXPNTREECACHEFULL错误,这表明MarkLogic实际上是在检索XML节点并将其返回到我的查询控制台之前实际上打开了所有文档。

是否可以更改此查询,使其至少返回结果?

我尝试运行未过滤的搜索并使用xdmp:eval隔离事务,但到目前为止没有结果。

4 个答案:

答案 0 :(得分:1)

我相信Taskbot-https://github.com/mblakele/taskbot-将有助于避免填充扩展的树缓存,因为它会将工作分为用户定义的事务数。您是正确的,因为ML需要加载每个文档才能在没有范围索引的情况下获取值。 Taskbot至少会避免诸如在一次交易中加载一百万个文档。

答案 1 :(得分:1)

通常,非常大的查询用于计算平均值或趋势,并且样本足够且适当。您可以将cts.search()与“ score-random”选项一起使用以进行随机采样。这会导致“搜索”(即搜索引擎术语,但实际上确实是查询)的顺序是随机的,因此前10,000个项目将是随机样本,具体取决于您的查询条件。

但是,如果您需要处理整个数据库或数据集,则可以选择taskbot,corb,范围索引或在摄取时实现数据。

答案 2 :(得分:0)

一个选择是执行CORB job,这将把工作分解成具有多个线程的单个模块执行。

这将避免出现扩大的树缓存错误的可能性,因为每个文档都在单个模块执行中处理,然后将结果收集在文件中。您还可以启用DISK-QUEUE选项,该选项使您可以处理非常大的URI集,而不必将它们全部放入JVM的内存中。

CORB作业将选择集合中所有文档的URI,并在URIS-MODULE中包含要报告的元素。 PROCESS-MODULE返回来自那些Cost元素的值。配置作业,以使用PROCESS-TASK将过程模块的结果写入单个文件,然后使用POST-BATCH-TASK来对值进行排序和删除。

下面是一个示例CORB选项文件,用于配置作业以实现所需的功能。您将需要调整XCC-CONNECTION-URI才能连接到数据库。

# how to connect to the database
XCC-CONNECTION-URI=xcc://myUsername:myPassword@localhost:8200

# An inline XQuery module to find the URIs of docs that have a Cost element and are in the myCollection
URIS-MODULE=INLINE-XQUERY|declare variable $URIS := cts:uris("", (), cts:and-query(( cts:collection-query("myCollection"), cts:element-query(xs:QName("Cost"), cts:true-query()) )) ); count($URIS), $URIS

# for every URI, extract and return the value of the Cost element(s)
PROCESS-MODULE=INLINE-XQUERY|declare variable $URI as xs:string external; fn:doc($URI)//Cost/string()

# write the results of the process module execution to a file
PROCESS-TASK=com.marklogic.developer.corb.ExportBatchToFileTask

# the name of the output file to write (use full path, or also use EXPORT-FILE-DIR)
EXPORT-FILE-NAME=cost-values.txt

# after batch processing is complete, modify the output file with a post-batch-task
POST-BATCH-TASK=com.marklogic.developer.corb.PostBatchUpdateFileTask

# sort and dedup the values in the export file
EXPORT-FILE-SORT=ascending|distinct

# how many threads you want processing the docs
THREAD-COUNT=10

DISK-QUEUE=true
# A location to store temporary files required for the disk queue, sorting and dedup, etc. (default is Java temp dir)
#TEMP-DIR=/temp

# Override the TEMP-DIR location with a different path to be used for the DISK-QUEUE
#DISK-QUEUE-TEMP-DIR=

答案 3 :(得分:0)

这听起来像是经典的“数据仓库BI查询”。在这种情况下,可以应用传统数据仓库数据库的概念。此类BI查询通过使用'列查询'(例如所有'行'上的聚合但被一个或几个'列'切成薄片-经典的'所有行中X的总和/最小/最大/平均')来举例说明。 因此诞生了列存储数据库和现代数据湖变体(Presto,Athena以及某种程度上的Hadoop)。 MarkLogic方式最主要是使用范围索引。您提到您必须在“我的所有字段”上应用索引-但您还说聚合函数是“一个字段”。这是错误地混淆索引使用的地方。我相信你的情况是如此 A)“查询候选文档”很复杂(可能是1000个字段) B)计算所需的值是一个(或几个)

您可以通过以下方法解决此问题:仅在字段“ B”上放置目标范围查询(或类似查询,包括语义索引),然后使用通用索引,或者根据需要对目的“ A”进行一些选择增强。结果可能完全(或很大程度上)可以通过索引解决

“ Data Wherehouse Trick 2” 创建一个临时数据库和林(最好在其他存储上)。 预处理源数据并将其过滤掉,可能将其重新规范化为最小的表示形式,并尽可能少地使用单独的元素/属性类型。 从中查询 只要有足够的内存,就可以完全在内存中完成(使用映射或数组)

妥协; 使用多次通过- 第一遍通过理想情况下完全可索引解析的查询来识别包含感兴趣值的文档ID。如果不是,则按上述方式分成几批。 文档ID可能适合会话或服务器范围变量。 仅使用精确的cts:search或xpath表达式查询必要的值,该表达式仅检索1值作为序列。预先获得文档ID会强制查询计划仅打开给定的“可能文档”。这些ID足以直接解决针对任何其他索引的AND和OR查询(文档包含)。