如何有效地比较和搜索整数列表?

时间:2009-01-03 10:23:46

标签: python postgresql

我有一个填充了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' )

如何有效地选择匹配的对象?

7 个答案:

答案 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)

在我看来,setsissubset()方法正是您所寻找的:

tags(1, 2, 3).issubset(q(1, 2, 3, 4))

如果tagsq都是set类的子类。 但我同意其他答案,在数据库中解决这个问题将是一个更好的解决方案。

答案 6 :(得分:0)

对不起看起来我很难很好地解释这个问题:)

这里的'postgresql'标签比'python'更有意义。 具有IS NULL条件的自加入TAG表是我真正需要的。

SQLalchemy也是一个很好的建议。

谢谢大家。