2012-03-29 20 views
5

¿Cómo puedo realizar consultas bit a bit en la base de datos con Django?
No he encontrado nada al respecto en los documentos.
¿Debo recuperar un queryset y luego filtrarlo programmically?¿Cómo realizar consultas de DB bit a bit en Django?

Si está interesado, utilizo las operaciones de bits como una alternativa a IN() declaraciones en consultas muy grandes y complejas, con el fin de mejorar el rendimiento.
Tengo un DB que contiene millones de elementos (registros). Algunos campos usan representación binaria de una propiedad del elemento.
Por ejemplo: la campo El color puede tener varios valores, por lo que es estructurado así:

0001 - Red 
0010 - Green 
0100 - Blue 
1000 - White 

(estos son los valores binarios)
Así que si un elemento tiene los colores rojo y azul, la color campo contendrá 0101.
Cuando un usuario consulta la base de datos, uso bitwise-OR para buscar coincidencias (en lugar de IN(), que es muy lento).

Respuesta

4

Comprobar django-bitfield, funciona bien w/PostgreSQL (probablemente también así MySQL)

+0

Hola, soy en realidad el uso de MySQL (pensando en migrar a MongoDB, pero no soporta bit a bit consulta ATM) – user1102018

+0

@ user1102018 que he acabo de comprobar el código, debería funcionar en MySQL, porque usa el campo entero normal y el bit a bit normal y | todos son compatibles con MySQL. – okm

3

Puede llevar a cabo a nivel de base de datos de operaciones bit a bit con F objects.

Si el campo no es negativo, significa que la condición field & mask > 0 se puede volver a escribir como (field > 0) AND (field >= (field & mask)). Si desea verificar si se aplican todos los bits de mask ((field & mask) == mask), puede compilar la expresión previa para cada bit y luego combinar las condiciones a través de sql AND. Por favor, vea ejemplos de cómo se puede hacer. (Custom QuerySet es solo por conveniencia. Si utiliza versiones antiguas de django puede implementar has_one_of y has_all como funciones separadas o classmethods, o mejor PathThroughManager). Nota 1 * F es una solución alternativa a la fuerza entre paréntesis durante la operación bit a bit, de lo contrario django (como para la versión 1.5) producirá mala SQL (colors >= colors & mask, la comparación tiene mayor prioridad, por lo que significará TRUE & mask)

import operator 
from django.db import models 
from django.db.models import Q, F 

_bit = lambda x: 2**(x-1) 
RED = _bit(1) 
GREEN = _bit(2) 
BLUE = _bit(3) 
WHITE = _bit(4) 


class ItemColorsQuerySet(models.QuerySet): 

    def has_one_of(self, colors): 
     """ 
      Only those that has at least one of provided colors 
     """ 
     return self.filter(
      colors__gt=0, 
      # field value contains one of supplied color bits 
      colors__gte=1 * F('colors').bitand(reduce(operator.or_, colors, 0)) 
     ) 

    def has_all(self, colors): 
     """ 
      Has all provided colors (and probably others) 
     """ 
     # filter conditions for all supplied colors: 
     # each one is "field value has bit that represents color" 
     colors_q = map(lambda c: Q(colors__gte=1 * F('colors').bitand(c)), colors) 
     # one complex Q object merged via sql AND: 
     # colors>0 and all color-bit conditions 
     filter_q = reduce(operator.and_, colors_q, Q(colors__gt=0)) 
     return self.filter(filter_q) 


class Item(models.Model): 

    name = models.CharField(max_length=100, unique=True) 
    # can handle many colors using bitwise logic. Zero means no color is set. 
    colors = models.PositiveIntegerField(default=0) 

    objects = ItemColorsQuerySet.as_manager() 
+0

fuente de donde lo aprendió. o es tu propia idea? –

+0

Sí, esa fue mi propia idea, encontré esta pregunta mientras buscaba una solución, y cuando finalmente la implementé en nuestro proyecto, volví a compartir la idea. –

6

Para postgres db que podría use .extra() params con django orm.

Por ejemplo:

SomeModel.objects.extra(where=['brand_label & 3 = 3'])