马克逻辑光学 API
Marklogic Optic API
我一直在测试将我们的一个系统迁移到 Marklogic 9 并使用 Optics API。
我们的一个功能涉及按 member_id、member_name 对声明进行分组并获取总和和计数,所以我做了这样的事情:
var results = op.fromView('test', 'claims')
.groupBy(['member_id', 'member_name'], [
op.count('num_claims', 'claim_no'),
op.sum('total_amount', 'claim_amount')
])
.orderBy(op.desc('total_amount'))
.limit(200)
.result()
.toArray();
以上工作正常。结果的形式为
[
{
member_id: 1,
member_name: 'Bob',
num_claims: 10,
total_amount: 500
},
...
]
但是,我们还有一个字段 "company",其中每个索赔都在不同的公司下提交。基本上相关的视图栏是claim_no, member_id, member_name, company, claim_amount
我希望能够显示一个列,其中列出 member_id/member_name 提出索赔的不同公司,以及每家公司的索赔数量。
即我希望我的结果类似于:
[
{
member_id: 1,
member_name: 'Bob',
num_claims: 10,
total_amount: 500,
companies: [
{
company: 'Ajax Co',
num_claims: 8
},
{
company: 'Side Gig',
num_claims: 2
}
]
},
...
]
我试过这样的事情:
results = results.map((member, index, array) => {
var companies = op.fromView('test', 'claims')
.where(op.eq(op.col('member_id'), member.member_id))
.groupBy('company', [
op.count('num_claims', 'claim_no')
])
.result()
.toArray();
member.companies = companies;
return member;
});
而且输出似乎是正确的,但执行起来也很慢——差不多一分钟(索赔文件总数约为 120k)
在我们之前的 ML8 实现中,我们为每个成员预先生成摘要文档 - 因此检索速度相当快,缺点是每当我们获得一堆新数据时,所有摘要文档都必须重新生成产生。我希望 ML9 的光学元件 API 可以更轻松地即时执行 retrieval/grouping/aggregates,这样我们就不必这样做了。
理论上,我可以只将公司添加到 groupBy 字段,然后根据需要合并结果查询中的行。但是这种方法的问题是我不能保证我会获得总金额的前 200 名(就像我最初的查询一样)
所以,问题是:有没有更好的方法在合理的执行时间内做到这一点?还是我应该坚持预先生成摘要文档?
如果我的理解正确,您应该能够使用分组两次的单个 Optic 查询来实现它。
- 第一组应该聚合到公司级别
- 第二组聚合到会员级别,用数组aggregate收集明细
查询可能如下所示:
const results =
op.fromView('test', 'claims')
.groupBy(['member_id', 'company'], [
'member_name',
op.count('company_claims', 'claim_no'),
op.sum('company_amount', 'claim_amount')
])
.select(['member_id',
'member_name',
'company_claims',
'company_amount',
op.as('company_desc', op.jsonObject([
op.prop('company', op.col('company')),
op.prop('num_claims', op.col('company_claims'))
]))
])
.groupBy(['member_id'], [
'member_name',
op.sum('num_claims', 'company_claims'),
op.sum('total_amount', 'company_amount'),
op.arrayAggregate('companies', 'company_desc')
])
.orderBy(op.desc('total_amount'))
.limit(200)
.result()
.toArray();
顺便说一句,如果您在聚合列表中指定了一个列,它就会被抽样。如果该列对整个组具有相同的值(我认为 "member_name" 就是这种情况),您可以对其进行采样而不是将其指定为附加分组键。
此外,在现代 JavaScript 中通常避免使用 var,而使用 const 或 let。
希望对您有所帮助,
我一直在测试将我们的一个系统迁移到 Marklogic 9 并使用 Optics API。
我们的一个功能涉及按 member_id、member_name 对声明进行分组并获取总和和计数,所以我做了这样的事情:
var results = op.fromView('test', 'claims')
.groupBy(['member_id', 'member_name'], [
op.count('num_claims', 'claim_no'),
op.sum('total_amount', 'claim_amount')
])
.orderBy(op.desc('total_amount'))
.limit(200)
.result()
.toArray();
以上工作正常。结果的形式为
[
{
member_id: 1,
member_name: 'Bob',
num_claims: 10,
total_amount: 500
},
...
]
但是,我们还有一个字段 "company",其中每个索赔都在不同的公司下提交。基本上相关的视图栏是claim_no, member_id, member_name, company, claim_amount
我希望能够显示一个列,其中列出 member_id/member_name 提出索赔的不同公司,以及每家公司的索赔数量。
即我希望我的结果类似于:
[
{
member_id: 1,
member_name: 'Bob',
num_claims: 10,
total_amount: 500,
companies: [
{
company: 'Ajax Co',
num_claims: 8
},
{
company: 'Side Gig',
num_claims: 2
}
]
},
...
]
我试过这样的事情:
results = results.map((member, index, array) => {
var companies = op.fromView('test', 'claims')
.where(op.eq(op.col('member_id'), member.member_id))
.groupBy('company', [
op.count('num_claims', 'claim_no')
])
.result()
.toArray();
member.companies = companies;
return member;
});
而且输出似乎是正确的,但执行起来也很慢——差不多一分钟(索赔文件总数约为 120k)
在我们之前的 ML8 实现中,我们为每个成员预先生成摘要文档 - 因此检索速度相当快,缺点是每当我们获得一堆新数据时,所有摘要文档都必须重新生成产生。我希望 ML9 的光学元件 API 可以更轻松地即时执行 retrieval/grouping/aggregates,这样我们就不必这样做了。
理论上,我可以只将公司添加到 groupBy 字段,然后根据需要合并结果查询中的行。但是这种方法的问题是我不能保证我会获得总金额的前 200 名(就像我最初的查询一样)
所以,问题是:有没有更好的方法在合理的执行时间内做到这一点?还是我应该坚持预先生成摘要文档?
如果我的理解正确,您应该能够使用分组两次的单个 Optic 查询来实现它。
- 第一组应该聚合到公司级别
- 第二组聚合到会员级别,用数组aggregate收集明细
查询可能如下所示:
const results =
op.fromView('test', 'claims')
.groupBy(['member_id', 'company'], [
'member_name',
op.count('company_claims', 'claim_no'),
op.sum('company_amount', 'claim_amount')
])
.select(['member_id',
'member_name',
'company_claims',
'company_amount',
op.as('company_desc', op.jsonObject([
op.prop('company', op.col('company')),
op.prop('num_claims', op.col('company_claims'))
]))
])
.groupBy(['member_id'], [
'member_name',
op.sum('num_claims', 'company_claims'),
op.sum('total_amount', 'company_amount'),
op.arrayAggregate('companies', 'company_desc')
])
.orderBy(op.desc('total_amount'))
.limit(200)
.result()
.toArray();
顺便说一句,如果您在聚合列表中指定了一个列,它就会被抽样。如果该列对整个组具有相同的值(我认为 "member_name" 就是这种情况),您可以对其进行采样而不是将其指定为附加分组键。
此外,在现代 JavaScript 中通常避免使用 var,而使用 const 或 let。
希望对您有所帮助,