我们在做类似搜索相关的特定服务时,通常都会遇到分词解析query,取出其中特定关键字进行检索的问题,这里提供一个简单的基于词槽的query匹配方法。
首先给出一个query示例:北京飞三亚机票多少钱?
我们需要达到的目标:
1.判定这个query的分类
2.解析出机票分类query中的起点和终点
3.从数据中检索对应数据并返回展示
这3个目标对应3个专业名词:1.da识别 2.pattern解析 3.召回判定。
下边我们来一步一步的实现这3个目标:
一、da识别:判定这个query的分类
就这个case而言还是比较简单的,我们可以给一个机票类模糊da词典,列上“机票、飞机、航班”等包含即可判定的关键词,然后给他分配一个分类id比如“1001”,当拿到query时,先用da词典按设定进行模糊或精确匹配,如果匹配上了,比如当前这个case模糊匹配上了”机票”两个字,那么da的结果就是”1001″。
这比“苹果”这种case简单多了,因为苹果可能在“品牌、水果、股票、电影”等很多分类中都存在,这种场景下da的结果就会是多个,比如“1101、1201、1301、1401”。
二、pattern匹配:解析出机票分类query中的起点和终点
da一定识别出了分类,接下来需要做的就要解析出其中的有用信息了。
我们看到,“北京飞三亚机票多少钱?”这个query中,除了关键词”机票”、起止点“北京、三亚”以外,还有”飞、多少钱、?”等其它文字,实际上,用户输入的query五花八门,比如”北京到三亚航班时刻表”,那么我们怎么才能使用一个通过的方法准确的识别出来,又不用花费太大的成本呢?
现在要讲的方法叫基于词槽的匹配方法,它有几个概念先提前解释一下:
词term:所有可能被分词切分的部分,比如“北京、飞、三亚、机票、多少、钱、多少钱、?”都是词。
词槽:用来容纳分词结果的槽位,不同的槽位代表不同的含义,比如“城市、介词、关键词”等槽位。
匹配规则pattern:枚举不同的词槽里的词可能有组合规则。比如“[起点城市][词][终点城市][关键词]”,如果query是“2015款jeep指南者4驱豪华版报价”,匹配规则是“[年款][品牌][车系][驱动模式][版型][意图]”
同义词synonym:用来做同义词转换,比如“北京飞亚龙湾航班”,亚龙湾即不是机场名,也不是机场所在的实际城市,而是个三亚的景点,而我们又想直接给用户显示结果,又想不影响检索性能,那么一个简单的办法就是用同义词把“亚龙湾”转换成“三亚”,这样就能直接用“北京”-“三亚”进行检索了。
杂质词ignore:query中包含的对检索结果无意义的词,他们对检索的结果没有影响,可以完全忽略掉,这部分词统称为杂质词,比如“多少钱、?”。因为这个case我们明确要显示航班、机票价格,所以这“多少钱、?”会无意义,但有些case时我们需要知道用户的意图和语气时,这些词可能又不是杂质词了,比如“宝马3系多少钱”,通过“多少钱”能知道用户是想查车的价格,“宝马3系图片”用户是想看车图,所以不同分类需要单独分析。
好了,了解了词槽匹配的几个概念词后,我们就开始实际实现一下:
term.dict
[from]
北京
…
[to]
北京
三亚
亚龙湾
…
[link]
到
飞
…
[keyword]
机票
航班
…
pattern.dict
[from][link][to][keyword]
[from][to][keywork]
…..
synonym.dict
亚龙湾 三亚
….
ignore.dict
多少钱
时刻表
?
….
编写query解析代码,思路如下:
1.先使用pattern对整个query字符串进行匹配,匹配命中的可以是使用“term.dict词槽(包含)+杂志词(忽略)”组成的任意组合。匹配规则成功时,记录匹配term的key和value,例如:“[{from:北京,link:飞,to:亚龙湾,keyword:航班},{…},..]”,命中的pattern可以是多个,都记录下来。
2.对所有匹配成功的term value执行同义词转换,转换结果为:“[{from:北京,link:飞,to:三亚,keyword:航班},{…},..]”
3.扩展:还可以加上地域扩展,比如用户搜“限行”,我们自动加上他的ip所在城市“北京”,这样就能在下一步调出北京限行数据。
三、召回判定:从数据中检索对应数据并返回展示
有了第一步的da分类判定”10001″、第二步的query解析结果“[{from:北京,link:飞,to:三亚,keyword:航班},{…},..]”,接下来就可以进行数据查询。
通常情况下,不同分类的数据会分开存储,所以我们通过da分类”10001″到对应的数据库中,查询from=北京,to=三亚的数据,如果能调出数据,认为这个分类召回,调出并显示数据即可。如果da识别多个分类都被调出数据,再根据分类权重+分类点击权重+分类停留时长等策略控制分类的展示顺序。
在数据存贮上,简单检索条件的数据,数据存储建议用kv数据库+cache来实现,比如上例中,kv的key可以用”10001_北京_三亚”,这样检索性能相对较好;
有些复杂的场景,比如“2015款jeep指南者2.0t4驱豪华版报价”,用户只想看2015款+jeep+指南者+2.0t+4驱+豪华版的报价,用户的搜索query可能甚至是大于8个字段的复合检索,那么简单的key或普通的关系型数据库都是无法满足的,这时候需要自己实现一个索引存储+kv数据存储的机制,比如数据在建库时,还是以kv的形式存储,但是在存储前,根据检索的pattern配置,为检索字段生成索引数据,存入索引库,索引库中记录所有pattern匹配的数据index及对应kv存储的key,当检索时,就能直接从索引库调出符合索引的kv key,再拿key从kv中调出数据,这样就能以非常好的性能进行多条件检索了。在压力达到一定规模时,索引库和kv再加层cache,性能数据很不错。
这篇文章重点讲解了基于词槽的简单query匹配方法,适合搜索query不定,但对不同query分类有特定业务逻辑的场景。
yan 2016.8.3 0:20