@yanglfyangl
2018-07-19T03:11:24.000000Z
字数 4341
阅读 747
在这里的关系引擎的重点还是关系存储引擎,并不是关系查询引擎
- 前期用Redis开发,功能调试
- 上线前转成Pika+Redis模式
- 存储基本关系
- 关系列举(尽量不要有上限)
- 基本关系查找
- 共同关系查找
- WIR关系查找
- 支持GEO查找
- 支持一定的排行榜能力
目前不支持的
- 事务
- 超过2跳的查询(这部分最好用图来做)
基于关系的特点(可失败,由用户补偿),所以第一期暂时不支持事务。
/*为了让关系的命名更加合理,命名最好符合如下模式"node名" +"关系" + ”node名“*/class NodeType:{public String User = "User"public String Circle = "Circle"public String Crowd = "Crowd"}class RelationEnum:{public String BeFriend = "ToBeFriends",public String UserJoinToCircle = "UserJoinToCircle"public String CrowdJoinToCircle = "CrowdJoinToCircle"}//如果是双向,则建立两个set,将关系全存下来。//如果是单向,则只存一方关系即可。class Direction:{public int Single = 0;public int Both = 1;}/*我称为Who In Reation搜索,比如:解释一下什么是Who In Relation搜索1. "Who in Relation"并不是传统意义上的搜索,他还是通过key来找value的一种方式。2. 主要支持的都是通过K-V的交并集等操作能做到的结果。下面个例子:想搜索我在某个圈子中的好友,可以这样做{whoID = 人的ID;whoRelation = RelationEnum.ToBeFriendsinID = 圈子ID;inRelation = RelationEnum.UserJoinToCircle;}实现方式是:取出两个Set来,做交集操作。*/class WIRCriteria:{String whoID;RelationEnum whoRelation;String inID;RelationEnum inRelation;}class RelationEngine:{/*更新节点的信息。1. 如果不存在,则创建;2. 如果存在,则更新;*/public bool updateNodeBasicInfo(String type,String nodeID, Map<String, String> info);/*删除节点为了达到性能尽可能高,删除节点时只做1. 删除节点基本信息;2. 删除本节点对应的关系;*/public bool deleteNode(String nodeID);/*建立关系结果为在KV库中增加1. Key为:A. 主动部分(比如加入群,是人主动)"rel_"+relation+"_ID_"+fromID+""意思是:由这个fromID来drive了这样一个relationB. 包含/被动部分(比如加入群,是群)"rel_"+relation+"_ID_"+toID+""意思是:某个toID中,包含了某个relation中加入了新值。2. value格式为:Set*/public Boolean joinRelation(String fromID, String toID, RelationEnum relation, Direction direction);/*退出关系*/public Boolean quiteRelation(String fromID, String toID, RelationEnum relation, RelationDirection direction);/*获取关系列表*/public List<String> getRelationList(String fromID, String toID, RelationEnum relation, String startID, int count);/*获取两两共同关系,例如:共同好友,共同圈子,共同社群。。。*/public List<String> getCommonRelations(String id1, String id2, RelationEnum relation);/*获取WIR关系*/public List<String> searchWIR(WIRCriteria cirteria);}
/*稍复杂些的查询逻辑用GEOCriteria主要业务逻辑是1. 通过BaseQuery和Relation各做一次搜索2. count最大值为10003. 得到结果后做交集4. 交集结果小于10时,但结果超过1000时,则再做一次搜索。*/class GEOCriteria:{BaseQuery:{groupNamelatlonradio}Relation:{String whoID;RelationEnum relation;}}
/*更新某个节点的 GPS相关信息如果不设置分组,则是放到大组中。(比如默认查找人员,或圈子等,不需要设置分组名)*/public bool updateNodeGeoInfo(String groupName, String nodeID, String lon, String lat);/*获取某个组中按中心点和半径的”Node"列表*/public List<String> searchByLocation(String groupName, String lon, String lat, double radio, int count)/*按结果进行搜索*/public List<String> searchByCriteria(GEOCriteria cirteria)
/*更新某个节点的 "Scroe"(分数) 相关信息*/public bool updateNodeScroeInfo(String GroupName, String nodeID, score);其它的与GeoHandler类似。。。
//生成或从mysql获取用户IDRelationEngine engine = RelationEngine.getInstance();engine.updateNodeBasicInfo(NodeType.User, usrID, userInfoDTO);
//生成或从库中获取圈子IDRelationEngine engine = RelationEngine.getInstance();engine.updateNodeBasicInfo(NodeType.Circle, cirID, userInfoDTO);
RelationEngine engine = RelationEngine.getInstance();engine.joinRelation(usrID, circleID, RelationEnum.UserJoinToCircle, Direction.Both)
RelationEngine engine = RelationEngine.getInstance();engine.GetGeoHandler().updateNodeGeoInfo(userID, ..., "UserLocation");//查找当前GPS坐标周围的人List<String> ret = engine.GetGeoHandler().searchByLocation("UserLocation", 100);//查找当前GPS坐标周围的我的好友Criteria criteria = new Criteria()criteria.setBaseQuery();criteria.setRelationQuery();List<String> ret = engine.GetGeoHandler().searchByCriteria(criteria);
RelationEngine engine = RelationEngine.getInstance();engine.GetRankHandler().updateNodeRankInfo(userID, ..., "UserLocation");//获取某个排行榜的用户列表List<String> ret = engine.GetRankHandler().getListByRank("UserLocation", 100);//获取某个排行榜中某个ID所在的位置int ret = engine.GetRankHandler().getListByRank("UserLocation", myID);//获取我好友在某个排行榜中的排行Criteria criteria = new Criteria()criteria.setBaseQuery();criteria.setRelationQuery();//获取排行榜IDString rankID = engine.GetGeoHandler().queryRank(criteria);//获取某个排行榜中某个ID所在的位置,-1表示未上榜;-2表示排行榜已过期不存在了。int ret = engine.GetRankHandler().getListByRank(rankID, myID);
有很多类似这样的场景,比如
- 获取我的好友列表,但不是整体的好友列表,而是某个时刻之后的好友列表。
- 不光是好友列表,还有变化,比如说是删除了好友,好友信息更新了等等操作。
- 还需要支持分页
如果不能支持,则对于移动端缓存数据,几乎就变成了不可能,特别是想支持很大数据量的情况。
所以,关系引擎需要支持类似的操作记录。
方法:
- 每个releation都建立一个###_log 的zset, scroe为当前的时间戳。
- 写入格式为:[ID_ACTION, 时间戳]
- 对于所有的add, delete操作,写入入对列。
- 对于update操作。分两种
- 全局性的node update更新,放到一个全局性的update更新 log中。(全局)
- 某个特殊关系的,直接写入关系对应的当中去。(局部)
需要按某个时间戳获取时
- 将全局与局部的进行并集。
- 找出前端时间戳之后的数据。
- 将数据进行去重。
- 进行后续操作。