【问题标题】:use fuzzy matching in django queryset filter在 django 查询集过滤器中使用模糊匹配
【发布时间】:2012-03-12 04:46:52
【问题描述】:

有没有办法在 django 查询集过滤器中使用模糊匹配?

我正在寻找类似的东西:

Object.objects.filter(fuzzymatch(namevariable)__gt=.9)

或者有没有办法在 django 查询中使用 lambda 函数或类似的东西,如果有,它会影响性能时间多少(假设我的数据库中有一组稳定的 ~6000 个对象,我想要匹配)

(意识到我可能应该把我的 cmets 放在问题中)

我需要比包含更强大的东西,类似于 difflib 的东西。我基本上是在尝试做一个Object.objects.all(),然后是一个带有模糊匹配的列表理解。

(虽然我不一定确定这样做会比尝试基于函数进行过滤要慢得多,所以如果您对此有想法,我很乐意倾听)

此外,即使这不是我想要的,我也愿意接受某种标记化的相反包含,例如:

Object.objects.filter(['Virginia', 'Tech']__in=Object.name)

将返回“Virginia Technical Institute”之类的内容。虽然不区分大小写,但最好。

【问题讨论】:

    标签: django django-models django-queryset


    【解决方案1】:

    当您使用 ORM 时,需要了解的是,您所做的一切都会转换为 SQL 命令,而重要的是底层数据库上的底层查询的性能。举个例子:

    SELECT COUNT (*) ...
    

    这么快吗?取决于您的数据库是否存储任何记录以向您提供该信息 - MySQL/MyISAM doesMySQL/InnoDB does not。英文 - 这是在 MYISAM 中的一个查找,在 InnoDB 中是 n。

    接下来 - 为了在 SQL 中有效地进行精确匹配查找,您必须在创建表时告诉它 - 您不能期望它能够理解。为此,SQL 有 INDEX 语句 - 在 django 中,在模型的字段选项中使用 db_index=True。请记住,这对写入(创建索引)有额外的性能影响,并且显然需要额外的存储空间(用于数据结构),因此您不能“INDEX all the things”。另外,我认为这对模糊匹配没有帮助 - 但无论如何都值得注意。

    下一个考虑——我们如何在 SQL 中进行模糊匹配?显然LIKECONTAINS 允许在SQL 中执行一定数量的搜索和通配符结果。这些是 T-SQL 链接 - 为您的数据库服务器翻译 :) 您可以通过 Model.objects.get(fieldname__contains=value) 实现此目的,这将产生 LIKE SQL 或类似的。那里有许多选项可用于不同的查找。

    这可能对你来说足够强大,也可能不够强大——我不确定。

    现在,对于一个大问题:性能。如果您正在执行包含搜索,那么 SQL 服务器可能必须访问数据库中的所有行 - 不要相信我的话,但这是我的赌注 - 即使启用了索引。对于 6000 行,这可能不会花费那么长时间;再说一次,如果您在每个连接到您的应用程序的基础上执行此操作,它可能会导致速度变慢。

    接下来要了解 ORM:如果你这样做:

    Model.objects.get(fieldname__contains=value)
    Model.objects.get(fieldname__contains=value)
    

    您将向数据库服务器发出两个查询。换句话说,ORM 并不总是缓存结果——所以你可能只想做一个.all() 并在内存中搜索。请阅读caching and querysets

    在最后一页上,您还会看到 Q 对象 - 对于更复杂的查询很有用。

    那么总结一下:

    • SQL 包含一些基本的类似模糊匹配的参数。
    • 这些是否足够取决于您的需求。
    • 它们的表现取决于您的 SQL 服务器 - 一定要衡量它
    • 您是否可以将这些结果缓存到内存中取决于扩展的可能性 - 再次测量内存提交结果可能是值得的 - 如果您可以在实例之间共享以及缓存是否会经常失效(如果会,不要这样做)。

    最终,我会先让您的模糊匹配正常工作,然后测量、调整、再测量,直到您弄清楚如何提高性能。其中 99% 都是我学到的 :)

    【讨论】:

    • 我需要比包含更强大的东西,类似于 difflib 的东西。我基本上是在尝试解决 Object.objects.all() 和模糊匹配的列表理解。
    • (虽然我不确定这样做会比尝试基于函数进行过滤要慢得多,所以如果您对此有想法,我很乐意倾听)
    • 另外,即使这不是我想要的,我也会对某种标记化的相反包含持开放态度,例如 Object.objects.filter(['Virginia', 'Tech']__in =Object.name),其中将返回“Virginia Technical Institute”之类的内容。虽然不区分大小写,但最好。
    • @Colleen:你的例子在功能上等同于Object.objects.filter(Q(name__icontains='virginia') | Q(name__icontains='tech'))
    • @Colleen 看看@Chris 怎么说。你也许可以在那里获得一部分。此外,根据您的 SQL 服务器,可能存在扩展以支持执行此类操作 - 但不会有 django 包装器来执行此操作。不过,在这样做之前,我肯定会衡量一个可行的解决方案!`
    【解决方案2】:

    使用 postgres 作为数据库,您可以使用 TrigramSimilarity 进行模糊搜索,并根据不同的权重对结果进行排名。这是文档的链接:

    https://docs.djangoproject.com/en/2.0/ref/contrib/postgres/search/#trigram-similarity

    全文搜索可以参考https://czep.net/17/full-text-search.html

    【讨论】:

      【解决方案3】:

      如果您需要比包含查找更强大的内容,请查看正则表达式查找:https://docs.djangoproject.com/en/1.0/ref/models/querysets/#regex

      【讨论】:

      猜你喜欢
      • 2018-10-20
      • 2023-04-11
      • 1970-01-01
      • 2018-09-02
      • 1970-01-01
      • 1970-01-01
      • 2019-07-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多