我有一个填充了100万个对象的数据库。每个对象都有一个'tags'字段 - 整数集。
例如:
object1: tags(1,3,4)
object2: tags(2)
object3: tags(3,4)
object4: tags(5)
等等。
查询参数是一个整数集,让我们试试q(3,4,5)
object1 does not match ('1' not in '3,4,5')
object2 does not match ('2' not in '3,4,5')
object3 matches ('3 and 4' in '3,4,5' )
object4 matches ('5' in '3,4,5' )
如何有效地选择匹配的对象?
答案 0 :(得分:3)
鉴于您使用的是PostgreSQL,您可以使用其array数据类型及其包含/重叠运算符。
当然,这会将你的应用紧密地绑在PostgreSQL上,这可能是不可取的。另一方面,它可以节省你真正需要的时间编码(即,当你最终必须将它移植到另一个数据库时)
虽然在Python中你有set datatype用于那个确切的操作组,但使用PostgreSQL可能有点过分(取决于性能要求)
>>> a = set([1,2,3])
>>> a
set([1, 2, 3])
>>> 1 in a
True
>>> set([1,2]) in a
False
>>> set([2,3]) & a
set([2, 3])
>>> set([8,9]) & a
set([])
>>> set([1,3]) & a
set([1, 3])
>>>
答案 1 :(得分:3)
通过存储以逗号分隔的标记ID列表,您在数据库设计中犯了一个常见错误。对你进行有效的查询对你来说是一个阻碍者并不奇怪。
您需要在单独的表格中对对象和标签之间的映射进行建模。
CREATE TABLE Tagged (
object_id INT NOT NULL,
tag_id INT NOT NULL,
PRIMARY KEY (object_id, tag_id),
FOREIGN KEY (object_id) REFERENCES Objects(object_id),
FOREIGN KEY (tag_id) REFERENCES Tags(tag_id)
);
为每个对象/标签配对插入一行。当然,这意味着每个object_id
有几行,但没关系。
您可以查询包含标签3,4,5的所有对象:
SELECT DISTINCT object_id
FROM Tagged
WHERE tag_id IN (3, 4, 5);
但是这匹配了你不想要的object1。您希望排除具有不在3,4,5中的其他标记的对象。
SELECT DISTINCT t1.object_id
FROM Tagged t1
LEFT OUTER JOIN Tagged t2
ON (t1.object_id = t2.object_id AND t2.tag_id NOT IN (3, 4, 5))
WHERE t1.tag_id IN (3, 4, 5)
AND t2.object_id IS NULL;
答案 2 :(得分:1)
如果我理解正确,它就像是:
Post-> posttags <-tags
有点架构。
我想知道你为什么这样做?
这是您遇到的问题,因为您正在使用ORM来检索对象和其他延迟加载的关联对象中的数据。
与SQLAlchemy中的Post和Tag类一样,Post mapper具有一个名为“tags”的属性,可以为给定的Post对象加载一组Tag对象。
如果是这样的话,这些操作在ORM中通常非常昂贵,应该使用ORM的SQL语句支持或使用直接dbapi,如psycopg2。 同样,如果从查询加载的对象数量很大(记住你的1Million),你需要拥有大量资源的机器(或者根本不需要纯 ORM不推荐)。
如果它不是ORM而且你的标签仍然像(套)一样存储,那么我认为架构有问题。
posttags
是一个多对多关系,因为我看到它和它自己的一个不同的表(很容易查询),而不是post表中的'set'。
答案 3 :(得分:0)
您尚未说明您希望使用SQL的天气,或者在此之前将数据读入应用程序。从您寻找基于代码的解决方案的事物的声音?
在.NET中,您可以创建一个类实现ICompare接口并编写自己的方法来比较两个返回0或1的值。
答案 4 :(得分:0)
这是基本集理论。将两组相交,如果结果与原始结果相同,则结果为“匹配”。否则不是。
您可以使用多种语言应用此原则。大多数都有用于处理集合的库。您甚至可以使用SQL执行此操作。
答案 5 :(得分:0)
在我看来,sets的issubset()
方法正是您所寻找的:
tags(1, 2, 3).issubset(q(1, 2, 3, 4))
如果tags
和q
都是set
类的子类。
但我同意其他答案,在数据库中解决这个问题将是一个更好的解决方案。
答案 6 :(得分:0)
对不起看起来我很难很好地解释这个问题:)
这里的'postgresql'标签比'python'更有意义。 具有IS NULL条件的自加入TAG表是我真正需要的。
SQLalchemy也是一个很好的建议。
谢谢大家。