概要
最近天猫客户端上线了一个新功能“大家最关心”,当用户搜索某些商品类别(比如“冰箱”)时,搜索结果中会出现一个模块,列出该类别下用户经常问到的一些问题(比如“声音大吗”)。
如果用户对这些问题感兴趣,可以继续点击进去看到更详细的信息。
这里面包含了所有常问到的问题。当用户选择某具体问题时,模块还会从所有用户写的商品评论里选出针对该问题的评论,并参考商品销量及评论情感等对商品进行排序,帮用户选出他关心的问题下较合适的商品(比如“无异味的冰箱”)。
目前该模块已经覆盖了沙发、床、电视柜、餐桌、餐椅、茶几、床垫、吊灯、吸顶灯、冰箱、洗衣机、扫地机器人、空气净化器、净水器、手机、耳机、笔记本电脑、投影机、蓝牙音箱等这几个大类。
要解决的问题
要实现上面的模块需要解决如下的问题:
问题选取
用户提交的问题里有些是针对某一商品的,比如“有多重?”,“什么面料的?”,有些是没有明确答案的,比如“好用吗?”,“哪个颜色好看?”,这些问题都应该去掉,只保留对某类商品通用的问题,比如“好安装吗?”,“掉色吗?”。
重复问题合并
用户提交的问题里很多意思都是重复的,比如“声音大吗?”,“声音大不大?”,“冰箱声音大吗?”,这类问题在模块中不能重复显示,而是显示最有代表性的一个。
问题和商品评论的关联
和“问大家”里的回答不同,当用户提交商品评论时,并不是针对具体问题去写的。比如这个评论“加湿器雾气很大,也没有多大的噪音,颜色比白色好看”里提到了商品的多个特性,而不是针对“噪音大吗?”这样的问题作了回答。所以,评论数据需要和问题数据进行关联。一个评论可以回答多个问题,也可能回答不了任何问题。只有正确生成了评论-问题间的映射,才能在每个模块里显示最相关的商品评论。
数据
该模块用到的数据主要来自下面几张表:
- 淘宝-社区-内容库(tbods.s_macross_feed):该表包含了淘宝网上“问大家”模块里用户提交的关于商品的所有问题和答案。
- ha3的全量评价表(search_kg.s_kg_all_comment_for_ha3):该表包含了淘宝网上用户提交的所有商品评论。
此外,还用到了淘系商品全量表(tbcdm.dim_tb_itm),卖家评分表(search_ats.ali_seller_matrix_open_d)和商品品类词表。
预处理
由于原始数据中存在噪声,数据需要被预处理后才能做为后续算法的输入。
对于问题,特殊字符和标点会从句子中删除。对于评论,空评论,无效评论和默认评论(“评价方未及时做出评价,系统默认好评!”)会从数据中删除。同时,被提问次数低的问题,销量低的商品,评分低的卖家也会从数据中移除。这样可以提高数据质量,并减少后续的计算量。
算法
词向量
由于训练数据集较少,我们直接使用了预训练的fastText数据做为中文的word embedding,该数据集使用了中文维基百科的文章进行训练,具体可参见【1】。
问题过滤
将问题转化为词向量之后,我们构造了如下分类器来判断问题是否应该被过滤。
首先,我们使用Bidirectional LSTM来学习对整句的理解,然后取出最终的hidden state,经过dropout layer之后,通过MLP来生成一个是否需要过滤该问题的概率。对于该模型,我们从几个类别中挑出了5000多个常见的问题,对该问题是否需要被过滤掉(是否是“针对问题”,“常见问题”,…)进行人工标注,然后随机使用80%的数据做训练,20%的数据做测试。最后选取在测试数据上准确率大于95%的模型发布到线上。
类目下所有问题经过过滤后,我们将其按频率从高到低排序,做为下一步的输入。
问题聚类
在对问题进行聚类之前,我们首先需要构造一个分类器,用于判断两个问题是否是同样的意思。这个问题是NLP领域中的一个开放问题,最近有很多新算法的提出,可以参考【2】。由于我们训练数据不大,采用了如下简单的模型:
由于问题对中的两个问题在分类器中处于同样的地位,我们在模型中使用了对称的网络结构。对于每个问题,我们首先使用Bidirectional LSTM来对句子意思进行编码,然后把当前问题的隐层表示作为query(target),另外一个问题的隐层表示作为memory(source)。接着使用下面的公式算出两个序列间每对位置的相似度:
假设隐层维数是d,则W是一个d*d的变量。然后使用下面的公式对query的每个位置算出attention vector:
其中WcWc是一个d*2d的变量。Attention vector将作为第二层Bidirectional LSTM的输入。这里使用的是Luong’s attention,具体算法见【3】。
最后,我们将两个问题在第二层Bidirectional LSTM的最终隐层输出连接在一起,经过dropout之后,再由一个MLP生成这两个问题是重复问题的概率。
为了生成训练数据集,我们从高频问题里生成了1万多的问题对,对是否是重复问题进行人工标注,最后用和“1. 问题过滤”类似的方法检验模型。
为了进一步提高聚类结果的准确率,我们设计了一个新的聚类算法,而不是简单由模型结果判定两个问题是否应该归为一类,具体如下:
- 将问题按频率降序排列,遍历每一个问题。
- 如果没有任何类,创建一个新类并将当前问题加入其中。
- 否则,对于每个已有类中所有问题,由模型判断当前问题是否和这些问题重复。如果当前问题和某个类中所有问题都重复,则将当前问题加入该类;如果当前问题和所有类中的所有问题都不重复,则创建一个新类并将当前问题加入其中;如果前面两个条件都不满足,就跳过当前问题处理下一个。
- 输出分类成功的问题以及对应的类编号。
通过使用新的聚类算法,召回率有所损失,但是准确率得到了很大的提高。
问题和评论的关联
判断一段话中是否包含某问题的答案是NLP领域里非常难的一个问题。目前这个问题并没有很好的解决方案。由于没有现成的训练数据集,我们使用了“问大家”中的数据做训练。我们尝试了和“2. 问题聚类”中类似的模型(由于问题和段落不是对称的,模型的两侧不再共享参数),但是在商品评论数据上应用时发现准确率较低。模型性能差的主要原因是“问大家”里的回答都是很短的句子,而商品评论大部分都是长得多的段落。这种训练数据和测试数据的差异导致了模型通用性的缺失。为了解决这一问题,我们采用了基于规则(关键词匹配)的评论检索方式。这种方法的缺点是召回率和可扩展性比模型低,但优点是准确率要高得多。
后续工作
- 将该模块在手淘上线,提高用户数。
- 使用模型来生成和问题相关的评论,使该方法能够容易扩展到更多的类目上,来增加对商品的覆盖率。
- 使用最新的机器阅读理解模型(比如BERT)来提高模型准确率。
参考资料:
【2】https://www.kaggle.com/c/quora-question-pairs
【3】https://arxiv.org/abs/1508.04025