SQL /(Django):用于翻译的高效数据库模式

时间:2014-12-26 23:28:44

标签: sql django database database-schema

场合

我尝试设置数据库架构来存储不同语言之间的翻译。到目前为止它看起来像这样(简单):

class Language(models.Model):
    tag = models.CharField(max_length=2)

    def __unicode__(self):
        return self.tag

class Phrase(models.Model):
    name = models.TextField()
    language = models.ForeignKey(Language)

    def __unicode__(self):
        return self.name

    class Meta:
        unique_together = ("name", "language")
        index_together = [
            ["name", "language"]
        ]

class Translation(models.Model):
    phrase1 = models.ForeignKey(Phrase, related_name="translation_as_1")
    phrase2 = models.ForeignKey(Phrase, related_name="translation_as_2")

    def __unicode__(self):
        return self.phrase1.name + " <=> " + self.phrase2.name

    class Meta:
        unique_together = ("phrase1", "phrase2")
        index_together = [
            ["phrase1", "phrase2"]
        ]

这个数据库架构对我来说似乎合情合理。我用不同的语言存储短语,然后翻译包含两个短语。

问题

问题是,由此架构产生的查询看起来很讨厌。例如:

from django.db.models import Q

name = "my phrase"
translations = Translation.objects.filter(Q(phrase1__name=text)|Q(phrase2__name=text))
translated_names = []
for translation in translations:
    name1 = translation.phrase1.name
    name2 = translation.phrase2.name
    if name1 == name:
        translated_names.append(name2)
    else:
        translated_names.append(name1)

我总是要包含“OR”关系,以确保我获得所有可能的翻译,因为短语可以存储为phrase1或phrase2。最重要的是,我必须在之后过滤我的结果以获得正确的translated_name(for循环)。

进一步说明

在我切换到所描述的架构之前,我改为使用以下架构(PhraseLanguage与之前相同):

class Translation(models.Model):
    phrase = models.ForeignKey(Phrase)
    name = models.TextField()

    def __unicode__(self):
        return self.phrase.name + " => " + self.name

    class Meta:
        unique_together = ("phrase", "name")
        index_together = [
            ["phrase", "name"]

这个架构让我可以这样进行查询:

from django.db.models import Q

name = "my phrase"
translations = Translation.objects.filter(phrase__name=text)
translated_names = [t.name for t in translations]

这看起来更好,当然更快。但是这个模式有缺点,它只在一个方向上呈现翻译,所以我转移到另一个,这也不是我想要的,因为查询太慢而且太复杂。

问题

对于这类问题,我是否有一个很好的架构,我可能会忽略它?

备注

我不仅对Django相关答案感兴趣。这种问题的纯SQL模式对我来说也很有趣。

1 个答案:

答案 0 :(得分:0)

这是我过去做过的方式。根据您的命名惯例进行调整。

假设我有一个名称和其他列的表,就像这样

TR_CLT_clothing_type

clt_id | clt_name | other columns ....
--------------------------------------
1      | T Shirt ...
2      | Pants ...

现在如果我决定需要翻译,首先我要制作语言表

TR_LNG_language

lng_id | lng_name | lng_display
-------------------------------
1      | English  | English (NZ)
2      | German   | Deutsch

我还需要将当前语言存储在数据库中(您很快就会看到原因)。它只有一行

TA_INF_info

inf_current_lng
---------------
1

然后从服装表 TR_CLT_clothing_type 中删除 clt_name 列。而是我制作关系表。

TL_CLT_clothing_type

clt_id | lng_id | clt_name
--------------------------
1      | 1      | T Shirt
1      | 2      | (German for T-Shirt)
2      | 1      | Pants
2      | 2      | keuchen (thank you google translate)

现在要获取名称,您需要为其创建存储过程。我没有在ORM中尝试过这个。

CREATE PROCEDURE PS_CLT
    @clt_id int
AS

SELECT lng.clt_name, clt.*
FROM TR_CLT_clothing_type clt
JOIN TL_CLT_clothing_type lng
ON lng.clt_id = clt.clt_id
WHERE clt.clt_id = @clt_id AND
      lng.lng_id in (SELECT inf_current_lng FROM TA_INF_info)

此存储过程将返回当前语言的名称和指定语言的所有其他列。要设置语言,请在 TA_INF_info 表中设置 clt_current_lng

免责声明:我没有任何东西可以检查我输入的内容的语法,但它应该是直截了当的。

- 编辑

有人担心能够做到&#34;给我语言Y中的单词X翻译成语言Z&#34;

有一个&#34;不那么优雅&#34;使用模式执行此操作的方法。你可以做点什么

for each table in database like "TL_%"

    SELECT name
    FROM table
    WHERE id IN (   SELECT id
            FROM table
            WHERE name = @name
            AND   lng_id = german
            )
    AND lng_id = english

现在我想这会需要一些自动生成的SQL代码,但我可以将其删除。

我不知道你将如何在ORM中做到这一点