مقارنة بين مرشحات django المختلفة على سبيل المثال من قاعدة بيانات PostgreSQL

بدلا من مقدمة



بدأ كل شيء بحقيقة أنه عرض علي المشاركة في المشروع في إطار موضوع "أساسيات برمجة الويب" ، بدلاً من القيام بالمختبرات والدورات الدراسية ، حيث ذكرت أنني أردت أن أفعل شيئًا بعيدًا عن الدورة العامة (وبالتالي كان هناك بالفعل ما يكفي من المعرفة على مجموعة من DRF + Vue ، أردت شيئًا جديدًا). وهكذا قررت في أحد PRs الخاصة بي على github استخدام البحث عن النص الكامل (المهمة التي تم التلميح إليها في هذا) لتصفية المحتوى ، مما جعلني أنتقل إلى وثائق Djangoبحثًا عن أفضل السبل لتنفيذ هذا العمل. أعتقد أنك تعرف معظم الأساليب المقترحة هناك (تحتوي على icontains و trigram_similar). جميعها مناسبة لبعض المهام المحددة ، ولكنها ليست جيدة جدًا في البحث عن نص كامل. بالتمرير قليلاً ، صادفت قسمًا تحدث عن تفاعل Django و Pgsql لتنفيذ البحث المستند إلى المستندات ، الأمر الذي جذبني ، نظرًا لأن postgre يحتوي على أداة مدمجة لتنفيذ هذا البحث [النص الكامل]. وقررت أنه على الأرجح ، يوفر django ببساطة واجهة برمجة تطبيقات لهذا البحث ، بناءً على ما يجب أن يعمل عليه هذا الحل وأكثر دقة وأسرع من أي خيارات أخرى. جادلنا المعلم ، لم يصدقني كثيرًا ، وعرض عليه إجراء بحث حول هذا الموضوع. وها أنا ذا.



بداية العمل



كانت المشكلة الأولى التي نشأت قبلي هي البحث عن نموذج لقاعدة البيانات ، حتى لا أتوصل إلى أي أشياء غير مفهومة بنفسي ، وذهبت إلى google وأقرأ postgres wiki . ونتيجة لذلك ، استقرت في قاعدتهم التجريبية حول الرحلات الجوية عبر روسيا.



حسنًا ، تم العثور على القاعدة. تحتاج الآن إلى تحديد طرق التصفية التي سيتم استخدامها للمقارنة. أول شيء أود استخدامه هو بالطبع طريقة البحث القياسية من django.contrib.postgres.search. يحتوي الثاني على (يبحث عن كلمة في سلسلة) ويحتوي على icontains (يوفر بيانات ، ويتجاهل اللهجات ، على سبيل المثال: بالنسبة لطلب البحث "Helen" ، ستكون النتيجة: <Author: Helen Mirren> ، <Author: Helena Bonham Carter> ، <Author: Hélène Joy>) الذي يوفره جانغو نفسه. أريد أيضًا مقارنة جميع طرق التصفية هذه بالبحث المدمج داخل postgresql. قررت البحث عن جدول التذاكر في النسخة الصغيرة التي تحتوي على 366733 إدخالاً. سيتم إجراء البحث في حقل اسم_الراكب ، والذي ، كما قد تتوقع ، يحتوي على اسم الراكب. هو مكتوب في الترجمة الصوتية.



دع django يعمل مع قاعدة بيانات موجودة



— django . django , , :



$ python manage.py inspectdb > models.py


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





, , , curl, , . , ( ).



django



, — , queryset - . .



:



إن QuerySet قابل للتكرار ، ويقوم بتنفيذ استعلام قاعدة البيانات الخاص به في المرة الأولى التي تقوم فيها بالتكرار فوقه. على سبيل المثال ، سيؤدي هذا إلى طباعة العنوان الرئيسي لجميع الإدخالات في قاعدة البيانات:



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




العرض النهائي يحتوي على
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


يحتوي على



لنبدأ مع يحتوي على ، فهو يعمل في الأساس مثل WHERE LIKE.



استعلام في Django ORM / Query in sql for يحتوي على
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%


من أجل الحصول على النتيجة من curl ، قمت بتنفيذ الطلب على النحو التالي (محسوب بالثواني):



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


أضع كل شيء في جدول على الورقة المناسبة.



— , 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) , , , , .



بشكل عام ، استقر فهمي لبعض الأعمال الداخلية لجانغو بفضل هذا البحث. وأخيرًا ، أدرك الفرق بين البحث عن سلسلة فرعية والبحث عن النص الكامل. الفرق في تنفيذها من خلال Django ORM.




All Articles