lua-zset icon indicating copy to clipboard operation
lua-zset copied to clipboard

讨论下是否还需要zset.score的设计

Open lizijie opened this issue 3 years ago • 3 comments

大多数编程语言本身都提供数组类型,并且可以自定义排序。以lua为例

local list = { {name="a", count=1}, {name="b", count=2 }
table.sort(list, function(a, b)
    if a.count ~= b.count then
         return a.count < b.count
    else
         return a.name < b.name
    end
    return false
end)

自定义排序,是为了方便调用端,做复杂的排序比较(复合排序)

redis zset为什么通过score定义排序?按我个人理解,这是为了将多维条件转换成一维条件,去隔离调用端各种乱七八槽的关系,如redis需要支持脚本化编程、两钟语言间据结构转换

谈回贵项目,是想在本地lua环境中提供zsert支持。那么将多维条件转换成一维条件就没必要了,lua业务层不需要老是想着如何转换成一维比较。比较函数可以在zsert.new时定义

local zs = zset.new(function(a, b)
    -- todo someting here
end)

lizijie avatar Oct 22 '22 03:10 lizijie

我猜测是效率问题,每对比一次要调用一次lua函数。可以写个 benchmark 对比一下试试?

hanxi avatar Oct 22 '22 12:10 hanxi

我猜测是效率问题,每对比一次要调用一次lua函数。可以写个 benchmark 对比一下试试?

以上只是初步构想并未实现。如果差别不大,或只是稍微高一丢丢,应该还可以接受。 可以的,我之后可以尝试实现并对比一下。

lizijie avatar Oct 22 '22 13:10 lizijie

底层是跳表,排序是在c层实现的,如果通过回调函数支持自定义排序,性能会降低比较多;

这个数据结构本身不是那么通用的,适合用来做排行榜之类,有score的场景。

xjdrew avatar Feb 23 '23 05:02 xjdrew

性能问题是不是可以传个c函数进去,然后用类似 ffi 的方式执行?

hanxi avatar Sep 03 '25 10:09 hanxi

性能问题是不是可以传个c函数进去,然后用类似 ffi 的方式执行?

我猜测是效率问题,每对比一次要调用一次lua函数。可以写个 benchmark 对比一下试试

我没实验测试过性能。 你早前提到的很有道理,每次调用一次lua函数会产生的切换消耗,skiplist以海量数据高性能定位的角度,为了高性能还是不传lua回调比较好,不然方向走偏。 后来,我有另一个不成熟的想法,可是我未去偿试实验,看看就好~~! 参考数据库sort接口设计。类似mongodb中的find/sort

-- 格式
db.collection.find(query).sort(sorting_criteria)
-- 样例
db.ranks.find().sort({ score: -1,  ts:-1 })

sorting_criteria: 是一个数组,第一个元素的优先级最高

对应地,在skilplist:slInsert就需要开放存放这个数组,而skiplist::slGetRank需要传入sorting_criteria

可是,存放数据又是另外一个新问题~

lizijie avatar Sep 03 '25 10:09 lizijie

@lizijie 如果像 mongo 的 sort 的话,可以把 score 改为数组,然后 compare 就不设计为函数,而是一个32位整数就行,这样就支持 score 数组长度就支持最大 32 了。0 和 1 就相当于 mongo sort 里的 1 和 -1 。

local sorting_criteria = {
    [1] = 1, -- score
    [2] = 0, -- ts
}
local sort_bits = pack_bits(sorting_criteria)
local zs = zset.new(sort_bits)

hanxi avatar Sep 03 '25 15:09 hanxi