0

这是我的模型:

class Item(models.Model):
    status = models.IntegerField(choices=STATUS_CHOICES, default=3)
    def __str__(self):
        return 'Item: {0}'.format(self.id)


class Name(models.Model):
    name = models.CharField(, max_length=600, default='')
    item = models.ForeignKey(Item, db_index=True, blank=True, null=True)
    main = models.BooleanField(default=False)

    def __str__(self):
        return '{}'.format(self.name)

我想查询集合项目,所以它返回按模糊模糊排序的 X 个项目。 基本上,我需要找到匹配的项目并将它们合并。

我试图创建一个字典,但它非常慢。我有大约 80 000 件物品,而且还在增加。

我尝试过类似的事情:

items = Item.objects.filter(status=3)
                 .annotate( score=fuzz.ratio(query,i.name_set.all().first().name))
                 .order_by('-score')

谁能给我一些关于这个话题的信息?谢谢

4

2 回答 2

3

如果数据库中有 80.000 个条目,则必须考虑以下选项:

(A) 让数据库排序(最好使用一些预先创建的索引)并只返回选择的行。这允许通过数据库进行分页。

(B) 尽快从数据库中返回所有内容,并对 RAM 中的所有 80.000 进行排序。如果你想坚持使用 python 模块 FuzzyWuzzy,你必须这样做。但正如您现在所经历的那样,这可能不会很快。您必须自己进行分页。

[FuzzyWuzzy] 使用 Levenshtein Distance 计算序列之间的差异,在一个简单易用的包中。

如果您使用 PostgreSQL 作为后端,则可以使用 levenshtein 函数,如下所述:

https://www.postgresql.org/docs/9.1/static/fuzzystrmatch.html

似乎有对 Django 的贡献来整合这个: https ://github.com/django/django/pull/4825

TrigramSimilarity已经可用。您可以查看源代码并基于 postgres levenshtein 实现类似的东西。但我建议先尝试一下。它可能已经满足您的需求。

编辑:

一般来说,对于这种大小或更大的表,请确保您的数据库在需要的地方有索引并使用它们。例如:Django 的__icontains过滤器没有被 Django 的db_index. 您必须自己在该列上添加一个三元组索引。

您当前的代码可能需要这么长时间,因为查询已经花费了不必要的时间。

于 2017-07-05T14:29:23.163 回答
1

如果您使用的是PostgreSQL,您可以使用Trigram Similar

trigram_similar查找允许您使用专用的PostgreSQL扩展来执行三元组查找,测量共享的三元组(三个连续字符)的数量。

安装:

更新你的settings.py::

INSTALLED_APPS = [
    ...
    'django.contrib.postgres',
]

添加一个新的迁移::

python manage.py makemigrations --empty yourappname

将创建一个新的迁移文件,例如:migrations/0002_auto_<date>_<time>.py. 更新它::

from django.db import migrations
from django.contrib.postgres.operations import TrigramExtension
class Migration(migrations.Migration):        

    dependencies = [
        ...
    ]
    operations = [
        TrigramExtension(),
    ]

现在迁移:

./manage.py migrate

现在您可以使用trigram_similar查找CharFieldTextField例如:

>>> City.objects.filter(name__trigram_similar="Middlesborough")
['<City: Middlesbrough>']
于 2018-08-11T05:35:12.597 回答