Como comparar e lista de inteiros procurar de forma eficiente?

votos
4

Eu tenho um banco de dados preenchida com 1 milhão de objetos. Cada objeto tem um campo 'tags' - conjunto de números inteiros.

Por exemplo:

object1: tags(1,3,4)
object2: tags(2)
object3: tags(3,4)
object4: tags(5)

e assim por diante.

parâmetro de consulta é um conjunto de números inteiros, vamos tentar 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' )

Como selecionar objetos combinados de forma eficiente?

Publicado 03/01/2009 em 11:23
fonte usuário
Em outras línguas...                            


7 respostas

votos
0

Você não declararam o tempo que você gostaria de usar SQL ou se a sua leitura dos dados em um aplicativo antes de fazer isso. De sons de coisas você está procurando uma solução de código com base?

Em .NET você faria uma classe implementar a interface ICompare e escrever seu próprio método para comparar dois valores que quer retornar um 0 ou 1.

Respondeu 03/01/2009 em 11:30
fonte usuário

votos
0

Esta é a teoria conjunto básico. Cruzam os dois conjuntos e se o resultado é o mesmo que o original, em seguida, o resultado é "jogo". Caso contrário, não o seu.

Você pode aplicar este princípio usando muitas línguas. A maioria tem bibliotecas para fazer as coisas com conjuntos. Você mesmo pode fazer isso usando SQL.

Respondeu 03/01/2009 em 11:44
fonte usuário

votos
3

Tendo em conta que você está usando PostgreSQL, você poderia usar a sua gama tipo de dados e sua contém / sobrepõe operadores.

Claro que isso seria amarrar seu aplicativo para PostgreSQL firmemente, que não pode ser desejado. Por outro lado, ele pode te salvar de codificação para quando é realmente necessário (ou seja, quando você finalmente tem que transportá-lo para outro banco de dados)

Embora, dado que em Python você tem o tipo de dados conjunto para esse grupo exato de operações, usando PostgreSQL pode ser um exagero (dependendo dos requisitos de desempenho)

>>> 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])
>>>
Respondeu 03/01/2009 em 11:54
fonte usuário

votos
1

Se eu entendi direito, é algo como um:

Post-> posttags <-tags

esquema kindof.

Eu me pergunto por que você fazê-lo desta maneira?

É um problema que você tenha atingido porque você está usando um ORM que recupera dados em objetos e outros objetos associados carregadas preguiçosos.

Como um Post e classe Tag em SQLAlchemy, com Pós mapeador de ter uma propriedade chamada 'tags' que pode carregar conjunto de objetos Tag para determinado posto de objeto.

Se é assim, esse tipo de operações são geralmente muito caro em ORM do e deve ser feito com o apoio instrução SQL de ORM do ou usando os dbapi da diretos como psycopg2. Novamente, se o número de objetos carregados a partir de uma consulta é enorme (tendo em mente o seu 1Million) você precisa máquina com grande quantidade de recursos (ou talvez nada em tudo - pura ORM não recomendado).

Se não é um ORM e ainda as tags são armazenados como (conjuntos), então eu acho que há algo de errado com o esquema.

posttags é um relacionamento muitos-para-muitos, como eu vê-lo e sua uma tabela diferente por si só (o que é facilmente queriable), não um 'set' na tabela mensagens.

Respondeu 03/01/2009 em 12:32
fonte usuário

votos
0

Parece-me que o issubset()método de conjuntos é o que você está procurando:

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

Se ambos tagse qsão subclasses da setclasse. Mas eu concordo com as outras respostas que resolver isso no banco de dados seria uma solução melhor.

Respondeu 03/01/2009 em 13:13
fonte usuário

votos
3

Você está cometendo um erro comum em design de banco de dados, armazenando uma lista separada por vírgulas de etiqueta de identificação da. Não é uma surpresa que a realização de consultas eficientes contra esse é um bloqueador para você.

O que você precisa é modelar o mapeamento entre objetos e tags em uma tabela separada.

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)
);

Inserir uma linha para cada emparelhamento objeto / tag. Claro, isso significa que você tem várias linhas para cada object_id, mas tudo bem.

Você pode consultar todos os objetos que têm etiquetas 3,4,5:

SELECT DISTINCT object_id
FROM Tagged
WHERE tag_id IN (3, 4, 5);

Mas isso corresponde object1, que você não quer. Você quer excluir objetos que têm outras tags não em 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;
Respondeu 03/01/2009 em 20:09
fonte usuário

votos
0

Eu sinto Muito. Parece que foi difícil para mim explicar o problema bem :)

A tag 'postgresql' Here OS muito mais significativo do que 'python'. Auto juntou mesa TAG com ESTÁ condição NULL é o que eu realmente preciso.

Sqlalchemy também é bom aconselhar.

Obrigado a todos.

Respondeu 04/01/2009 em 11:35
fonte usuário

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more