为什么QuerySet迭代这么慢?

问题描述 投票:-1回答:1

我正在尝试为系统创建准确有效的搜索算法。我安装了Postgresql来利用它的trigram相似性查询,这就是我搜索对象的方式:

objects_found = Question.objects.extra(where=["CHAR_LENGTH(answer) > 300"])).filter(question__trigram_similar=message

这非常快,执行大多数查询花了不到0.5秒。 objects_found查询集的所有对象与查询文本类似,但我需要找出最相似的对象。

我知道在这种情况下两种算法非常好,第一种是Cosine Similarity,第二种是Ratcliff/Obershelp pattern recognitionwhich has built-in implementation in Python)。

我尝试进行迭代,测试每个迭代,Cosine Similarity在大多数情况下快了大约1.5倍(正如预期的那样,考虑到矢量的测量速度要快得多),但是SequenceMatcher会给出更准确的结果。因此我仍然选择了SequenceMatcher。请注意,此迭代需要很长时间。

最后,我尝试在代码中实现SequenceMatcher:

objects_found = (Question.objects.extra(where=["CHAR_LENGTH(answer) > 300"])).filter(question__trigram_similar=message).iterator()
zsim = ("", 0)
for i in objects_found:
    rsim = _search.ratcliff_obershelp(querytext, i.question)
    if zsim[1] < rsim:
       zsim = (i.answer, rsim)
       if rsim > 0.75:  # works in most of the cases
            break
response = zsim[0]

在数据库中有大约1GB的~500万行,并且需要postgresql小于0.5s才能选择具有trigram相似性的正确行。在大约500万行中,只有10-90被过滤,并且在62s左右进行查询集迭代以找到最相似的行。

即使迭代在开始时中断也是如此,例如,如果只有4行要迭代以达到75%以上的相似性,Django仍然会加载90行。

我真的怀疑相似性算法本身就是问题,它似乎只是需要花费很长时间来加载行的查询集,一旦它们被加载,算法几乎可以立即完成所有操作。

为什么会这样?有没有办法让Queryset迭代更有效率?数据库级迭代会产生更快的结果吗?

p.s时间由python的时间模块测量。

python django postgresql django-queryset
1个回答
2
投票

您所面临的困惑是由于Django对QuerySets的推迟评估造成的。您正在等待Django的0.5秒实际上只是准备SQL - 也就是说,将ORM调用转换为SQL查询(或几个SQL查询),以后可以执行。

QuerySets被评估as late as possible然后缓存,所以要知道它实际通过Django需要多长时间,你需要强制评估QuerySet,让Django执行SQL。您可以通过以下几种方式执行此操作:

print(objects_found)

要么

list(objects_found)

要么

for item in objects_found:
    pass
© www.soinside.com 2019 - 2024. All rights reserved.