PostgreSQL数据库演示示例中不同django过滤器的比较

代替序言



一切始于这样一个事实:我被安排在“ Web编程基础”主题的框架内参加该项目,而不是从事实验室工作和课程工作,因为我说过我想做一些远离一般课程的事情(因此,已经有足够的知识了)在一堆DRF + Vue上,我想要一些新东西)。因此,在github上的我的PR中,我决定使用全文搜索(在此提示的分配)来过滤内容,这使我转向Django文档寻找如何最好地实施这项业务。我认为您知道那里建议的大多数方法(包含,图标包含,trigram_like)。它们全都适合某些特定任务,但不是很擅长,即全文搜索。向下滚动一下,我遇到了一个部分,该部分讨论了Django和Pgsql的交互以实现基于文档的搜索,这吸引了我,因为postgre具有用于实现此[全文搜索]的内置工具。而且我认为django最有可能只是为这种搜索提供一个API,这是基于这种解决方案应该能起作用的原理,并且比任何其他选项都更准确,更快。老师不相信我太多,我们与他争论,他提议对此主题进行研究。我在这里。



开始工作



摆在我面前的第一个问题是搜索数据库模型,以免自己搞不清楚任何事情,于是我去google并阅读了postgres wiki。结果,我在他们的演示基地上确定了有关俄罗斯各地航班的信息。



好的,已经找到了基地。现在,您需要确定将使用哪些过滤方法进行比较。我首先要使用的是django.contrib.postgres.search中的标准搜索方法。第二个是包含(搜索字符串中的单词)和图标集(提供数据,忽略重音,例如:对于查询“ Helen”,结果将是:<作者:Helen Mirren>,<作者:Helena Bonham Carter>,<作者:HélèneJoy>) django本身提供的。我还想将所有这些过滤方法与postgresql中的内置搜索进行比较。我决定在小版本中搜索票证表,其中包含366733个条目。搜索将在passenger_name字段上执行,您可能会猜测其中包含乘客的姓名。它是用音译写的。



让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中查询/在SQL中查询包含
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的一些内部工作方式的理解已经稳定下来。最终实现了子字符串搜索和全文搜索之间的区别。通过Django ORM在实现上的差异。




All Articles