gpt4 book ai didi

python - 来自 ManyToManyField 的 Django 最大相似度(TrigramSimilarity)

转载 作者:太空狗 更新时间:2023-10-29 21:45:08 25 4
gpt4 key购买 nike

我必须实现一个容错的搜索功能。
目前,我有以下情况:

模型:

class Tag(models.Model):
name = models.CharField(max_length=255)

class Illustration(models.Model):
name = models.CharField(max_length=255)
tags = models.ManyToManyField(Tag)

查询:

queryset.annotate(similarity=TrigramSimilarity('name', fulltext) + TrigramSimilarity('tags__name', fulltext))

示例数据:

插图:

ID |  Name  |        Tags       |
---|--------|-------------------|
1 | "Dog" | "Animal", "Brown" |
2 | "Cat" | "Animals" |

插图有标签:

ID_Illustration | ID_Tag |
----------------|--------|
1 | 1 |
1 | 2 |
2 | 3 |

标签:

ID_Tag |   Name   |
-------|----------|
1 | Animal |
2 | Brown |
3 | Animals |

当我使用"Animal" 运行查询时,"Dog" 的相似度应该高于"Cat",因为这是一个完美的匹配。
不幸的是,这两个标签以某种方式被考虑在一起。
目前,它看起来像是将标签连接成一个字符串,然后检查相似性:

TrigramSimilarity("Animal Brown", "Animal") => X

但我想以一种在Illustration 实例名称及其标签之间获得最高相似度的方式对其进行调整:

Max([
TrigramSimilarity('Name', "Animal"),
TrigramSimilarity("Tag_1", "Animal"),
TrigramSimilarity("Tag_2", "Animal"),
]) => X

Edit1:我正在尝试查询所有插图,其中标题或其中一个标签的相似度大于 X。

Edit2:附加示例:

fulltext = 'Animal'

TrigramSimilarity('Animal Brown', fulltext) => x TrigramSimilarity('Animals', fulltext) => y

Where x < y

But what I want is actually

TrigramSimilarity(Max(['Animal', 'Brown]), fulltext) => x (Similarity to Animal) TrigramSimilarity('Animals', fulltext) => y

Where x > y

最佳答案

你不能分解 tags__name (至少我不知道办法)。
根据您的示例,我可以假设 2 种可能的解决方案(第一种解决方案并非严格使用 Django):


  1. 不是所有的东西都需要严格通过Django
    我们拥有 Python 的强大功能,所以让我们使用它们吧:

    让我们先编写查询:

    from difflib import SequenceMatcher

    from django.db.models import Q

    def create_query(fulltext):
    illustration_names = Illustration.objects.values_list('name', flat=True)
    tag_names = Tag.objects.values_list('name', flat=True)
    query = []

    for name in illustration_names:
    score = SequenceMatcher(None, name, fulltext).ratio()
    if score == 1:
    # Perfect Match for name
    return [Q(name=name)]

    if score >= THRESHOLD:
    query.append(Q(name=name))

    for name in tag_names:
    score = SequenceMatcher(None, name, fulltext).ratio()
    if score == 1:
    # Perfect Match for name
    return [Q(tags__name=name)]

    if score >= THRESHOLD:
    query.append(Q(tags__name=name))

    return query

    然后创建您的查询集:

    from functools import reduce # Needed only in python 3
    from operator import or_

    queryset = Illustration.objects.filter(reduce(or_, create_query(fulltext)))

    解码以上内容:

    我们正在检查每个 IllustrationTag反对我们的名字fulltext我们正在用相似度通过 THRESHOLD 的每个名称编写一个查询.

    • SequenceMatcher 方法比较序列并返回比率 0 < ratio < 1其中 0 表示不匹配,1 表示完美匹配。检查此答案以获取另一个用法示例:Find the similarity percent between two strings (注意:还有其他字符串比较模块,找一个适合你的)
    • Q() Django 对象,允许创建复杂的查询(有关链接文档的更多信息)。
    • operator reduce 我们转换 Q() 的列表OR 分隔查询参数的对象:
      Q(name=name_1) | Q(name=name_2) | ... | Q(tag_name=tag_name_1) | ...

    注意:您需要定义一个可接受的 THRESHOLD .
    正如您可以想象的那样,这会有点慢,但是当您需要进行“模糊”搜索时,这是可以预料的。


  1. (Django 之道:)
    使用具有高相似度阈值的查询并按此相似率对查询集进行排序:

    queryset.annotate(
    similarity=Greatest(
    TrigramSimilarity('name', fulltext),
    TrigramSimilarity('tags__name', fulltext)
    )).filter(similarity__gte=threshold).order_by('-similarity')

    解码以上内容:

    • Greatest() 接受表达式或模型字段的聚合(不要与 Django 方法 aggregate 混淆)并返回最大项。
    • TrigramSimilarity(word, search)返回 0 到 1 之间的比率。比率越接近 1,word 越相似是search .
    • .filter(similarity__gte=threshold) , 将过滤低于 threshold 的相似度.
    • 0 < threshold < 1 .您可以将阈值设置为 0.6这是相当高的(考虑默认值是 0.3 )。 您可以利用它来调整您的表现。
    • 最后,按 similarity 对查询集进行排序降序排列。

关于python - 来自 ManyToManyField 的 Django 最大相似度(TrigramSimilarity),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48603190/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com