2012-03-29 11 views
5

Jak mogę wykonać kwantowe zapytania w DB z Django?
Nie znalazłem nic na ten temat w dokumentach.
Czy powinienem pobrać zestaw zapytań, a następnie filtrować programowo?Jak wykonać zapytania bitowe DB w Django?

Jeśli jesteś zainteresowany, używam ops bitowe jako alternatywa dla IN() wypowiedzi w bardzo dużych i złożonych zapytań, w celu poprawy wydajności.
Mam DB zawierający miliony pozycji (rekordy). Niektóre pola używają binarnej reprezentacji właściwości elementu.
Na przykład: pole Kolor może mieć wiele wartości, tak jest skonstruowany w taki sposób:

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

(są to wartości binarne)
Więc jeśli przedmiot ma kolorach czerwonym i niebieskim, z Kolor pole będzie zawierać 0101.
Gdy użytkownik zapytuje DB, używam bitowego-OR, aby znaleźć dopasowania (zamiast IN(), który jest bardzo wolny).

Odpowiedz

4

Sprawdź django-bitfield, to działa dobrze w/PostgreSQL (prawdopodobnie również dobrze MySQL)

+0

Cześć, jestem rzeczywiście przy MySQL (myślenie o migracji do MongoDB, ale nie obsługuje bitowe odpytuje ATM) – user1102018

+0

@ user1102018 Właśnie sprawdziłem kodu, powinien działać na MySQL, ponieważ używa normalnego pola liczb całkowitych i zwykłego bitowego & i | które są obsługiwane przez MySQL. – okm

3

można wykonać na poziomie bazy danych operacje bitowe z F objects.

Jeśli pole jest nieujemne, oznacza to, że stan field & mask > 0 można ponownie napisać pod numerem . Jeśli chcesz sprawdzić, czy wszystkie bity z mask mają zastosowanie ((field & mask) == mask), możesz zbudować poprzednie wyrażenie dla każdego bitu, a następnie scalić warunki przez sql AND. Zobacz przykład, jak to zrobić. (Custom QuerySet ma zastosowanie tylko dla wygody. Jeśli używasz starych wersji django, możesz implementować has_one_of i has_all jako oddzielne funkcje lub metody klas, lub lepiej PathThroughManager). Uwaga 1 * F jest obejście zmusić nawias nad operacji bitowej, w przeciwnym razie django (jak dla wersji 1.5) będzie produkować złe SQL (colors >= colors & mask, porównanie ma wyższy priorytet, więc będzie to oznaczać 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

źródło, z którego się tego nauczyłeś. czy to jest twój własny pomysł? –

+0

Tak, to był mój własny pomysł, znalazłem to pytanie podczas poszukiwania rozwiązania, a kiedy w końcu zaimplementowałem je w naszym projekcie, właśnie wróciłem, by podzielić się tym pomysłem. –

6

Dla PostgreSQL db to polubisz użyj parametrów .extra() z django orm.

Na przykład:

SomeModel.objects.extra(where=['brand_label & 3 = 3']) 
Powiązane problemy