问题 在django queryset过滤器中使用模糊匹配


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

我正在寻找Object.objects.filter(fuzzymatch(namevariable)__ gt = .9)的内容。

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

(意识到我应该把我的评论放在问题中)

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

(虽然我不一定确定这样做比尝试根据函数进行过滤要慢得多,所以如果你对此有所了解我很乐意听)

另外,即使它不是我想要的,我也会接受某种标记化的反向包含,比如Object.objects.filter(['Virginia','Tech'] __ in = Object.name),像“弗吉尼亚技术学院”将被退回。虽然不区分大小写,但最好是。


9577
2018-02-21 20:49


起源



答案:


当您使用ORM时,要理解的是您所做的一切都转换为SQL命令,而这是底层数据库上基础查询的性能。例证:

SELECT COUNT (*) ...

那快吗?取决于您的数据库是否存储任何记录以提供该信息 - MySQL / MyISAM可以MySQL / InnoDB没有。在英语中 - 这是在MYISAM中的一个查找,在InnoDB中是n。

接下来的事情 - 为了在SQL中有效地进行精确匹配查找,您必须在创建表时告诉它 - 您不能仅仅期望它能够理解。为此,SQL有 INDEX 声明 - 在django,使用 db_index=True 在模型的字段选项中。请记住,这会增加写入性能(创建索引),显然需要额外的存储空间(对于数据结构),所以你不能“INDEX 所有的事情“。而且,我认为它不会有助于模糊匹配 - 但无论如何它值得注意。

下一个考虑因素 - 我们如何在SQL中进行模糊匹配?显然很好 LIKE 和 CONTAINS 允许在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() 并在内存中搜索。请阅读 缓存和查询集

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

那么总结一下:

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

最后,我首先让你的模糊匹配工作,然后测量,然后调整,然后测量,直到你找出如何提高性能。其中99%我学会了这样做:)


10
2018-02-21 21:25



我需要比包含更强大的东西,类似于difflib的东西。我基本上试图绕过做一个Object.objects.all(),然后是一个模糊匹配的列表理解。 - Colleen
(虽然我不一定确定这样做比尝试根据函数进行过滤要慢得多,所以如果你对此有所了解我很乐意听) - Colleen
另外,即使它不是我想要的,我也会接受某种标记化的反向包含,比如Object.objects.filter(['Virginia','Tech'] __ in = Object.name),像“弗吉尼亚技术学院”将被退回。虽然不区分大小写,但最好是。 - Colleen
@Colleen:你的例子在功能上等同于 Object.objects.filter(Q(name__icontains='virginia') | Q(name__icontains='tech')) - Chris Pratt
+1非常彻底和深思熟虑的答案。 - Chris Pratt


答案:


当您使用ORM时,要理解的是您所做的一切都转换为SQL命令,而这是底层数据库上基础查询的性能。例证:

SELECT COUNT (*) ...

那快吗?取决于您的数据库是否存储任何记录以提供该信息 - MySQL / MyISAM可以MySQL / InnoDB没有。在英语中 - 这是在MYISAM中的一个查找,在InnoDB中是n。

接下来的事情 - 为了在SQL中有效地进行精确匹配查找,您必须在创建表时告诉它 - 您不能仅仅期望它能够理解。为此,SQL有 INDEX 声明 - 在django,使用 db_index=True 在模型的字段选项中。请记住,这会增加写入性能(创建索引),显然需要额外的存储空间(对于数据结构),所以你不能“INDEX 所有的事情“。而且,我认为它不会有助于模糊匹配 - 但无论如何它值得注意。

下一个考虑因素 - 我们如何在SQL中进行模糊匹配?显然很好 LIKE 和 CONTAINS 允许在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() 并在内存中搜索。请阅读 缓存和查询集

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

那么总结一下:

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

最后,我首先让你的模糊匹配工作,然后测量,然后调整,然后测量,直到你找出如何提高性能。其中99%我学会了这样做:)


10
2018-02-21 21:25



我需要比包含更强大的东西,类似于difflib的东西。我基本上试图绕过做一个Object.objects.all(),然后是一个模糊匹配的列表理解。 - Colleen
(虽然我不一定确定这样做比尝试根据函数进行过滤要慢得多,所以如果你对此有所了解我很乐意听) - Colleen
另外,即使它不是我想要的,我也会接受某种标记化的反向包含,比如Object.objects.filter(['Virginia','Tech'] __ in = Object.name),像“弗吉尼亚技术学院”将被退回。虽然不区分大小写,但最好是。 - Colleen
@Colleen:你的例子在功能上等同于 Object.objects.filter(Q(name__icontains='virginia') | Q(name__icontains='tech')) - Chris Pratt
+1非常彻底和深思熟虑的答案。 - Chris Pratt


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


2
2018-02-22 15:55



该链接断开1.0。最新的文档在这里: docs.djangoproject.com/en/dev/ref/models/querysets/#regex - dokkaebi


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

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

有关全文搜索,请参阅 https://czep.net/17/full-text-search.html 


1
2018-04-12 14:11