此次算是网易的秋招补录了吧,也不知道从哪里把我挖出来,让我去面试。面试的岗位是数据挖掘,总共有四轮面试,全是技术面试,岗位虽然是数据挖掘,但是面试官问的问题绝大多数是偏自然语言处理的,
面试的内容不再一一阐述,下面就其中个人觉得比较有意思的问题作以下记录。
1.第一个问题是拼写纠正问题,面试官写了这样一句话:I hase an apple,显示hase拼写错误,并提出修改建议(have),这里实际上要解决两个问题:一.如何识别拼写错误,这个很简单。二针对拼写错误,如何快速给出修改建议。
这个问题我当时能想到的方法都说了,但是貌似答得不太好,下面是我整理的答案,答案来源于:http://blog.sina.com.cn/s/blog_567842410100obxd.html
现在各大流行的搜索引擎几乎都具备一个功能,那就是提供拼写纠错功能。用户将查询的关键词提交给搜索引擎之后,搜索引擎便开始分析用户的输入,检查用户的拼写是否有错误,如果有的话,给出正确的拼写建议。也就是说,搜索引擎的拼写纠错功能,要完成两部分的工作,首先,对用户输入的查询进行处理,判断是否有拼写错误,接着,对于有拼写错误的查询输入,给出正确词汇的提示。因为中文的拼写纠错涉及到中文分词等复杂逻辑,所以本文只对英文的拼写纠错进行讨论。
英文单词纠错法
常见的英文单词纠错法,主要有以下几种:误拼词典法、最小编辑距离法、词干法,N-gram法和基于规则的技术等,下面我们对这些英文单词纠错法逐个进行介绍。
(1)误拼字典法。这种方法可以理解成穷举法,通过收集大规模真实文本中拼写出错的英文单词并给出相应的正确拼写,建造一个无歧义的误拼字典。在进行英文单词拼写检查时,查找误拼字典,如命中,则说明该单词拼写有误,该词的正确拼写字段为纠错建议。比如在搜索引擎的实现中,通过记录日志的形式,把所有用户的输入都记录下来,提取有拼写错误的输入,形成误拼词典。该方法的特点是算法简单,效率高。但英文拼写错误具有随机性,很难保证误拼字典的无歧义性和全面性,因此查准率低、校对效果差;而且,对于搜索引擎用户海量的误拼输入,空间复杂度也是需要考虑的问题。
(2)最小编辑距离法。通过计算误拼字符串与词典中某个词间的最小编辑距离来确定纠错候选词。所谓最小编辑距离是指将一个词串转换为另一个词串所需的最少的编辑操作次数。在编辑操作中,可以将单次的编辑动作归纳为三种:插入字符、删除字符和替换字符;考虑到在实际计算机输入过程中,字符的颠倒异位也是常见的错误,我们将颠倒异位也算作一种编辑动作。还有人提出了反向最小编辑距离法,这种方法首先对每个可能的单个错误按照编辑距离进行搜索,生成一个候选集,然后,通过查词典看哪些是有效的单词,并将这些有效的单词作为误拼字符串的纠错建议。
(3)N-gram法。基于n元文法,通过对大规模英文文本的统计得到单词与单词问的转移概率矩阵。当检测到某英文单词不在词典中时。查转移概率矩阵,取转移概率大于某给定阈值的单词为纠错建议。
通过对这些现有的英文单词纠错法的分析,我们选定反向最小编辑距离法作为拼写纠错功能的实现方式
拼写纠错功能的实现
搜索引擎如何判断用户的输入是否有拼写错误呢?通过分析现有的著名搜索引擎的行为,我想应该是查词典的方式。每个搜索引擎维护一个关键词的词典,对于用户的输入,检查它是否在词典中。如果词典中有这个词条,则直接返回搜索结果;如果发现这个用户输入的词并不包含在词典里边,那么它很有可能是一个错误的输入,于是马上触发拼写纠错功能,对用户提供拼写建议。我们很容易就能在Google或者百度这样的搜索引擎中验证这个猜想,在搜索框里输入一个正常的词,比如“Microsoft”,搜索引擎不会有错误提示;而你故意输入一个词典不包括的词,比如“Micorsoft”,搜索引擎会提示你正确的搜索词汇。
字典的数据结构
字典的数据结构,大多数情况下,比照C++ STL中的map,我们会想到两种实现途径,首先是二叉树,其次是哈希表。对于哈希表,在选取恰当的哈希函数的情况下,它的理论查找效率是O(1),这看起来是个不错的选择,事实上哈希表已经用作在一些搜索引擎中[1]。于是我们可以在训练搜索引擎的过程中,把所有的常用词都输入到这个词典中,然后就能够用很高的效率进行搜索。但是这种方法带来一个问题,词典里的单词量通常是非常巨大的,每一个单词都需要完整的存储,随着时间的推移,这种实现需要的内存空间也会变得越来越大。
在二叉树的实现中,我们可以把所有的单词都保存在二叉树的节点中,但这样需要的空间几乎可以肯定不会比哈希表的方式少,除了存储单词的空间,还需要额外的实现二叉树的空间,况且搜索的时间复杂度是O(logn),所以我们需要对这种方式进行优化。所有的单词还是存储在二叉树结构中,但是每个节点仅保存一个字符,每个节点可以有两个子节点,其中左子节点表示当前字符的兄弟(Sibling), 说明有多个单词存在相同的前缀,右子节点表示当前字符的后续字符(Next),利用这种存储方法,我们可以高效率地将有相同前缀的词存储在同一棵子树中(貌似是前缀树)。
给出拼写建议
前面我们提到最小编辑距离法中,需要对用户输入的误拼字符串按照编辑距离进行搜索并形成候选集,然后在字典中查找后选的单词。如果存在,则说明是个有效的单词,可以作为拼写建议提供给用户。我们只考虑编辑距离为1的情况,如果编辑距离更大的话,返回的结果太多,反而影响拼写建议的准确度。
我们按照编辑操作来枚举生成候选集模式。比如对于误拼字符串abc,删除字符可以产生ab、ac和bc;插入字符可以产生?abc、a?bc、ab?c和abc?;替换字符可以产生?bc、a?c和ab?;将字符颠倒可以产生bac和acb。然后,我们将这些候选模式放到二叉树中去搜索,就可以返回匹配的候选单词集合。
候选单词集中包含有我们需要提供给用户的拼写建议,但是我们不能这样直接给用户。首先,候选单词集中可能存在重复的单词,其次存在多个单词的情况下,如何才能把最准确的拼写建议返回给用户。第一个问题,我们可以通过过滤逻辑去除重复;而第二个问题,我想不同的搜索引擎都有自己不同的实现,比如可以按照单词的优先级返回,分析用户查询日志,查询次数越多的单词优先级越高。
2.第二个问题,是一个女面试官,和蔼可亲,她打开有道词典,问了里面一个功能:网络释义是怎么实现的,如下图所示,
她说网络释义这一块是她带领团队做的。
网络释义这一块,首先在海量的互联网的网页上、文档中去寻找一些固定模型的pattern片段,pattern可以是:xxx(xxx)、xxx:xxx、xxx::xxx等等,找到海量的pattern片段之后,建立和维护一个库,然后根据用户的输入,在这个库当中用倒排索引的方法去查找合适的网络释义显示给用户。
1.网络释义的中文左边界怎么确定 ?举例如下:
用来做塑料袋的主要成份是聚氯乙烯,其放出的气体氯化氢(HCL)是有毒气体。
在这个例子中,氯化氢(HCL)是准确的网络释义,那么我们如何确定 氯化氢(HCL)、体氯化氢(HCL)、气体氯化氢(HCL)、、、、、,哪个是最佳的呢。
由于我们有海量的这样的信息,我们可以用统计学的方法,基于海量的信息计算出各个组合的概率,然后选择概率最大的那种组合入库即可
2.pattern的形式有很多,可以是:氯化氢(HCL)、氯化氢:HCL、氯化氢::HCL、氯化氢--HCL等等,如何找出所有的这种解释说明性的pattern?
不管是:、::、--、()哪一种符号,中文和英文的距离总是很近的,中间是什么符号并不重要,可以用正则表达式代替。解决方法还是基于统计学的方法,计算出距离比较近的各种组合的概率,选择概率大的入库。