我有两个表,一个是图像,另一个是描述哪些用户喜欢哪些图像。第二个表每个图像/用户组合只有一行。我想编写一个查询,该查询将返回数据库中的其他图像中有多少人喜欢'尽可能共同。因此,表格如下:
images
+----+----------+
| id | filename |
+----+----------+
images_users
+----------+---------+
| image_id | user_id |
+----------+---------+
我的查询是:
SELECT images.filename FROM
images_users INNER JOIN images ON images.id = images_users.image_id
WHERE images_users.user_id IN ( .... list of user IDs ....)
AND NOT images.id = <current image id>
GROUP BY images.id ORDER BY COUNT(images.id) DESC LIMIT 10;
也就是说,查找匹配&#39; likers&#39;的所有行,按图片ID分组,按其计数顺序,并返回前10名。我还排除当前图片ID,因为当然这总是最受欢迎的。
当我想要匹配的用户ID列表增长时,此查询可能需要几分钟才能运行 - 尽管我只在家用PC上运行它,而不是大型服务器。
我有点感觉我被困在这里,因为我的数据根据规则进行了规范化,但对于服务器而言,这只是一项艰巨的工作。我有连接中的所有列和查询的索引。
我可以用其他方式表示此信息,这可能会缩短查询时间吗?
-----编辑以下问题-----
查询的解释输出如下:
explain SELECT filename from images_users inner join images on id = image_id
where image_users.user_id in
(162,591,596,603,856,1654,1967,2219,3640,3847,3956,9201,10601)
and not images.image_id = 41578 group by images.id order by count(images.id) desc limit 10;
"1" "SIMPLE" "images_users" "range" "u_id_2,u_id,i_id" "i_id" "4" \N "9086346" "Using where; Using temporary; Using filesort"
"1" "SIMPLE" "images" "eq_ref" "PRIMARY" "PRIMARY" "4" "images_users.i_id" "1" ""
images_users表中大约有10,000个用户,大约1.5M图像和大约6M行。
答案 0 :(得分:0)
我在这里回答了我自己的问题,因为我接受了@Jason的评论,跟着neo4j的链接,安装了它,学到了一些优秀的查询语言Cyper和bam。问题解决了。
我拿走了所有数据,200万张图片和1000万张关系,并将它们推入neo4j。首先,我创建了索引。
CREATE INDEX ON :Image(filename)
CREATE INDEX ON :User(name)
然后针对用户和图像之间的每个关系运行以下查询。如果它们不存在,这也会为用户和图像创建节点。
MERGE (i:Image{filename:'...'})
MERGE (u:User{name:'...'})
CREATE (u)-[:LIKES]->(i)
这有点慢,我确实最终改进了导入过程,但结果数据是一样的。然后搜索查询变为
MATCH (n:Image{filename:'...'})<-[]-(u:User)-[l]->(i:Image)
WITH count(l) AS c, i.filename AS f
ORDER BY c DESC LIMIT 10
在任何情况下,这是一种更具表现力的编写查询的方式,并且比同等的MySQL查询运行速度快一个数量级,在该查询中存在所有适当的索引。
其他查询,也可能最终成为非常昂贵的联接,比如向我展示超过五个喜欢的所有图像,非常有效
MATCH (n:Image) where size ( (n)<-[]-() ) > 3 return n.filename
LIMIT 20