基于FAQ的智能问答(一): Elasticsearch的调教

背景

对话领域是当前最热门的一个NLP的方向之一,无论在学术界还是在工业界。由此衍生出来的产品包括通用形态的苹果siri,微软小冰,小米的小爱同学等,以及各个行业领域的智能助手,智能客服等。 这些产品基本可以看成下一代人机自然语言交互的雏形。

具体而言人机对话又可以拆分为以下几种形式:

(1) FAQ-Bot: 基于常见问答对的问答,也是运用最为广泛的智能问答技术,可以认为是最朴素的一种对话。抽象出来是一个信息检索的问题,给定用户的问题,在由{问答:答案}组成的知识库中检索相似的问题,最后将与用户相似问法问题的答案作为结果返回给用户。

(2) MRC-Bot: 基于机器阅读的智能问答,一般运用在开放域的问答中。给定用户的问题,具体分成召回和机器阅读两个阶段,先从知识库中检索出可能存在答案的文档,再针对文档做机器阅读确定答案。在实际落地中也很有前景,相比FAQ-Bot用户不需要耗费很大力气构建知识库,只需要上传产品文档即可。但是目前机器阅读的准确性还不够,效果不稳定,还不能直接将机器阅读的结果作为答案返回给用户。

(3)KG-Bot: 基于知识图谱的问答,一般用于解答属性型的问题,比如“北京的市长是谁”。给定用户的问题,需要先解析成知识图谱查询语句,再到知识图谱中检索答案。这种问答一般回答的准确率非常高,但是能回答的问题也非常局限,同时构建知识图谱非常耗费人力。

(4)Task-Bot: 任务型对话,是面向特定场景的多轮对话,比如“查天气”,“订机票”。"Task oriented dialogue"在学术和工业界都已经有了很深入的研究,分成pipeline和end-to-end两种思路。在实地落地过程中,难得是如何让用户自主的灵活配置一个任务型对话场景,训练语料可能只有一两条,如何训练出一个NER的槽位?

(5)Chat-Bot: 闲聊对话,一般用于提高机器人的趣味性,比如“你是谁?”,“你是机器人吗?”等。在学术上一般基于end-to-end的方案,可以支持多轮,但是回复结果不可控。所以在实际落地中还是会转换成FAQ-Bot,预先构建一个寒暄库,转换成检索的任务。

机器人类型知识库结构核心技术落地难度
FAQ-Bot{问题:答案}信息检索
MRC-Bot文档信息检索+机器阅读
KG-Bot知识三元组知识图谱构建/检索
Task-Bot槽位/对话策略对话状态跟踪/管理
Chat-Bot{寒暄语:回复}信息检索

总结:目前最简单最切合实际的落地方式还是基于FAQ-Bot,而目前“智能客服”等产品采用的技术也大都基于此。

所以本系列文章将系统分享FAQ-Bot是如何进行产品化落地,在实际落地过程中踩过的坑以及我们自己的一些微创新。

Elasticsearch的搭建

基于FAQ的智能问答,本质是一个信息检索任务,而Elasticsearch真是这个领域的必备的工具!

Elasticsearch:官方分布式搜索和分析引擎 | Elastic

Elasticsearch:官方分布式搜索和分析引擎 | Elastic​www.elastic.co/cn/elasticsearch/正在上传…重新上传取消

贴一段官网上的介绍:

速度:Elasticsearch 很快,快到不可思议
可扩展性:可以在笔记本电脑上运行。也可以在承载了 PB 级数据的上千台服务器上运行。
相关度:搜索所有内容,找到所需的具体信息

简单的说,将问答对{q:a}存入ES中以后,给定一个用户的问题(query),ES可以快速返回有序的相似问题。

具体在搭建ES的过程中,还有几点需要注意:

(1) 版本:推荐使用7.x版本!!

ES的7.x版本的核心安全功能免费提供了,意味不用去破解x-pack获取密码登陆的功能了...

同时7.x版本配套的kibana整体风格也更明快,同时也多了“机器学习”等新的模块。

ES 7.8版本的Kibana

(2) 安装: docker

推荐使用docker快速安装elasticsearch和kibana

Install Elasticsearch with Docker​www.elastic.co/guide/en/elasticsearch/reference/current/docker.html正在上传…重新上传取消

需要注意的是基于docker安装需要在宿主机器上额外设置virtual memory

sysctl -w vm.max_map_count=262144

Virtual memory | Elasticsearch Reference [7.10] | Elastic​www.elastic.co/guide/en/elasticsearch/reference/current/vm-max-map-count.html正在上传…重新上传取消

如果基于k8s启动则需要配置一个初始化容器

initContainers:
- name: increase-vm-max-map
    image: busybox
    command: [ "sysctl", "-w", "vm.max_map_count=262144" ]
    securityContext:
    privileged: true

(3) 分词:

中文场景下需要使用分词的插件,一般常用的就是 IK 分词器;安装时候需要选择对应的ES版本。

https://github.com/medcl/elasticsearch-analysis-ik​github.com/medcl/elasticsearch-analysis-ik

如果基于docker启动的es,则可以自己构建一个包含了IK分词器的docker镜像。

与MySQL的数据同步

一般业务数据(知识库中的问答对)都存储在MySQL中,所以ES的数据来源是MySQL,并且如果数据发生了变化(增删改查)需要及时的从MySQL同步到ES中。

调研了一圈ES与MySQL的同步方案,最终选择阿里的canal ,运行至今,也一直非常稳定。

canal架构图

canal [kə'næl],译意为水道/管道/沟渠,主要用途是基于 MySQL 数据库增量日志解析,提供增量数据订阅和消费

canal具体分成server与client两端,server端监控MySQL,并将接收到的binlog数据投递到MQ,client端负责从MQ中消费binlog数据,并处理后写入到ES中.

如果通过容器启动,需要启动server和client两个服务。

需要注意的是该同步服务是增量同步,也就是一旦client处理错误,或者server不稳定丢了binlog,binlog就不会再次同步了。

所以会进行定期的MySQL和ES全量数据同步,一般在每天深夜进行。

支持首字母与拼音检索

经过上面两个步骤,启动了ES,从MySQL中同步了数据,就已经具备了检索的功能了!

query: "公务员考试"

search_result: "公务员考试省考与国考题型区别大吗?"

“公务员考试”搜索结果

这时候希望额外支持对首字母,拼音,以及混合的检索,即支持:

query: "gongwuyuan考试" , "gwyks", "公务员ks" , "公务员考试"

search_result: "公务员考试省考与国考题型区别大吗?"

这时候就需要引入另外一个分词器: medcl/elasticsearch-analysis-pinyin

安装以后,具体还需要额外配置

(1) 配置默认分词器为ik分词器,并引入pinyin分词器

"analysis": {
    "analyzer": {
        "default":{
            "tokenizer":"ik_max_word"
        },				
        "pinyin_analyzer": {
        "type": "custom",
        "tokenizer": "custom_pinyin",
        "filter": ["word_delimiter"]
        }
    },
    "tokenizer": {
        "custom_pinyin" : {
        "type" : "pinyin",
        "keep_first_letter":true,
        "keep_separate_first_letter" : false,
        "keep_full_pinyin" : true,
        "keep_original" : false,
        "limit_first_letter_length" : 16,
        "lowercase" : true
        }
    }
}

(2) 对于需要支持拼音检索的字段,配置拼音分词

"question" : {
    "type" : "text",
    "analyzer" : "ik_max_word",
    "boost" : 20
    "fields" : {
        "pinyin" : {
            "type" : "text",
            "term_vector" : "with_positions_offsets",
            "analyzer" : "pinyin_analyzer",
            "boost" : 10
            }
    }
}

(3) 同时支持拼音和汉字检索

通过multi_match的检索,可以同时对quesiton和quesiton.pinyin两个字段进行检索

{
  "query": {
    "multi_match": {
      "type":"most_fields",
      "query":"公务员ks",
      "fields":["quesiton", "quesiton.pinyin"]
    }
  }
}

当然还可以配置更精细的检索规则,例如:"如果query中包含中文,则必须包含在返回的结果中"等。

自定义词典

如果引入了IK分词器,会自动引入一个中文的词典:elasticsearch-analysis-ik/config/main.dic

但是,这个词表还是有局限的。针对例子: "美甲上门服务", 以下是ik的分词结果

美甲上门服务 的IK分词结果

可以看到切出了一个很奇怪的词语: "甲上", 而最新的词的"美甲"是没有被正确切分的。

所以检索“美甲”检索到的结果会很靠后,只有“美” 命中。同时“美甲”不能高亮显示。

经查证:“甲上”确实是IK中自带的一个词

IK的词典

所以需要根据自己的业务场景,配置领域词典,对于该例,配置词典“美甲”即可。

IK分词器支持配置远程扩展字典,所以,产品上可以支持由用户自己在前端配置领域词典。

停用词

IK分词器也自带了停用词,如下所示

IK的停用词

这个默认的词典只有33个英文,自然的想法是我们一般都是中文的场景,所以这33个英文停用词是远远不够。而Github上刚好也由一份相对完备的中文停用词表,2K+ star

https://github.com/goto456/stopwords​github.com/goto456/stopwords

所以会尝试在自己的项目中直接用仓库中整理的停用词表,例如“baidu_stopwords”,停用词达到了1300多个!

但是,实际场景中会造成很大的误伤!!

例如配置了baidu_stopwords:

检索 :“附近有哪些药店?”

因为: “附近”是停用词,"有"是停用词,“哪些”是停用词,“?”是停用词

这样经过停用词处理以后只有“药店”,相比原本的query丢失了很多的信息!

所以我们最后自己维护了一份停用词表,只有标点符号和最基本的语气词,包括"吗","呢"等

甚至有的场景下没有配置停用词,实际效果也没有下降。

最后

ES在IR领域是非常“宝藏”的工具,在信息检索中绝大多数业务功能:“输入联想”,“分组查询”,“分页查询”,“基于GIS附近的人”等都有了很好的支持,同时ES的社区非常活跃,版本也在持续更新维护。所以了解学习ES可以做到遇事不慌,快速搭建出一个能用的baseline~

基于FAQ的智能问答(一): Elasticsearch的调教 - 知乎

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值