在 MarkLogic 中检索没有范围索引的元素值
Retrieving element values without range indexes in MarkLogic
我在MarkLogic中有以下情况。我有一个包含大量文档的数据库,每个文档都有数百个字段。现在假设,对于其中一个字段,我想从大量文档中检索所有值(使用 cts:search
)。我有哪些选择?
显然,我可以在这里使用范围索引。但是,当我探索我的数据集时,这意味着我必须将范围索引应用到我的所有字段,这似乎……有点矫枉过正。此外,我完全可以接受每个查询需要一点时间。
所以我尝试 运行 一个简单的 cts:search 查询:cts:search(//Cost, cts:collection-query("myCollection))
。此函数 returns 我感兴趣的元素的值(和元素),并且在我查找少于 10k 的文档时工作正常。但是,当我探索包含 1m 个文档的集合时,我收到一个 XDMP-EXPNTREECACHEFULL 错误,这表明 MarkLogic 在检索 XML 节点并将其返回到我的查询控制台之前实际上打开了所有文档。
有什么方法可以更改此查询,使其至少 returns 个结果?
我已经尝试 运行 未过滤的搜索并使用 xdmp:eval
来隔离事务,但到目前为止没有结果。
我相信 Taskbot - https://github.com/mblakele/taskbot - 将有助于避免填充扩展树缓存,因为它将工作拆分为用户定义数量的事务。您是正确的,因为 ML 需要加载每个文档以在没有范围索引的情况下获取值。 Taskbot 至少会通过避免例如在一次交易中加载一百万份文件。
一般来说,非常大的查询是为了计算平均值或趋势,一个样本就足够了。您可以使用带有 "score-random" 选项的 cts.search() 来进行随机抽样。这会导致 "search"(这是搜索引擎术语 - 但当然它实际上是一个查询)的排序是随机的,因此前 10,000 个项目将是一个随机样本,具体取决于您的查询条件。
但如果您需要处理整个数据库或数据集,taskbot、corb、范围索引或在摄取时具体化数据都是选项。
一个选项是执行 CORB job,这会将工作分散到具有多个线程的各个模块执行中。
这将避免扩展树缓存错误的可能性,因为每个文档都是在单个模块执行中处理的,然后将结果收集在一个文件中。您还可以启用 DISK-QUEUE 选项,它允许您处理非常大的 URI 集,而不必将它们全部放入 JVM 的内存中。
CORB 作业将 select 集合中所有文档的 URI,并在 URIS-MODULE. The PROCESS-MODULE returns the values from those Cost
elements. Configure the job to write the results of the process module to a single file using the PROCESS-TASK, and then use a 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=
这听起来很经典'Data Warehouse BI Query'。在这种情况下,可以应用传统数据仓库数据库的概念。这种类型的 BI 查询通过使用 'columar queries'(例如聚合所有 'rows' 但被一个或几个 'columns' 切片——经典的 'sum/min/max/avg of X across all rows'
因此诞生了列存储数据库和现代数据湖变体(Presto、Athena,以及在某些方面的 Hadoop)。 MarkLogic 方法主要是使用范围索引。您提到您必须在 "All my fields" 上应用索引——但您还说聚合函数是 'One Field' 。这是人们可能会错误地将索引的使用混为一谈的地方。我相信你的情况是这样的
A)"Query for candidate documents" 很复杂(可能有 1000 个字段)但是
B)计算所需的值是一个字段(或几个)
您可以通过仅在字段 "B" 上放置目标范围查询(或类似的查询,包括语义索引)来解决此问题,然后使用通用索引,或者如果需要的话使用一些 select目的 "A" 的增强功能。结果可能完全(或大部分)由 indexes
解析
"Data Wherehouse Trick 2"
创建一个临时数据库和林(最好在不同的存储上)。
预处理源数据并对其进行过滤,可能会重新规范化为具有尽可能少的单独 element/attribute 类型的最小表示。
从那查询
如果有足够的内存,这可以完全在内存中完成(使用映射或数组)
妥协;
使用多遍——
第一遍通过理想情况下完全索引可解析的查询来识别包含感兴趣值的文档 ID。如果没有,按上述方法分成几批。
文档 ID 可能适合会话或服务器范围变量。
使用精确的 cts:search 或仅检索 1 值作为序列的 xpath 表达式仅查询必要的值。拥有文档 ID 的前期强制查询计划不需要打开 'possible documents' 仅那些给定的。这些 ID 足以直接针对任何其他索引解决 AND 和 OR 查询(文档包含)。
我在MarkLogic中有以下情况。我有一个包含大量文档的数据库,每个文档都有数百个字段。现在假设,对于其中一个字段,我想从大量文档中检索所有值(使用 cts:search
)。我有哪些选择?
显然,我可以在这里使用范围索引。但是,当我探索我的数据集时,这意味着我必须将范围索引应用到我的所有字段,这似乎……有点矫枉过正。此外,我完全可以接受每个查询需要一点时间。
所以我尝试 运行 一个简单的 cts:search 查询:cts:search(//Cost, cts:collection-query("myCollection))
。此函数 returns 我感兴趣的元素的值(和元素),并且在我查找少于 10k 的文档时工作正常。但是,当我探索包含 1m 个文档的集合时,我收到一个 XDMP-EXPNTREECACHEFULL 错误,这表明 MarkLogic 在检索 XML 节点并将其返回到我的查询控制台之前实际上打开了所有文档。
有什么方法可以更改此查询,使其至少 returns 个结果?
我已经尝试 运行 未过滤的搜索并使用 xdmp:eval
来隔离事务,但到目前为止没有结果。
我相信 Taskbot - https://github.com/mblakele/taskbot - 将有助于避免填充扩展树缓存,因为它将工作拆分为用户定义数量的事务。您是正确的,因为 ML 需要加载每个文档以在没有范围索引的情况下获取值。 Taskbot 至少会通过避免例如在一次交易中加载一百万份文件。
一般来说,非常大的查询是为了计算平均值或趋势,一个样本就足够了。您可以使用带有 "score-random" 选项的 cts.search() 来进行随机抽样。这会导致 "search"(这是搜索引擎术语 - 但当然它实际上是一个查询)的排序是随机的,因此前 10,000 个项目将是一个随机样本,具体取决于您的查询条件。
但如果您需要处理整个数据库或数据集,taskbot、corb、范围索引或在摄取时具体化数据都是选项。
一个选项是执行 CORB job,这会将工作分散到具有多个线程的各个模块执行中。
这将避免扩展树缓存错误的可能性,因为每个文档都是在单个模块执行中处理的,然后将结果收集在一个文件中。您还可以启用 DISK-QUEUE 选项,它允许您处理非常大的 URI 集,而不必将它们全部放入 JVM 的内存中。
CORB 作业将 select 集合中所有文档的 URI,并在 URIS-MODULE. The PROCESS-MODULE returns the values from those Cost
elements. Configure the job to write the results of the process module to a single file using the PROCESS-TASK, and then use a 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=
这听起来很经典'Data Warehouse BI Query'。在这种情况下,可以应用传统数据仓库数据库的概念。这种类型的 BI 查询通过使用 'columar queries'(例如聚合所有 'rows' 但被一个或几个 'columns' 切片——经典的 'sum/min/max/avg of X across all rows' 因此诞生了列存储数据库和现代数据湖变体(Presto、Athena,以及在某些方面的 Hadoop)。 MarkLogic 方法主要是使用范围索引。您提到您必须在 "All my fields" 上应用索引——但您还说聚合函数是 'One Field' 。这是人们可能会错误地将索引的使用混为一谈的地方。我相信你的情况是这样的 A)"Query for candidate documents" 很复杂(可能有 1000 个字段)但是 B)计算所需的值是一个字段(或几个)
您可以通过仅在字段 "B" 上放置目标范围查询(或类似的查询,包括语义索引)来解决此问题,然后使用通用索引,或者如果需要的话使用一些 select目的 "A" 的增强功能。结果可能完全(或大部分)由 indexes
解析"Data Wherehouse Trick 2" 创建一个临时数据库和林(最好在不同的存储上)。 预处理源数据并对其进行过滤,可能会重新规范化为具有尽可能少的单独 element/attribute 类型的最小表示。 从那查询 如果有足够的内存,这可以完全在内存中完成(使用映射或数组)
妥协; 使用多遍—— 第一遍通过理想情况下完全索引可解析的查询来识别包含感兴趣值的文档 ID。如果没有,按上述方法分成几批。 文档 ID 可能适合会话或服务器范围变量。 使用精确的 cts:search 或仅检索 1 值作为序列的 xpath 表达式仅查询必要的值。拥有文档 ID 的前期强制查询计划不需要打开 'possible documents' 仅那些给定的。这些 ID 足以直接针对任何其他索引解决 AND 和 OR 查询(文档包含)。