如何基于字段对MarkLogic 9 Optic Java API查询结果分区
用MarkLogic 9 Optic Java API实现按字段分区(保留所有行)
嘿Swati,刚好我对MarkLogic Optic API的窗口函数和聚合功能很熟悉,能帮你找到简便的解决方案,不用多次查询或者聚合丢失数据!
你的需求是按newspaper字段分区展示所有结果、保留原始行,这其实可以通过两种方式实现,对应不同的输出结构:
方式1:保留所有原始行,按分区排序并添加分区标识
这种方法完全保留总行数,给每行打上分区内的行号,同时让同分区的行连续排列,客户端拿到结果后可以轻松分组展示。核心是用窗口函数(Window Functions),这就是Optic API对应SQL PARTITION BY的等效功能。
Java代码示例
PlanBuilder op = PlanBuilder.newPlanBuilder(); ModifyPlan partitionedPlan = op.fromView(recordsSchema, recordsView) // 保留你原有的连接逻辑 .joinInner(op.fromView(productsSchema, productsView), op.on(op.viewCol(recordsView, "md5Digest"), op.viewCol(productsView, "md5Digest"))) .joinInner(op.fromView(occurrencesSchema, occurrencesView), op.on(op.viewCol(productsView, "md5Digest"), op.viewCol(occurrencesView, "md5Digest"))) // 保留原有的过滤条件 .where(op.or( op.and(op.contains(op.col("adDescription"), "SNACK FOODS"), op.eq(op.col("pageNumber"), 5)), op.and(op.eq(op.col("state"), "KY"), op.eq(op.col("issue"), "2018-01-21")) )) // 选择需要的字段,务必包含分区字段newspaper .select( op.col("newspaper"), op.col("pageNumber"), op.col("state"), op.col("adDescription"), op.col("issue") ) // 添加窗口函数:按newspaper分区,生成分区内行号 .window( op.partitionBy(op.col("newspaper")), op.col("row_in_partition").as(op.rowNumber()) ) // 先按newspaper排序,再按原有的issue降序,确保同分区的行排在一起 .orderBy(op.col("newspaper"), op.desc(op.col("issue")));
查询返回的结果里,所有原始行都保留,并且按newspaper分组排列,每行还会有row_in_partition字段标记它在当前分区的位置,客户端只需要遍历结果,遇到新的newspaper值就切换分组展示即可。
方式2:直接生成结构化分组结果(分区对应行数组)
如果希望数据库直接返回类似你示例的结构(每个分区对应一个行数组),可以用groupBy配合arrayAgg聚合函数,把同分区的所有行打包成数组,虽然总行数变成分区的数量,但所有原始行数据都完整保留在数组里。
Java代码示例
PlanBuilder op = PlanBuilder.newPlanBuilder(); ModifyPlan groupedPlan = op.fromView(recordsSchema, recordsView) // 保留原有的连接和过滤逻辑 .joinInner(op.fromView(productsSchema, productsView), op.on(op.viewCol(recordsView, "md5Digest"), op.viewCol(productsView, "md5Digest"))) .joinInner(op.fromView(occurrencesSchema, occurrencesView), op.on(op.viewCol(productsView, "md5Digest"), op.viewCol(occurrencesView, "md5Digest"))) .where(op.or( op.and(op.contains(op.col("adDescription"), "SNACK FOODS"), op.eq(op.col("pageNumber"), 5)), op.and(op.eq(op.col("state"), "KY"), op.eq(op.col("issue"), "2018-01-21")) )) // 选择需要的字段,包含分区字段newspaper .select( op.col("newspaper"), op.col("pageNumber"), op.col("state"), op.col("adDescription"), op.col("issue") ) // 按newspaper分组,将同组的行聚合成数组 .groupBy(op.col("newspaper"), op.col("rows").as(op.arrayAgg(op.map( op.entry("pageNumber", op.col("pageNumber")), op.entry("state", op.col("state")), op.entry("adDescription", op.col("adDescription")), op.entry("issue", op.col("issue")) ))) ) .orderBy(op.col("newspaper"));
这个查询的结果会是每个newspaper一行,包含一个rows数组,数组里是该分区的所有原始行数据,和你给出的示例结构完全匹配,客户端拿到后可以直接遍历每个分区展示对应的行。
关键说明
- MarkLogic 9的Optic API完全支持窗口函数,
op.window()方法就是实现SQLPARTITION BY逻辑的核心,它不会合并行,只会给每行添加分区相关的计算字段。 arrayAgg是Optic的聚合函数,用来把多行数据打包成数组,完美解决了你担心groupBy会合并行丢失数据的问题。
内容的提问来源于stack exchange,提问作者Swati
相关产品推荐
相关产品推荐

