Alih-alih kata pengantar
Semuanya dimulai dengan fakta bahwa saya ditawari untuk berpartisipasi dalam proyek dalam kerangka subjek "Dasar-dasar Pemrograman Web", alih-alih melakukan pekerjaan laboratorium dan kursus, karena saya menyatakan bahwa saya ingin melakukan sesuatu yang jauh dari kursus umum (sehingga sudah ada cukup pengetahuan pada sekelompok DRF + Vue, saya ingin sesuatu yang baru). Jadi di salah satu PR saya di github, saya memutuskan untuk menggunakan pencarian teks lengkap (tugas ini mengisyaratkan) untuk memfilter konten, yang membuat saya beralih ke dokumentasi Djangomencari cara terbaik untuk mengimplementasikan bisnis ini. Saya pikir Anda tahu sebagian besar metode yang disarankan di sana (berisi, icontains, trigram_similar). Semuanya cocok untuk beberapa tugas tertentu, tetapi tidak terlalu bagus, yaitu pencarian teks lengkap. Menggulir ke bawah sedikit, saya menemukan bagian yang berbicara tentang interaksi Django dan Pgsql untuk mengimplementasikan pencarian berbasis dokumen, yang menarik saya, karena postgre memiliki alat bawaan untuk mengimplementasikan pencarian [teks lengkap] ini. Dan saya memutuskan bahwa kemungkinan besar, Django hanya menyediakan API untuk pencarian ini, atas dasar mana solusi seperti itu harus bekerja dan lebih akurat dan lebih cepat daripada opsi lain. Guru itu tidak terlalu mempercayaiku, kami berdebat dengannya, dan ia menawarkan untuk melakukan penelitian tentang topik ini. Dan inilah saya.
Awal pekerjaan
Masalah pertama yang muncul sebelum saya adalah mencari mockup basis data, agar tidak muncul sendiri hal-hal yang tidak dapat dipahami, dan saya pergi ke google dan membaca postgres wiki . Akibatnya, saya menetap di pangkalan demo mereka tentang penerbangan di seluruh Rusia.
, . , . , , , 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 - . .
QuerySet dapat diubah, dan menjalankan kueri basis datanya saat pertama kali Anda mengulanginya. Misalnya, ini akan mencetak judul semua entri dalam database:
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
Mengandung
Mari kita mulai dengan berisi, pada dasarnya berfungsi seperti SEPERTI WHERE.
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%
Untuk mendapatkan hasil dari curl, saya menjalankan permintaan sebagai berikut (dihitung dalam detik):
$ curl -w "%{time_total}\n" -o /dev/null -s http://127.0.0.1:8000/api/tickets/?name=IVAN
1,242888
Saya meletakkan semuanya di atas meja di lembar yang sesuai.
β , 140 1400 . , . ORM 73 600 , 55 100 .
Icontains
Icontains - ( , ). , contains β 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) , , , , .
Secara keseluruhan, pemahaman saya tentang beberapa pekerjaan batin Django telah pulih berkat penelitian ini. Dan akhirnya muncul realisasi perbedaan antara pencarian substring dan pencarian teks lengkap. Perbedaan implementasi mereka melalui Django ORM.