MarkLogic Optic查询条件记录占比统计报错及逻辑修正咨询
Optic查询实现条件占比统计的修正方案
原代码错误原因
op:where()是Optic的行过滤算子,语法要求传入2个参数:过滤条件、待过滤的查询计划,不能直接作为op:select()中的列值表达式使用,这是抛出XDMP-TOOFEWARGS参数不足错误的直接原因。- 原逻辑把过滤操作放在
op:group-by()聚合之后执行,此时已经完成了全量计数,原始行的字段(比如BookingCreateDt、Ancillary_QuotePrice)已经被聚合结果替代,无法再基于原始字段做条件判断。 - 原写法中两个
op:count()都在同一个无分组聚合中计算,得到的两个结果都是全量记录数,无法得到符合筛选条件的子集计数。
筛选条件的正确使用方式
要实现「符合条件的记录数 / 全量总记录数」的占比计算,不能直接在视图初始层加全局op:where()过滤——否则全量计数也会被过滤,最终算出来的占比永远是100%。正确做法是在聚合计数时,用op:case()做条件计数,只统计满足筛选条件的Var1数量,Var2保持全量计数即可。
修正后的可运行代码
xquery version "1.0-ml"; import module namespace op="http://marklogic.com/optic" at "/MarkLogic/optic.xqy"; import module namespace ofn="http://marklogic.com/optic/expression/fn" at "/MarkLogic/optic/optic-fn.xqy"; import module namespace osql="http://marklogic.com/optic/expression/sql" at "/MarkLogic/optic/optic-sql.xqy"; declare option xdmp:mapping "false"; let $view := op:from-view("GTM2_Shipment", "Shipment_View") let $Var1 := op:view-col("Shipment_View", "Ancillary_QuotePrice") let $Var2 := op:view-col("Shipment_View", "Shipment_Ref") let $BookingCreateDt := op:view-col("Shipment_View", "BookingCreateDt") (: 提前计算6个月前的日期阈值,避免逐行重复计算 :) let $thresholdDate := osql:dateadd('month', -6, ofn:format-dateTime(fn:current-dateTime(),'[Y0001]-[M01]-[D01]')) return $view => op:group-by((), (: 全量总记录数,不受筛选条件影响 :) op:count("totalCount", $Var2), (: 条件计数:只统计满足两个筛选条件的Var1记录 :) op:sum("conditionCount", op:case( op:when(op:and(( op:gt($Var1, 0), op:gt(ofn:format-dateTime($BookingCreateDt, '[Y0001]-[M01]-[D01]'), $thresholdDate) )), 1), op:else(0) )) ) => op:select( op:as("percentageFinal", op:multiply(100, op:divide(op:col("conditionCount"), op:col("totalCount")))) ) => op:result()
逻辑说明
- 提前计算6个月前的日期阈值,避免逐行重复执行日期计算,提升查询性能。
- 用
op:case()搭配op:sum()实现条件计数:符合筛选条件的行记为1,不符合的记为0,求和结果就是符合条件的总记录数。 - 全量计数
totalCount不受条件影响,始终返回视图内所有记录总数,保证百分比计算的分母正确。
内容的提问来源于stack exchange,提问作者Rashmita Purkayastha
相关产品推荐
相关产品推荐

