Apache Spark在大规模分布式自然语言处理的应用


  • 青云

    我们TripAdvisor公司拥有大量的用户评价数据,据最近的一次公告,大约有几亿条。我是从事机器学习相关的工作,在机器学习中我们常喜欢做的一件事就是堆砌大量数据来分析。

    最近我一直在研究一个有趣的问题,我想给大家介绍一下。在这篇博文里,我先会引入问题,以及解决它的技术支持手段。在后续的博文里,我将深入剖析算法本身。如果你最近浏览过Tripadvisor网站,也许会注意到我们给站点内的宾馆、餐厅和景点都贴上了不同的元数据标记(我们称之为标签)。其中一些是我们从各种数据源搜集的简单是非问答结果。如“这家宾馆是否提供游泳池?”,“这是一家意大利餐馆吗?”等等。

    如果有可靠的数据源,这些信息对我们很有帮助,可是如果没有呢?也许在世界的某个角落你始终无法获得可靠的数据源(毕竟我们的业务遍布全球)。有时候又会遇到主观性问题,像“这是个浪漫的宾馆吗?”所有的宾馆经理可能都给出一个肯定的答案。顾客却不一定这么认为。那么该如何对付这些问题呢?其实,当你拥有像我们这么优质的客户基础时,你直接问他们就够了。这段时期,我们一直让用户在“发表评价”的表格最后或者其它地方再回答一些简单的是非题。平均每个评价里,用户能回答三个问题。这些答案对我们来说是非常有用的,同时也能惠及站内的其它用户。

    最近,我正在努力挖掘这些答案的最大潜在价值,这个项目被称之为“自动贴标签”。任何时候如果对用户的答案没有把握,你可以直接去询问用户那些问题,但这会浪费他们时间,结果的覆盖率也有局限性。为了避免上述情况,我们基于自然语言构建了回归模型,来预测用户对每个问题回答“是”或者“不是”的概率。这样我们只有在给出所有数据仍不能确定用户答案的时候才去询问他们。

    具体说来,就是当用户在填写评价表时,我们尝试在见到用户填写的内容前,去预测该用户对给定的贴标签问题回答“是”的概率值。注意,这与看到评价表的内容再做预测是有区别的。因为我们不是想预测当前这位用户是否度过了一个浪漫之夜,亦或宾馆是否给他们带来了家的温馨感觉。我们是想知道下一位客户是否在这家宾馆能有上述那些体验。我发现当人们经历一段非常浪漫的时光后,他们就会基于自己的体验给宾馆一个浪漫的标签,而不在意宾馆的其它方面品质。通过预测某个特定地区的赞成投票比例,我们能平滑这种噪音的影响,从而得到对某个宾馆、饭店、景点的浪漫程度、温馨程度等方面的客观预测。

    我们采用半监督形式的逻辑回归来处理这个问题。模型主要包含“词袋”类型的特征,来自用户提交的对于宾馆各方面的文字评价。由于它属于一种半监督方法,所以我们不仅用带有标签的地点评价数据训练模型,还使用了大量未标记的数据。另外,在实际应用模型预测最终结果时,我们还需要读取和处理所有评价记录。在这之上,我们得到了上百个不同的标签。

    大家思考一会儿。上百万条的评价记录乘以上百个标签。算法本身就很炫酷,我也将在另一篇博文里详细介绍。今天,我想先介绍算法依赖的技术方法。我们使用Spark技术来实现这个算法。Spark是一款卓越的数据分布式计算引擎,它能把数据分散到集群的所有节点进行计算。它和Map/Reduce有两个重要的区别:

    • Spark程序代码更容易阅读和理解,因为一切都是逐步展开,没有太多的模板规则。比如,对比Spark和Map/Reduce对Word Count(大数据领域的“Hello World”)的实现过程。
    • Spark的操作都在内存中完成,只在需要的时候把数据写出到磁盘。

    基于Spark技术,处理所有这些数据的过程就显得简洁易懂。我们仅需把所有文字评价读入分散在集群各个节点的内存中,然后迭代地每次处理一个标签。原来最耗时的反复读文件和转换数据格式步骤,现在只需要在开头处理一次就够了。

    整个数据处理过程被分为三个阶段。

    • 数据集生成:读入对所有地点(饭店、宾馆、景点)有投票的所有评价,然后给每个标签生成一个数据集。这一步包括特征选择、生成特征向量和准备交叉验证数据集。(后两步对解决本问题至关重要。)
    • 训练模型:对每个标签,调整规则化参数并训练模型。这个原本“尴尬的并行”阶段被Spark的并行计算操作完美地解决了。我只需要把数据集广播到各个节点,并且并行我想调整的参数。每个任务仅返回我用来选择模型的误差估计值。
    • 应用:把所有评价读入内存。没错,是所有的。迭代地给每个地点的每个标签打分,把结果存储到Hadoop文件系统。再用“加载数据”把他们导入Hive,这一步本质上就是一个HDFS的简单重命名操作。
    所有步骤都极度高效地完成。Spark让我方便地控制哪些内容需要保留在内存中,哪些不再有用的需要涮出。我还能选择数据在节点的分区方式。我确保数据基于地点的ID分区,使得reduction和grouping步骤的节点间数据交换最少。除此之外,我可以使用真正的、易读的Java语言。不必再拘泥于使用某些类SQL语言,或者Map/Reduce要求的大量模板规则和易混淆的代码。

    我对Spark提供集群操控功能真的十分满意,强烈推荐大家也用一下。

    原文链接:http://www.csdn.net/article/2015-09-06/2825618


登录后回复
 

与 青云QingCloud 社区 的连接断开,我们正在尝试重连,请耐心等待