问题描述
我已使用Redis的Sorted sets构建游戏的快速排行榜解决方案。 我的任务需要执行两个主要的查询操作:
据我所知,Redis对排序集使用特殊的数据结构,该结构将某种跳过列表与哈希表结合在一起。
现在,我想从Redis迁移到现代IMDG解决方案,并在Hazelcast和Apache Ignite之间进行选择。在Hazelcast / Apache Ignite中,Redis排序集和ZREVRANGE,ZREVRANK操作最接近的类似物是什么?
解决方法
在Hazelcast中,您可以创建IndexType.SORTED
。请查看相关文档Hazelcast Reference Manual: Indexing Queries。
似乎可以利用Apache Ignite
中的query entities。
这是一个原始示例。
<bean class="org.apache.ignite.configuration.CacheConfiguration">
<property name="name" value="testCache"/>
<property name="queryEntities">
<list>
<bean class="org.apache.ignite.cache.QueryEntity">
<property name="keyType" value="com.company.ScoreAndId"/>
<property name="keyFields">
<list>
<value>score</value>
<value>id</value>
</list>
</property>
<property name="valueType" value="com.company.UserInfo"/>
<property name="fields">
<map>
<entry key="score" value="java.lang.Long"/>
<entry key="id" value="java.lang.Long"/>
<entry key="name" value="java.lang.String"/>
</map>
</property>
<property name="indexes">
<list>
<bean class="org.apache.ignite.cache.QueryIndex">
<constructor-arg value="id"/>
</bean>
<bean class="org.apache.ignite.cache.QueryIndex">
<constructor-arg>
<list>
<value>score</value>
<value>id</value>
</list>
</constructor-arg>
<constructor-arg value="SORTED"/>
</bean>
</list>
</property>
</bean>
</list>
</property>
</bean>
之后,可以使用常规的SQL
查询从缓存中获取数据。表名将是"USERINFO"
,因为它是从类型名UserInfo
继承而来的,无论如何都可以reconfigure。模式来自缓存名称。
例如:
SELECT * FROM "testCache"."USERINFO" WHERE SCORE > ? AND SCORE < ?;
它将进行范围索引扫描。
您可以运行EXPLAIN
命令来检查正在使用的索引(在示例中,我们有2个索引。)
explain SELECT * FROM "testCache"."USERINFO" WHERE SCORE > ? AND SCORE < ?;
,
在像IMDG这样的分布式系统中实施排行榜似乎是一项非常复杂的任务。如果我错了,请纠正我,但是ZSET在Redis
中更像是本地事物,您的Sorted Set不能大于最大碎片。
我想将此问题分为两种情况:本地和分布式。
- 本地。通常,在
Ignite
中,可以通过创建缓存REPLICATED来实现。可以将本地SQL
查询与LIMIT/OFFSET
一起使用,但据我所知,没有快速(O(log(n)
)索引跳转可以从具有特定编号的某行开始进一步扫描。这使得无法实现O(log(n) + m)
的整体复杂性,其中m
是窗口大小。从理论上讲,可以实现这一点。我已经在“ Apache Ignite开发人员”列表上启动了discussion。无论如何,这都取决于您的实际用例:您拥有多少用户,目标延迟是多少,百分位数等。 - 已分发。在这里,它变得更加复杂,因为无法保证在使用PARTITIONED缓存的情况下,它足以从排名从
a
到b
的每个节点获取值,因为数据{{3} }(亲和力将键映射到节点)可能不是绝对偶数。这意味着您需要扫描每个节点上的整个索引,直到达到b
(或上面最接近的值)为止。