一、实现思路
1.按比例求分摊: 分摊金额/实际付款金额 = 个数*单价/该单原始总金额
2.所以: 分摊金额 = 个数*单价*实际付款金额/该单原始总金额
3.由于有除法的存在, 结果我们需要做四舍五入, 会导致精度的丢失
4.一个订单对应多个详情, 每个详情均做四舍五入, 他们的和可能与该订单的实际支付总金额不等
订单 详情 1 详情 2 详情 3
原始: 120 40 40 40
分摊: 100 33.33 33.33 33.33
5.需要消除这个bug
如果有 3 个详情:
前面的详情使用乘除: 分摊金额 = 个数*单价*实际付款金额/该单原始总金额
最后一个详情使用减法: 分摊金额 = 实际付款总金额
6.难点: 如何知道最后一个详情
当前详情
个数*成单价 == 该单原始总金额
7.需要记录的状态:
∑前面分摊总金额
∑前面详情的个数*单价
OLAP在线分析处理查询:
hive,hbase+phoenix
kylin
es
Clickhourse
![微信图片_20201123200131](https://i-blog.csdnimg.cn/blog_migrate/fb85efb1c9127304ef2cc1fe0c67c7f9.png)
二、实现代码
orderWideDetail
.mapPartitions((it: Iterator[OrderWide]) => {
val client: Jedis = MyRedisUtil.getClient
val r = it.map(orderWide => {
val preTotalKey = s"pre_total:${orderWide.order_id}"
val preShareKey = s"pre_share:${orderWide.order_id}"
val preTotalTemp: String = client.get(preTotalKey)
val preTotal: Double = if (preTotalTemp != null) preTotalTemp.toDouble else 0D
val preShareTemp: String = client.get(preShareKey)
val preShare: Double = if (preShareTemp != null) preShareTemp.toDouble else 0D
val current = orderWide.sku_num * orderWide.sku_price
if (current == orderWide.original_total_amount - preTotal) {
val share = orderWide.final_total_amount - preShare
orderWide.final_detail_amount = share
client.del(preTotalKey)
client.del(preShareKey)
println("最后一单...")
} else {
val shareTemp = current * orderWide.final_total_amount / orderWide.original_total_amount
val share = math.round(shareTemp * 100).toDouble / 100
orderWide.final_detail_amount = share
client.incrByFloat(preShareKey, share)
client.incrByFloat(preTotalKey, current)
println("不是最后一单...")
}
orderWide
})
client.close()
r
})
三、将数据写入clickhouser
val clickHouseUrl = "jdbc:clickhouse://hadoop162:8123/gmall"
orderWideDetail
.foreachRDD(rdd => {
rdd
.toDS
.write
.option("batchsize", "100")
.option("isolationLevel", "NONE")
.option("numPartitions", "2")
.mode("append")
.jdbc(clickHouseUrl,"order_wide",new Properties())
OffsetManager.saveOffsets(offsetRanges.values.reduce(_ ++ _), groupId, topics)