多语言字典的数据结构?

时间:2011-08-15 07:49:25

标签: data-structures dictionary multilingual

单行摘要:建议主要代表印欧语系的多语言词典的最佳(查找速度/紧凑性)数据结构(列表在底部)。

假设您要构建一些数据结构来实现多语言字典,让我们说在互联网上排名前N(N~40)的欧洲语言,排名选择语言by number of webpages(粗略在这个问题的底部给出的语言列表)。 目的是存储每种语言的工作词汇(即英语等25,000个单词)。排除正确的名词。不确定我们是否存储复数,动词变形,前缀等,或者添加关于如何从名词单词或动词词干形成这些词语的特定语言规则。 您还可以选择我们如何编码和处理重音符号,双元音和特定语言的特殊字符,例如:也许在可能的情况下我们transliterate事(例如Romanize德语ß为'ss',然后添加一个规则来转换它。显然,如果你选择使用40-100个字符和一个trie,那么分支太多了,而且大多数都是空的。

任务定义:无论您使用何种数据结构,都必须执行以下两项操作:

  1. 查找中的主要​​操作是快速获得指示'是这是A,B和F语言中的有效单词,但不是C,D或E'。因此,如果N = 40语言,你的结构迅速返回40布尔人。
  2. 辅助操作是为每种语言返回该词(及其所有变体)的某些指针/对象(如果无效,则返回null)。该指针/对象可以是用户定义的,例如词性和词典定义/词库比喻/翻译成其他语言的列表/ ...它可以是语言特定的或与语言无关的,例如: pizza
  3. 的共享定义

    效率的主要指标是a)紧凑性(跨所有N种语言)和b)查找速度的权衡。插入时间并不重要。

    所以:

    1. 什么是可能的数据结构,它们如何排名 查找速度/紧凑度曲线?
    2. 您是否拥有所有N种语言的统一结构,或者分区,例如将日耳曼语融入一个子结构,斯拉夫语成 另一个等?或者只是N个独立的结构(这将允许你 霍夫曼编码)?
    3. 您对字符,重音符号和特定语言的特殊字符使用什么表示形式?
    4. 理想情况下,提供算法或代码的链接,尤其是Python或者其他C. -
    5. (我检查了SO并且有相关的问题,但没有这个确切的问题。当然不是在寻找一个SQL数据库。一篇2000论文可能有用:"Estimation of English and non-English Language Use on the WWW" - Grefenstette & Nioche。还有一个list of multi-language dictionaries) 资源:两个在线多语言词典Interglot (en/ge/nl/fr/sp/se)LookWayUp (en<->fr/ge/sp/nl/pt)


      要包括的语言:

      简单来说可能主要是Indo-European languages:英语,法语,西班牙语,德语,意大利语,瑞典语+阿尔巴尼亚语,捷克语,丹麦语,荷兰语,爱沙尼亚语,芬兰语,匈牙利语,冰岛语,拉脱维亚语,立陶宛语,挪威语,波兰语,葡萄牙语,罗马尼亚语,俄语,塞尔维亚克罗地亚语,斯洛伐克语,斯洛文尼亚语+布列塔尼语,加泰罗尼亚语,科西嘉语,世界语,盖尔语,威尔士语

      可能包括俄语,斯拉夫语,土耳其语,排除阿拉伯语,希伯来语,伊朗语,印度语等。也许包括马来语家庭。告诉我什么是可以实现的。

5 个答案:

答案 0 :(得分:4)

我不确定这是否适用于您的特定问题,但这是一个想法的想法。

通常用于快速,紧凑的语言表示的数据结构是该语言的最小状态DFA。你可以通过为语言创建一个trie来构造它(它本身就是一个用于识别语言中的字符串的自动机),然后使用规范算法来构造语言的最小状态DFA。这可能需要大量的预处理时间,但是一旦你构建了自动机,你就可以非常快速地查找单词。您只需从开始状态开始,然后按照每个字母的标记过渡进行操作。无论状态是否与该语言中的单词相对应,每个州都可以编码(可能)每种语言的40位值编码。

由于不同的语言使用不同的字母表,因此最好按字母表分隔每种语言,以便最大限度地减少自动机的转换表的大小。毕竟,如果你有使用拉丁字母和西里尔字母的单词,表示希腊字的状态的状态转换可能都是拉丁字母的死状态,而拉丁字母的希腊字符的转换也将是死状态。因此,为每个字母表设置多个自动机可以消除大量浪费的空间。

答案 1 :(得分:3)

我不会在这里赢得积分,但有些事情。

多语言词典是一项庞大而耗时的工作。你没有详细谈论你的词典的确切用途:统计可能,不是翻译,不是语法,......不同的用法需要收集不同的数据,例如将“go”分类为传递时态。 / p>

首先在文档中制定您的第一个要求,并使用编程的接口原型。在算法概念之前询问数据结构我经常看到复杂的业务逻辑。然后一个人会开始出错,冒着feature creep的风险。或者是过早的优化,比如罗马化,这可能没有优势,也可能没有优势。

也许你可以从一些活跃的项目开始,比如Reta Vortaro;它的XML可能效率不高,但为组织提供了一些想法。有几个学术语言项目。最相关的方面可能是阻止:将 greet / greets / greeted / greeter / greeting / greetings (@ smci)识别为属于同一(主要)条目。你想要采用已编程的割线器;它们经常经过充分测试,已经应用于电子词典中。我的建议是研究这些项目,而不会给他们带来太大的能量和动力;足以收集想法并查看它们的用途。

可以想到的数据结构,是次要的恕我直言。我会首先收集一个定义良好的数据库,然后生成软件使用的数据结构。然后,您可以比较和衡量替代方案。它可能是开发人员最有趣的部分,创建一个美丽的数据结构和算法


答案

<强>要求:

单词地图到[语言,定义参考]列表。 定义清单。

几个单词可以具有相同的定义,因此需要定义参考。 定义可以包含语言约束定义(语法属性,倾斜度)和/或语言独立定义(概念描述)。

一个词可以有几个定义(书=(名词)阅读材料,=(动词)保留使用位置)。

<强>说明

当处理单个单词时,这并不认为发生的文本通常是单语言的。由于文本可以是混合语言,我认为O-复杂性没有特殊的开销,这似乎无关紧要。

因此,过于笼统的抽象数据结构将是:

Map<String /*Word*/, List<DefinitionEntry>> wordDefinitions;
Map<String /*Language/Locale/""*/, List<Definition>> definitions;

class Definition {
    String content;
}

class DefinitionEntry {
    String language;
    Ref<Definition> definition;
}

具体的数据结构:

wordDefinitions最适合使用优化的哈希映射。


请允许我添加:

我最后提出了一个具体的数据结构。我从以下开始。

Guava的MultiMap是我们在这里所拥有的,但如果在核心中使用紧凑的二进制表示,那么Trove的基本类型的集合就是人们所需要的。

人们可以这样做:

import gnu.trove.map.*;

/**
 * Map of word to DefinitionEntry.
 * Key: word.
 * Value: offset in byte array wordDefinitionEntries,
 * 0 serves as null, which implies a dummy byte (data version?)
 * in the byte arrary at [0].
 */
TObjectIntMap<String> wordDefinitions = TObjectIntHashMap<String>();
byte[] wordDefinitionEntries = new byte[...]; // Actually read from file.

void walkEntries(String word) {
    int value = wordDefinitions.get(word);
    if (value == 0)
        return;
    DataInputStream in = new DataInputStream(
        new ByteArrayInputStream(wordDefinitionEntries));
    in.skipBytes(value);
    int entriesCount = in.readShort();
    for (int entryno = 0; entryno < entriesCount; ++entryno) {
        int language = in.readByte();
        walkDefinition(in, language); // Index to readUTF8 or gzipped bytes.
    }
}

答案 2 :(得分:1)

NLP领域的常见解决方案是有限自动机。见http://www.stanford.edu/~laurik/fsmbook/home.html

答案 3 :(得分:0)

易。

为您的数据构建minimal, perfect hash function(所有词典的联合,离线构建哈希),并在剩下的时间内构建enjoy O(1) lookup

利用您的密钥静态知道的事实。不关心你的口音等等(如果你愿意,可以在散列之前将它们标准化)。

答案 4 :(得分:0)

我有一个类似的(但不完全是)任务:对集合实现四向映射,例如ABCD

每个项目x在所有集合x.Ax.Bx.Cx.D中都有投影;

任务是:对于遇到的每个项目,确定它属于哪个集合并在其他集合中找到其投影。

使用语言比喻:对于任何单词,请确定其语言并找到所有翻译成其他语言的语言。

但是:在我的情况下,一个单词只能唯一地识别为一种语言,因此英语中的驴子不是西班牙语中的burro等假朋友,而英语中的burro是黄油(另请参见https://www.daytranslations.com/blog/different-meanings/

我实现了以下解决方案:

  • 匹配条目与其唯一ID(整数)匹配的四个地图/词典
    AtoI[x.A] = BtoI[x.B] = CtoI[x.C] = DtoI[x.D] = i
    
  • 匹配唯一ID与相应语言的四个地图/词典

    ItoA[i] = x.A;
    ItoB[i] = x.B;
    ItoC[i] = x.C;
    ItoD[i] = x.D;
    

对于每次遇到x,我需要在最坏的情况下进行4次搜索以获取其ID(每次搜索为O(log(N)));然后进行3次访问操作,每个O(log(N))。总而言之,O(log(N))

我还没有实现这一点,但是我不明白为什么不能将哈希集用于任一O(1)词典。

回到您的问题: 给定M种语言中的N个概念(总共N * M个词)

我的方法采用以下方式适应

M个查找哈希集,可为您提供每种语言的整数ID(如果该语言中不存在该单词,则为None / null)。 对于不同语言的查找将产生不同的id,从而覆盖了这种情况。

对于每个单词,您在与语言对应的哈希集中进行M * O(1)查找,产生K <= M id,将单词识别为属于K种语言;

对于每个ID,您都需要在实际词典中进行(M-1)* O(1)个查询,将K个ID分别映射到M-1个翻译)

总的来说,我认为O(M K M)不错,因为您的M = 40,而K在大多数情况下会比M小得多(K = 1相当多)的单词)。

对于存储:id到word字典的N M个单词+ N M个整数,反向搜索(word到id)的数量相同;