我们在MarkLogic中拥有庞大的数据集,文档分布在多个集合中。我们需要通过搜索分布在这些集合中的文档来开发报告。
样本数据集:
Collection1 - Inventory [Contains 5 million Inventory documents]
URI: /inventory/inv1
<xml>
<INVENTORY>
<ItemName>10</ItemName>
<InventoryQuantity>100</InventoryQuantity>
.
.
</INVENTORY>
</xml>
Collection2 - Item[Contains 1 million Item documents]
URI: /item/item1
<xml>
<Item>
<ItemName>10</ItemName>
<ItemWmos>
<UnitPrice>895</UnitPrice>
.
.
<ItemWmos>
.
.
</Item>
</xml>
For each Inventory in the Inventory collection
Step 1 : Get "ItemName", its "InventoryQuantity" and for the same "ItemName" find "UnitPrice" from Item document in Item collection.
Step 2 : CurrentInventoryValue = InventoryQuantity * UnitPrice
Step 3 : TotalInventoryValue = TotalInventoryValue + CurrentInventoryValue;
Repeat;
使用下面的XQuery,我已经达到了上述报告要求。然而,执行和显示超时异常需要大量时间。我无法在这里利用路径范围索引,因为我必须将"ItemName“和它的"InventoryQuantity”放在一起,并在具有相同项目名称的不同集合文档中搜索单价。
XQuery:
sum(for $doc in cts:search(doc(), cts:and-query((cts:collection-query("Inventory"))))
[(fn:string-length(//INVENTORY/ItemName/text()) > 0) and (fn:string-length(//INVENTORY/InventoryQuantity/text()) > 0)]
let $itemName := $doc//INVENTORY/ItemName/text()
let $inventoryQuantity := $doc//INVENTORY/InventoryQuantity/text()
return (
for $doc in cts:search(doc(), cts:and-query((cts:collection-query("Item"))))[//Item/ItemName/text()=$itemName
and (fn:string-length(//ItemWmos/UnitPrice/text()) > 0)]
return ($inventoryQuantity * $doc//ItemWmos/UnitPrice/text())
))
如何有效地在MarkLogic中实现这样复杂的查询需求?
发布于 2019-09-10 07:20:20
波段援助方法:
通过将XPath表达式重写为绝对表达式并将它们转换为cts查询逻辑,您可能可以获得更好的性能。但是,即使它解决了眼前的问题,它也不会扩大到更远的范围(因为您可以迭代的文档数量没有限制):
(注意:我还没有测试过这段代码,所以可能存在语法错误)
sum(for $doc in cts:search(doc(), cts:and-query((cts:collection-query("Inventory"))), "unfiltered")
let $itemName := $doc/xml/INVENTORY/ItemName/string()
let $inventoryQuantity := $doc/xml/INVENTORY/InventoryQuantity/string()
where
fn:string-length($itemName) gt 0 and fn:string-length($inventoryQuantity) gt 0
return (
for $doc in cts:search(doc(), cts:and-query((cts:collection-query("Item")), cts:elementValueQuery("ItemName", $itemName)), "unfiltered")
return (xs:integer($inventoryQuantity) * xs:integer($doc/xml/Item/ItemWmos/UnitPrice/string()))
))
可扩展方法#1:
我要做的第一件事是将您在MarkLogic中拥有的/inventory/ data转换为以下格式,并将其还原为所摄取的数据:
<envelope>
<headers xmlns="http://yoursite.com/item/headers"> <!-- Note the unique namespace -->
<ItemName>10</ItemName>
<InventoryQuantity>100</InventoryQuantity>
<UnitPrice>85</UnitPrice>
<ItemPrice>8500</ItemPrice>
</headers>
<attachments>
<INVENTORY>
<ItemName>10</ItemName>
<InventoryQuantity>100</InventoryQuantity>
.
.
</INVENTORY>
<Item>
<ItemName>10</ItemName>
<ItemWmos>
<UnitPrice>895</UnitPrice>
.
.
</ItemWmos>
.
.
</Item>
</attachments>
</envelope>
现在,要运行报告,只需在<ItemPrice>
上放置一个<ItemPrice>
并运行cts:总和-合计。
如果您使用DataHub框架,您可以更简单地管理用于提取不相交数据并协调它的过程。
可扩展方法#2:
您可以保持数据的原样,但也可以将TDE视图放在其之上,这将对数据进行索引,并允许您使用Optic来运行性能连接和从中聚合。这有一些背景开销,这使得方法1在苹果与苹果之间的比较中表现得更好,但是快速运行更广泛的各种查询的灵活性,而不必改变吞食,可能会使它对您来说是值得的。
发布于 2019-10-14 21:49:30
请在URI上使用xdmp:目录进行迭代。
let $var1:=<xml>
<INVENTORY>
<ItemName>10</ItemName>
<InventoryQuantity>100</InventoryQuantity>
</INVENTORY>
<INVENTORY>
<ItemName>10</ItemName>
<InventoryQuantity>101</InventoryQuantity>
</INVENTORY>
<INVENTORY>
<ItemName>12</ItemName>
<InventoryQuantity>102</InventoryQuantity>
</INVENTORY>
</xml>
let $var2:=
<xml>
<Item>
<ItemName>10</ItemName>
<ItemWmos>
<UnitPrice>895</UnitPrice>
</ItemWmos>
</Item>
<Item>
<ItemName>11</ItemName>
<ItemWmos>
<UnitPrice>896</UnitPrice>
</ItemWmos>
</Item>
<Item>
<ItemName>12</ItemName>
<ItemWmos>
<UnitPrice>897</UnitPrice>
</ItemWmos>
</Item>
</xml>
let $mergeInvertory:= <merge>{for $in in $var2//Item/ItemName[. eq $var1//INVENTORY/ItemName]
return <mergeFile>{$in/..,$var1//ItemName[. eq $in]/following-sibling::InventoryQuantity}</mergeFile>
}</merge>
let $CurrentInventoryValue:=<mergeInventory>{for $item in $mergeInvertory/mergeFile
return <INVENTORY><ItemName>{$item//ItemName}</ItemName><UnitPrice>{data($item//UnitPrice)}</UnitPrice><InventoryQuantity>{$item//InventoryQuantity}</InventoryQuantity><TotalInventoryQuantity>{$item//UnitPrice * sum($item//InventoryQuantity)}</TotalInventoryQuantity></INVENTORY>
}</mergeInventory>
return $CurrentInventoryValue
发布于 2019-09-10 10:50:12
ItemName在库存中只出现一次吗?每个ItemName值是否只出现在一个库存中?如果是这样的话,您可以使用包含cts:*-co-occurrences
函数的范围索引来获取两个“表”,然后将它们相乘。
let $itemQuantities := cts:element-value-co-occurrences(
xs:QName('ItemName'),
xs:QName('InventoryQuantity'),
'map',
cts:collection-query('Inventory')
)
let $itemPrices := cts:element-value-co-occurrences(
xs:QName('ItemName'),
xs:QName('UnitPrice'),
'map',
cts:collection-query('Item')
)
return fn:sum(
for $itemName in map:keys($itemQuantities)
return map:get($itemQuantities, $itemName) * map:get($itemPrices, $itemName)
)
https://stackoverflow.com/questions/57871156
复制