Comparaison de différents filtres django sur l'exemple de la démo de base de données PostgreSQL

Au lieu d'une préface



Tout a commencĂ© par le fait que l'on m'a proposĂ© de participer au projet dans le cadre du sujet «Bases de la programmation Web», au lieu de faire des travaux de laboratoire et des cours, puisque j'ai dĂ©clarĂ© que je voulais faire quelque chose Ă  distance du cours gĂ©nĂ©ral (et donc il y avait dĂ©jĂ  assez de connaissances sur un tas de DRF + Vue, je voulais quelque chose de nouveau). Et donc dans l'un de mes PR sur github, j'ai dĂ©cidĂ© d'utiliser la recherche en texte intĂ©gral (l'affectation y faisait allusion) pour filtrer le contenu, ce qui m'a fait me tourner vers la documentation DjangoĂ  la recherche de la meilleure façon de mettre en Ɠuvre cette entreprise. Je pense que vous connaissez la plupart des mĂ©thodes suggĂ©rĂ©es ici (contient, icontains, trigram_similar). Tous conviennent Ă  certaines tĂąches spĂ©cifiques, mais pas trĂšs bons, Ă  savoir la recherche de texte intĂ©gral. En descendant un peu, je suis tombĂ© sur une section qui parlait de l'interaction de Django et Pgsql pour implĂ©menter la recherche basĂ©e sur des documents, ce qui m'a attirĂ©, car postgre a un outil intĂ©grĂ© pour implĂ©menter cette recherche trĂšs [plein texte]. Et j'ai dĂ©cidĂ© que trĂšs probablement, django fournissait simplement une API pour cette recherche, sur la base de laquelle une telle solution devrait fonctionner et plus prĂ©cise et plus rapide que toute autre option. Le professeur ne m'a pas trop cru, nous nous sommes disputĂ©s avec lui, et il a proposĂ© de mener des recherches sur ce sujet. Et me voici.



DĂ©but des travaux



Le premier problĂšme qui s'est posĂ© devant moi Ă©tait la recherche d'une maquette de base de donnĂ©es, afin de ne pas trouver moi-mĂȘme des choses incomprĂ©hensibles, et je suis allĂ© sur google et j'ai lu le wiki postgres . En consĂ©quence, je me suis installĂ© sur leur base de dĂ©monstration sur les vols Ă  travers la Russie.



, . , . , , , search django.contrib.postgres.search. — contains ( ) icontains ( , , : "Helen" : <Author: Helen Mirren>, <Author: Helena Bonham Carter>, <Author: HĂ©lĂšne Joy>), django. postgresql. tickets small 366733 . passenger_name, , , . .



django



— django . django , , :



$ python manage.py inspectdb > models.py


, , settings.py. . , . , ( ), , 300+ , 10, , . , , curl. .





, , , curl, , . , ( ).



django



, — , queryset - . .



:



Un QuerySet est itĂ©rable et il exĂ©cute sa requĂȘte de base de donnĂ©es la premiĂšre fois que vous l'itĂ©rez. Par exemple, cela imprimera le titre de toutes les entrĂ©es de la base de donnĂ©es:



for e in Entry.objects.all():
       print(e.headline)```




Vue finale pour contient
class TicketListView(g.ListAPIView):
    serializer_class = TicketSerializer

    def get_queryset(self):
        queryset = ''
        params = self.request.query_params

        name = params.get('name', None)

        if name:
            start_time = d.datetime.now()

            queryset = queryset.filter(passenger_name__contains=name)
            print('len of result is {} rows'.format(len(queryset)))

            end_time = d.datetime.now()

            time_diff = (end_time - start_time)
            execution_time = time_diff.total_seconds() * 1000

            print("Filter execution time {} ms".format(execution_time))

        return queryset


Contient



Commençons par contient, cela fonctionne essentiellement comme un WHERE LIKE.



RequĂȘte dans Django ORM / RequĂȘte en sql pour contient
queryset = queryset.filter(passenger_name__contains=name)


SELECT "tickets"."ticket_no", "tickets"."book_ref", "tickets"."passenger_id", "tickets"."passenger_name", "tickets"."contact_data" FROM "tickets" WHERE "tickets"."passenger_name"::text LIKE %IVAN%


Afin d'obtenir le rĂ©sultat de curl, j'ai exĂ©cutĂ© la requĂȘte comme suit (comptĂ© en secondes):



$ curl -w "%{time_total}\n" -o /dev/null -s http://127.0.0.1:8000/api/tickets/?name=IVAN
1,242888


Je mets tout dans un tableau sur la feuille appropriée.



— , 140 1400 . , . ORM 73 600 , 55 100 .



Icontains



Icontains - ( , ). , contains — icontains. .



Django ORM/ sql icontains
queryset = queryset.filter(passenger_name__icontains=name)


SELECT "tickets"."ticket_no", "tickets"."book_ref", "tickets"."passenger_id", "tickets"."passenger_name", "tickets"."contact_data" FROM "tickets" WHERE UPPER("tickets"."passenger_name"::text) LIKE UPPER(%IVAN%)


, , ( 300 ), 200 1500 . ORM — 200 700 .



Full text search ( django.contrib.postgres)



, full text search . 1300 , 1000 1700 . , ORM — 1000 1450 .



class TicketListView(g.ListAPIView):
    serializer_class = TicketSerializer

    def get_queryset(self):
        # queryset = Tickets.objects.all()
        queryset = ''

        params = self.request.query_params

        name = params.get('name', None)

        if name:

            start_time = d.datetime.now()

            queryset = Tickets.objects.filter(passenger_name__search=name)

            end_time = d.datetime.now()

            time_diff = (end_time - start_time)
            execution_time = time_diff.total_seconds() * 1000

            print("Filter execution time {} ms".format(execution_time))

            f = open('results.txt', 'a')

            f.write('{}'.format(execution_time))
            f.write('\n')

            f.close()

        return queryset


Full text search ( rest_framework.filters, — SearchFilter)



FTS, FTS , , contains icontains. 200 1710 .



FTS , . , 800 1120 .



...
from rest_framework import filters as f

class TicketListView(g.ListAPIView):
    queryset = Tickets.objects.all()
    serializer_class = TicketSerializer
    filter_backends = [f.SearchFilter]
    search_fields = ['@passenger_name']


django-filter



contains icontains, . , django-filter - Django ORM.



?



— (, , ) , . — . , ( , , contains/icontains) , , , , .



Dans l'ensemble, ma compréhension de certains des fonctionnements internes de django s'est stabilisée grùce à cette recherche. Et finalement vint la réalisation de la différence entre la recherche de sous-chaßnes et la recherche de texte intégral. La différence dans leur implémentation via Django ORM.




All Articles