唯有回望,才能发现,我们究竟已经走出多远。唯有前瞻,才能相信,我们沿着这条航线,一定能抵达梦想的彼岸。
标签匹配算法分析
假设有一篇文章,标题和内容如下:
标题:Spring Boot 容器选择 Undertow 而不是 Tomcat
内容:Spring Boot内嵌容器支持Tomcat、Jetty、Undertow。为什么选择Undertow?这里有一篇文章,时间 2017年1月26日发布的:Tomcat vs. Jetty vs. Undertow: Comparison of Spring Boot Embedded Servlet Containers这篇文章详细测试了Spring Boot应用在三种容器下的性能和内存使用,内含完整的测试代码和测试流程。证明了Undertow在性能和内存使用上是最好的。
如果要为此文章自动生成标签,该如何做呢?
1、创建一个带指针的字符串对象
|↓| |:--:| |S|p|r|i|n|g| |B|o|o|t|
2、生成标签字典
此处需要一个标签库,可以利用爬虫技术从相关资源网站爬取
2.1 定义标签节点 TagNode
属性 | 数据类型 | 描述 |
headTwoCharMix | int | 标签头2个字符的int值 |
words | TreeSet | 头2个字符相同的标签集合 |
next | TagNode | 指向下一个标签节点的指针 |
2.2 生成字典 TagNode[]
-
① 初始化标签节点数组,数组大小(size)最好与标签库的数量相同,因为数组是顺序存储的,通过下标查找,速度非常快; -
② 计算标签头2个字符的Hash值(hash),计算标签应该存到数组的位置(hash & (size - 1)); -
③ 如果数组该位置为空,为此标签生成节点,添加此节点到该位置; -
④ 如果数组该位置不为空,判断标签和此位置的节点的headTwoCharMix是否相等,若相等,则将标签添加到 TreeSet 中,若不相等,则生成新的节点,并用指针关联;【拉链法解决Hash冲突】
2.3 在文本中匹配标签
↓ | |||||||
S | p | r | i | n | g | B | |
选 | 择 | U | n | d | e | r | |
是 | T | o | m | c | a | t |
指针从文本的开头,向后遍历,计算当前的位置的headTwoCharMix,即此处的 “Bo” 2个字符,然后计算Hash值定位到字典的位置,字典的位置只会出现如下两种情况:
- 无节点:指针向后移动,继续匹配;
- 有节点:计算 headTwoCharMix ,若 headTwoCharMix 相等,然后根据 TreeSet 中的标签,进行最长匹配;若 headTwoCharMix 不相等,则用后继节点来匹配,直到后继节点为空位置。中途匹配到标签,则指针直接向后移动(标签的长度)位。
标签匹配在实际应用中的问题
1、权重问题
标题和内容的权重应该是不同的,所以在匹配出标签的时候,需要给匹配到的标签添加分数,依据得分高低对匹配标签排序
2、英文字符大小写的问题
例如:标签库中有一个标签“Docker”,结果文中出现的是 “docker”,这两个字符串是不相等的,从逻辑上来讲,标签是匹配到的,所以要调整算法,将大写字母全部转换为小写字母来匹配
标签匹配核心算法
带指针的字符串 StringPointer.java
标签节点 TagNode.java
标签分数统计类 TagBean.java
标签匹配工具类 TagTools.java