Redis进行职位搜索

网友投稿 533 2022-11-26

Redis进行职位搜索

Redis进行职位搜索

本文可作为redis in action第七章的读书笔记

需求背景

职位数据库里有这样的数据

job1:skill1,skill2,skill4

job2:skill3,skill2

而每一个应聘者,都有若干个技能

给定一个应聘者,从库里筛选出他能胜任(职位要求的仅能这个人必须都具备,当然他有更多的职位并没有要求的技能也是OK的)的职位

方案一

这也是最符合我们第一思维的逻辑

有一个set域 job:jobid

里面存放了这个职位需要的技能

在检查某个人是否能胜任某个职位的时候

用job:jobid与它本人的技能求差集

如果差集的size等于0说明职位要求的技能,这个人都具备,他可以胜任这个工作

如果差集的size大于0说明职位要求的技能,这个人并不都具备,他不能胜任这个工作

public void addJob(Jedis conn, String jobId, String... requiredSkills) { conn.sadd("job:" + jobId, requiredSkills); } @SuppressWarnings("unchecked") public boolean isQualified(Jedis conn, String jobId, String... candidateSkills) { String temp = UUID.randomUUID().toString(); Transaction trans = conn.multi(); for(String skill : candidateSkills) { trans.sadd(temp, skill); } trans.expire(temp, 5); trans.sdiff("job:" + jobId, temp); List response = trans.exec(); Set diff = (Set)response.get(response.size() - 1); return diff.size() == 0; }

测试代码:

public class Chapter07Test { static Jedis conn = null; static Chapter07 c=null; @BeforeClass public static void initConn(){ System.out.println("test before"); conn = new Jedis("10.150.0.80"); conn.auth("dlf123123"); c=new Chapter07(); } @Test public void testIsQualifiedForJob() { System.out.println("\n----- testIsQualifiedForJob -----"); c.addJob(conn, "test", "q1", "q2", "q3"); //返回true System.out.println(c.isQualified(conn, "test", "q1", "q3", "q2","q4")); //返回false System.out.println(c.isQualified(conn, "test", "q1", "q2")); }}

OK,上面的代码能正常运行 那么有问题么?

如果库里有10000个职位,那我就得判断10000次

这就是问题

方案二

还有第二种方式

假如有10000个职位,每个职位都有若干个所需技能

我先算出某个人对于这10000个职位里,每个职位都具备几个技能--这个我们称为set-a

然后我还得计算出,每个职位都需要几个技能--这个我们称为set-b

我用setb与seta相减,结果仍然是一个zset集合,member是职位,score等于0的话就说明这个人是能胜任这个工作的#

我们先设计下面几个域

idx:skill:sillId--set集合

这里面列出了,需要这个技能的所有职位信息

idx:jobs:req---zset集合

member是职位 score是这个职位需要的技能的数量

首先将职位与技能添加到库里

public void indexJob(Jedis conn, String jobId, String... skills) { Transaction trans = conn.multi(); Set unique = new HashSet(); for (String skill : skills) { trans.sadd("idx:skill:" + skill, jobId); unique.add(skill); } // 记录每个职位需要的技能数量 trans.zadd("idx:jobs:req", unique.size(), jobId); trans.exec(); }

好了,我们现在先不看代码了,先说说我们得了解的redis的几个命令

Zunionstore 命令

redis 127.0.0.1:6379> ZRANGE programmer 0 -1 WITHSCORES

1) "peter"

2) "2000"

3) "jack"

4) "3500"

5) "tom"

6) "5000"

redis 127.0.0.1:6379> ZRANGE manager 0 -1 WITHSCORES

1) "herry"

2) "2000"

3) "mary"

4) "3500"

5) "bob"

6) "4000"

# 一共有2个待处理集合分别是programmer和manager

# 给他们的工资分别乘以1和3 我艹 为啥?

# 最后那两个新的工资单 相加

# 结果放到salary集合中

# 公司决定加薪。。。除了程序员。。。

redis 127.0.0.1:6379> ZUNIONSTORE salary 2 programmer manager WEIGHTS 1 3

(integer) 6

redis 127.0.0.1:6379> ZRANGE salary 0 -1 WITHSCORES

1) "peter"

2) "2000"

3) "jack"

4) "3500"

5) "tom"

6) "5000"

7) "herry"

8) "6000"

9) "mary"

10) "10500"

11) "bob"

12) "12000"

另外对于Zunionstore命令来说,如果待操作的集合并不是有序集合(也就是说没有score域),那么系统就默认认为它的score是1

更详细的见:

​​如果后台工程师这个职位本身既在c++这个技能要求里,也在db这个技能要求里

最后得出的数据域里后台工程师这个member对应的score就是2

那么下一个问题

我用setb与seta相减,结果仍然是一个zset集合,member是职位,score等于0的话就说明这个人是能胜任这个工作的#

怎么办?WEIGHTS设为-1不就OK了?

上面那个命令是求并集呀?

去看这个命令:ZINTERSTORE

​​Set findJobs(Jedis conn, String... candidateSkills) { String[] keys = new String[candidateSkills.length]; double[] weights = new double[candidateSkills.length]; for (int i = 0; i < candidateSkills.length; i++) { keys[i] = "skill:" + candidateSkills[i]; weights[i] = 1.0; } Transaction trans = conn.multi(); //这里的idx:jobScores //member是职位 score是我能满足这个职位的技能的数量 //这里面是所有跟我还有点"关系"的职位 //国务院总理这个职位所要求的技能 我一个都没有 //那么 这个idx:jobScores里肯定就没有国务院总理这个职位 String jobScores = zunion( trans, 100, new ZParams().weightsByDouble(weights), keys); System.out.println("jobscores: zrange idx:"+jobScores+" 0 -1 withscores"); // 用需要的技能数 减去我现在有的技能数 String finalResult = zintersect( trans, 100, new ZParams().weightsByDouble(-1, 1), jobScores, "jobs:req"); System.out.println("jobscores: zrange idx:"+finalResult+" 0 -1 withscores"); trans.exec(); return conn.zrangeByScore("idx:" + finalResult, 0, 0); } public String zintersect(Transaction trans, int ttl, ZParams params, String... sets){ return zsetCommon(trans, "zinterstore", ttl, params, sets); } public String zunion(Transaction trans, int ttl, ZParams params, String... sets) { return zsetCommon(trans, "zunionstore", ttl, params, sets); } //把zunionstore和zinterstore提取出来 //使用反射技术 不懂的自己去看反射 //这里产生的中间数据 都不必一直保存 所有有个ttl private String zsetCommon(Transaction trans, String method, int ttl, ZParams params, String... sets) { String[] keys = new String[sets.length]; for (int i = 0; i < sets.length; i++) { keys[i] = "idx:" + sets[i]; } String id = UUID.randomUUID().toString(); try{ Method m=trans.getClass().getDeclaredMethod(method, String.class, ZParams.class, String[].class); System.out.println("method: "+method); m.invoke(trans,"idx:" + id, params, keys); }catch(Exception e){ throw new RuntimeException(e); } trans.expire("idx:" + id, ttl); return id; }

再看看测试代码:

@Test public void testIndexAndFindJobs() { System.out.println("\n----- testIndexAndFindJobs -----"); c.indexJob(conn, "test1", "q1", "q2", "q3"); c.indexJob(conn, "test2", "q1", "q3", "q4"); c.indexJob(conn, "test3", "q1", "q3", "q5"); // System.out.println(c.findJobs(conn, "q1").size()); Iterator result =null; // result=c.findJobs(conn, "q1", "q3", "q4").iterator(); // printIterator(result); result = c.findJobs(conn, "q1", "q3", "q5").iterator(); printIterator(result); result = c.findJobs(conn, "q8", "q9", "q310", "q11", "q12").iterator(); printIterator(result); }

测试结果:

test before ----- testIndexAndFindJobs ----- method: zunionstore jobscores: zrange idx:51926856-67fd-42ba-8620-fa90cae4f4d8 0 -1 withscores method: zinterstore jobscores: zrange idx:b6df8812-f725-46fd-a121-a08c75248d5a 0 -1 withscores test3 abc method: zunionstore jobscores: zrange idx:784ce6b6-5218-4e4d-ac53-b235cf317374 0 -1 withscores method: zinterstore jobscores: zrange idx:990004c6-2c9e-4c26-95b9-248dbf2a5864 0 -1 withscoresabc

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:spring cloud config和bus组件实现自动刷新功能
下一篇:Nginx静态资源性能测试
相关文章

 发表评论

暂时没有评论,来抢沙发吧~