我用多维立方体模型(一种数据挖掘算法)来解决这个问题,程序模拟了5万条记录进行测试。测试机器配置是 WinXP SP2,
Pentium4 3.06GHz, 1G 内存。
用传统方法循环比较,测试10000次,用时 125 秒,采用多维立方体模型,用时31秒。采用优化后的多维立方体模型用时15秒。我感觉已经把这种算法的效率发挥到了极致,不过我还有办法把查询速度再提高1倍左右。
我的机器是3年前的配置,如果用目前流行的 intel core 2 duo 普通PC,5秒钟之内我认为还是可以达到的。
近两天我将写一篇博文来专门介绍这个算法。
另外我用的是模拟数据,如果用实际数据,效果可能会更好,为什么会更好,看了我的博文就会知道。
代码没办法在这里贴出来,楼主如果现在想要,请发站内短信给我。
下面我给出程序的主函数,和测试结果:
static void Main(string[] args)
{
//产生模拟数据
UserPreference[] users = GenerateData.Generate(50000);
//设置各分量的匹配条件,和权重
PreferencRank[] pRanks = {
new PreferencRank("红", 12),
new PreferencRank("赵薇", 13),
new PreferencRank("跑步", 14),
new PreferencRank("七里香", 16),
new PreferencRank("铁板烧", 10),
new PreferencRank("丰田", 20),
new PreferencRank("登喜路", 15),
};
//阀值为60,查询10000次
Test(new SimpleAnlayse(), users, pRanks, 60, 10000);
Test(new CubeAnlayse(), users, pRanks, 60, 10000);
Test(new SuperCubeAnalyse(), users, pRanks, 60, 10000);
Console.ReadKey();
}
Test SimpleAnlayse 查询10000次
Count=3
姓名:芮建新, 色调:青,名星:林志林,运动:跑步,歌曲:七里香,小吃:铁板烧,车:丰田,衣服:
太平鸟,得分:60
姓名:吕雨欣, 色调:紫,名星:范冰冰,运动:攀岩,歌曲:七里香,小吃:铁板烧,车:丰田,衣服:
登喜路,得分:61
姓名:赖文婷, 色调:灰,名星:周笔畅,运动:跑步,歌曲:七里香,小吃:兰州拉面,车:丰田,衣
服:登喜路,得分:65
用时 125 秒
Test CubeAnlayse 查询10000次
Count=3
姓名:芮建新, 色调:青,名星:林志林,运动:跑步,歌曲:七里香,小吃:铁板烧,车:丰田,衣服:
太平鸟,得分:60
姓名:吕雨欣, 色调:紫,名星:范冰冰,运动:攀岩,歌曲:七里香,小吃:铁板烧,车:丰田,衣服:
登喜路,得分:61
姓名:赖文婷, 色调:灰,名星:周笔畅,运动:跑步,歌曲:七里香,小吃:兰州拉面,车:丰田,衣
服:登喜路,得分:65
用时 31 秒
Test SuperCubeAnalyse 查询10000次
Count=3
姓名:芮建新, 色调:青,名星:林志林,运动:跑步,歌曲:七里香,小吃:铁板烧,车:丰田,衣服:
太平鸟,得分:60
姓名:吕雨欣, 色调:紫,名星:范冰冰,运动:攀岩,歌曲:七里香,小吃:铁板烧,车:丰田,衣服:
登喜路,得分:61
姓名:赖文婷, 色调:灰,名星:周笔畅,运动:跑步,歌曲:七里香,小吃:兰州拉面,车:丰田,衣
服:登喜路,得分:65
用时 15 秒
?这个问题(基于集合)用数据库去处理应该是强项吧?
那只是因为你不会用而已.--->对楼主说的。
5万的数据量应该还好吧,最近也刚好在做类似的项目。
什么叫给定的权重及属性在1万到2万间呢?是每个用户有1万个属性,还是说有一万种权重还是说要进行一万次查询?根本没说清楚啊。
我记得数据结构里面有总算法是求出最小路径
你可以通过给出的查询条件和阀值先算出不符合条件的所有情况
然后把这些过滤掉
然后再获得剩下的条件 就ok了
别权重求和在输出
例如:你给的这个条件阀值是60
那么只要权重超过40获取不到的就全部过滤掉
条件1是车,歌曲,衣服不对的不用选(车的权重是20,歌曲是16,衣服是15,这3个都不对就超过40了)
然后是车,歌曲,运动不对的不用选等等
吧所有的不属于的情况列出来(这个可以通过类似最小树的算法吧所有的条件都列出来)
然后再查询条件里面 通过select * from table where id not in ( select id from table where (车不相等 and 歌曲不对 and 衣服不对) or 等等) sql我不擅长 应该可以优化一下的
这样就可以求出符合条件的人
然后再对每个人进行权重求和
在输出结果就可以了吧
阀值超过50用算法写出不属于的情况
阀值低于50用算法写出属于的情况
过滤条件是越少越好
ps:以上仅仅是个人见解,我没做过这种算法优化
提前建立好倒排索引,然后按照权重由大到小的顺序使用属性值进行查询,对结果做集合的并操作,同时计算集合中各个元素的潜力分数,如果当前分数加上潜力分数不够阈值的话,从集合中去除。
其中的倒排索引是提前建好的,不应算在5s时间内。
主要的操作是查询和集合合并,指定了多少个属性,就得有多少个查询,每个查询的时间基本是常数的了。
合并操作的复杂性明天再分析,太晚了,睡觉去。
~~~~~~~~~~~~
每个查询的结果列表都是排好序的(倒排表就可以这么建)
合并两个排好序的列表复杂性是列表长度之和
列表中每个元素维持一个当前分数,记录在已经观察了的属性上它所获得的分数
同时有一个全局的潜力分数,表示集合中的元素最多还能得多少分(其实就是剩余属性的分数之和)
在合并时,发现一个元素的当前分数加上潜力分数不足阈值,则将其从当前和所有后续列表中删除
如此得到的最后的列表就是所有慢足要求的元素了
如果平均一个属性值出现在1/K的元素中,合并的复杂性就是 10000×50000/K,K的值就是效率提升的倍数。加上其间对不满足元素的过滤,应该还有不小的提升。
楼主看看有什么启发没有,呵呵,代码懒得写了,只提供一下想法。还有倒排索引的概念是信息检索里的,我是搞信息检索的,望多多交流。