[关闭]
@heavysheep 2021-04-01T11:55:27.000000Z 字数 10629 阅读 620

热点发现系统技术文档v0.7

文档


20210401 更新内容

新增了服务内部根据view的倒排,修改簇心生成优先级
修改了默认CLUSTER.threshold的默认参数为0.7,优先考虑准确率
增加了编辑距离算法,融合单一的群组外数据,强化召回

20210127 更新内容

新增了携带配置参数的请求样例

20210125 更新内容

  1. 修改入库INCIDENT.AREA为二级分类,枚举值包括:
    • 国外
    • 中央
    • 北京
    • 省外
  2. 缩放INCIDENT.HEAT为[1, 100]的区间。

20210104 文档更新内容

20201220 更新内容

详细说明

  1. 按照需求,聚类服务接口新增batch_time字段,字段格式为yyyy-MM-dd HH:mm:ss;回调时返回batch_time字段;同时增加INCIDENT.BATCH_TIME表字段;
  2. 按照需求,新增INCIDENT.HOT_TYPEINCIDENT.HOT_STATUS表字段;
  3. 按照需求,拆分原表中SECTION字段为SECTION_LEVEL_SECTION_LEVEL_2,字段仍以,作为切分,最多存储6个分类;
  4. 按照需求,incident_group的key部分改为String类型INCIDENT.ID字段,其他内容不变;
  5. 根据需求,原先以IS_DELETE标注逻辑删除的数据转换为物理删除: 当库中有同名batch_name的数据,删除其IS_DELETE != 1IS_MANUAL != 1的数据;
  6. 根据需求,如5所述,当有同批次数据入库,且库中存在因IS_DELETE == 1IS_MANUAL == 1而留库的数据时,如有事件名称相同,进行如下合并处理:

    • 更新原留库TASK_ID以标注,不更改原留库数据的其他字段,不插入同名新聚类数据;
    • 新的RAW_DATA指向旧的留库数据ID。
  7. 根据新测试数据,增加了大量normalize逻辑,尽可能过滤无用unicode、乱码、前端标签、原数据分类等字符,防止影响聚类效果和聚类结果名称;尽可能过滤无用unicode等会影响关键词提取的内容;降低了由于乱码导致入库事务失败的可能性;

  8. 设置了每个批次数据数量不超过2500的限制;
  9. 调整了聚类算法服务的超时时间由10分钟改为30分钟;
  10. 修复了一些当验证不通过时,响应信息说明有误的bug;
  11. 由于业务和代码逻辑调整,修改了部分_default.json参数。

20201118晚更新内容

部署代码

码云

配置

.env文件

.env文件是项目部署的基础配置,示例说明如下

  1. # [BASE]
  2. ENV=TEST # [环境标签] 枚举为DEV/TEST/PROD区别是日志颗粒度不同
  3. TZ=Asia/Shanghai # [时区配置] 正常不需修改
  4. # [ORACLE]
  5. ORACLE_HOST=172.16.5.129 # [ORACLE HOST] 按需修改
  6. ORACLE_USER=dgrd # [ORACLE USER] 按需修改
  7. ORACLE_PASSWORD=dgrd # [ORACLE PASS] 按需修改
  8. ORACLE_PORT=1521 # [ORACLE PORT] 按需修改
  9. ORACLE_CHARSET=UTF8MB4 # [ORACLE_CHARSET] 按需修改
  10. DB=orcl # [ORACLE_DB] 按需修改
  11. # [REDIS]
  12. REDIS_HOST=redis # [REDIS HOST] 指向同网络名为redis的容器,正常不需修改
  13. REDIS_PORT=6379 # [REDIS PORT] 正常不需修改
  14. REDIS_PASSWORD=xxadksll1 # [REDIS_PASSWORD] 正常不需修改
  15. DATA_CACHE=0 # [缓存DB索引] 正常不需修改
  16. CELERY_BROKER=1 # [队列DB索引] 正常不需修改
  17. # [Middle Platform]
  18. MP_SERVER=incident_cluster_server:10001 # [中台位置] 队列任务基于此地址找到中台,正常不需修改
  19. # [SERVICE]
  20. CLUSTER_SERVICE=cluster_service:8000 # [聚类服务位置] 正常不需修改
  21. TAGGING_SERVICE=tagging_service:9190 # [抽取服务位置] 正常不需修改
  22. # [CALLBACK API]
  23. # [回调API] 按需修改,填写可访问的API
  24. # 当任务成功时,会向此API发送JSON数据形式POST请求告知聚类枚举信息
  25. CALLBACK_API=incident_cluster_server:10001/comm/callback

_default.json

_default.json位于部署项目的task.d文件下,修改后下次任务生效。
注意点: 常规情况下,media_type参数为int值,但由于此处作为json的key使用,因此改为string格式。系统中有且只有此处的media_type为string。

参数 类型 默认值 说明
CLUSTER Object 聚类配置
--size Int 500 聚类结果数量
超过热度的数据,以热度排序并做截断
--strategy String 1v1 聚类策略,枚举为:
1v1: 1对1比对
--threshold Float 0.7 聚类阈值:超过阈值视为相似,值越大匹配越严格
KEYWORD Object 关键词配置
--keep_num Int 10 保留关键词数量;
值必须>=0;
抽取的关键词在表中以,区隔
--threshold Float 0.4 保留关键词阈值:权重低于此阈值的关键词不会被保存
值必须>=0
抽取的关键词在表中以,区隔
HEAT Object 热度配置
--strategy String "weight" 数据评论量;值必须>=0
--value_weight Object 运算参数权重配置
----view Float 1 浏览量权重: 热度将加和此参数*权重的值
----comment Float 10 评论量权重: 热度将加和此参数*权重的值
----forward Float 20 转发量权重: 热度将加和此参数*权重的值
--classification_weight Object {} 类型权重配置
----(item) Float {} 热度基于以上计算后,将乘以匹配此分类权重的值
示例: {"宏观经济": 2,"北京": 5}
即数据包含宏观经济时热度*2
包含北京时*5
同时包含即为*10
--media_weight Object 0 数据转发量;值必须>=0
----(item) Float {} 热度基于以上计算后,将乘以匹配此分类权重的值
示例: {"1": 1.5, "5":2}
即新闻类型热度*1.5
微博类型热度*5

API

[POST] 聚类热点(数据插入)

说明

请求方式

[POST](json) {cluster_service}/api/cluster

请求头

参数名称 参数值
Content-Type application/json

请求参数

参数 类型 是否必填 默认值 说明
batch_name String 批次名称
batch_time String 批次时间;yyyy-MM-dd HH:mm:ss格式
raw_data List(Object) 数据内容
--id String 数据ID
--title String 数据标题;标题为空时填写空字符串""
--content String 数据正文;正文为空时填写空字符串""
--datetime String %Y-%m-%d %H:%M:%S格式datetime字符串
--classifications List(String) 应包含板块、地域、情感三项分类,枚举参见分类枚举
--media_type Int 媒体类型;
枚举参见媒体类型枚举
--view Int 0 数据浏览量;
值必须>=0;
--comment String 0 数据评论量;
值必须>=0
--forward String 0 数据转发量;
值必须>=0
task_info Object 单次任务规则
未传此参数时,读取预置默认规则
具体参数信息可见default.json

分类枚举

此业务中,classifications应包含板块分类,地域分类,情感分类等三项分类业务中的二级分类枚举,枚举外的分类不会被处理,枚举如下

板块分类枚举

地域分类枚举

情感分类枚举

示例为:

  1. {
  2. ...
  3. "classifications": ["宏观经济", "中性", "国内"],
  4. ...
  5. },
  6. {
  7. ...
  8. "classifications": ["娱乐", "正面"],
  9. ...
  10. }

返回参数

参数 类型 是否必填 说明
code Int 状态码
data Object 分类结果列表
--check Bool 检查是否通过
成功: True http状态码202
失败: False http状态码400
message String 处理信息

请求样例

  1. # 请求数据
  2. {
  3. "batch_name": "2",
  4. "batch_time": "2020-11-17 15:00:00",
  5. "raw_data": [{
  6. "id": "6034",
  7. "title": "中央发话后,公安系统揪出了7个“老政法”",
  8. "content": "原标题:昆山世硕“扔证件”后续:员工排队4小时离职,母公司营收创新高   近日,一段“扔证件”的视频在网上流传。视频显示,江苏昆山的世硕电子(昆山)有限公司工作人员给新员工发证件时,随手将员工证件丢在地上,新员工只能弯腰去捡。事发后,该公司曾发声明,表示主管将率团队向员工致歉。   9月7日下午,近日已从昆山世硕离职的员工告诉新京报贝壳财经记者,近日公司出现离职现象,离职手续并不复杂,但仍然排队超过4小时。不过也有员工表示,工厂(世硕)本身人员流动性就比较高,有人辞职也属于正常现象。记者在招聘网站上看到,昆山世硕如今仍在大量招人,如品保工程师岗位招聘70人,生产组长招聘100人等。   新京报贝壳财经记者9月7日拟就员工离职及公司生产情况采访昆山世硕,多次致电均未能接通。   据昆山世硕官网介绍,公司的母公司为和硕联合科技股份有限公司。后者2019年年报介绍,公司营业收入创新高,原因包括人力规划及原物料管理精实,制造成本达到有效管控。   年报还显示,公司酬金级别中,等级最高的为每年新台币500万元-1000万元,有10名高管在此列,其中就包括昆山世硕的法定代表人张天宝。   员工为离职排队4小时   “今天我去昆山世硕办离职,人太多了,排了4个小时队”。9月7日下午,一名刚从世硕离职的员工向新京报贝壳财经记者表示,他上午办理了离职手续,手续并不复杂,需要在表格内填写姓名、身份证号、银行卡号、工号等信息,但由于办理人数太多,排队等了很久,“一直排到了大马路上”。   还有多名世硕员工告诉记者,最近世硕离职人数众多。有员工说,他们宿舍原本有9个人,目前已经全部离职。还有员工称,自己所在车间原本有上千工人,据他所知已经离职过半。还有一位名为“子弹壳”的网友,自称昆山世硕已离职员工,其在腾讯新闻话题栏目表示,有车间出现大量人员离职。   该员工还称,如果是通过中介介绍入职的,在一定条件下,员工可以拿到一笔“返费”,今天离职的人应该大部分是拿到了返费的人。   记者在昆山世硕直招的公众号上看到,公司本月招聘帖中,给出的员工底薪为2280元、全勤奖金100元、绩效奖金最高400元、岗位津贴最高300元,此外还有夜班补贴和加班工资。其中,打卡55天的返费为1.35万元-1.45万元。   不过,也有员工表示,在没有发生此事前,世硕也有人员流动,各家工厂的人员流动性原本就比较大,",
  9. "comment": 72897,
  10. "datetime": "2020-09-07 23:52:24",
  11. "classifications": ["宏观经济", "商业", "金融", "国内", "正面"],
  12. "media_type": 1,
  13. "view": 7040,
  14. "forward": 3284
  15. },
  16. ...]
  17. }
  18. # 请求携带任务配置,可在此基础进行修改
  19. {
  20. "batch_name": ...,
  21. "batch_time": ...,
  22. "raw_data": ...,
  23. "task_info": {
  24. "CLUSTER": {
  25. "size": 500,
  26. "strategy": "1v1",
  27. "threshold": 0.7
  28. },
  29. "KEYWORD": {
  30. "keep_num": 10,
  31. "threshold": 0.4
  32. },
  33. "HEAT": {
  34. "strategy": "weight",
  35. "value_weight": {
  36. "view": 1,
  37. "comment": 10,
  38. "forward": 20
  39. },
  40. "classification_weight": {
  41. "北京": 1,
  42. "宏观经济": 1
  43. },
  44. "media_weight": {
  45. "1": 1,
  46. "2": 1,
  47. "3": 1,
  48. "4": 1,
  49. "5": 1
  50. }
  51. }
  52. }
  53. }
  54. # 响应数据: 成功
  55. {
  56. "code": 0,
  57. "data":{
  58. "check": True
  59. }
  60. "message": "请求成功"
  61. }
  62. # 响应数据: 失败
  63. {
  64. "code": 1101,
  65. "data":{
  66. "check": False
  67. }
  68. "message": "index:[1] param [content] must be string"
  69. # 第二条数据的正文字段不为string
  70. }

[PUT] 修改热点(此接口弃用)

说明

此接口不会修改IS_MANUAL参数 != 0的数据

请求方式

[PUT](json) {cluster_service}/api/cluster

请求头

参数名称 参数值
Content-Type application/json

请求参数

参数 类型 是否必填 默认值 说明
id Int 数据ID
data_id List(String) 数据ID
title str 热点标题
keyword List(String) 热点关键词
heat Int 热点热度值
section List(String) 热点板块分类
当新标签不在定义中则报错,详见分类枚举
area List(String) 地域分类
当新标签不在定义中则报错,详见分类枚举
sentiment String 0 热点情感分类
当新标签不在定义中则报错,详见分类枚举
total_view Int 0 热点总浏览(点击)量
total_comment Int 0 热点总评论量
total_forward Int 热点总转发量
total_count Int 热点数据总量
sort_index Float 热点排序位置

分类枚举

此业务中,classifications应包含板块分类,地域分类,情感分类等三项分类业务中的一级分类枚举,枚举外的分类不会被处理,枚举如下
板块分类枚举

地域分类枚举

情感分类枚举

返回参数

参数 类型 是否必填 说明
code Int 状态码
data Object 分类结果列表
--row_count Int 实际修改数据量
message String 处理信息

请求样例

  1. # 请求
  2. {
  3. "id": 230,
  4. "title": "修改后的名字",
  5. "heat": 2300,
  6. "section": ["政治", "科技"]
  7. }
  8. # 响应
  9. {
  10. "code": 0,
  11. "data": {
  12. "row_count": 1
  13. },
  14. "message": "更新成功"
  15. }

[DELETE] 删除热点

说明

此接口不会删除IS_MANUAL参数 != 0的数据

请求方式

[DELETE](json) {cluster_service}/api/cluster

请求头

参数名称 参数值
Content-Type application/json

请求参数

参数 类型 是否必填 默认值 说明
id List(Int) 数据ID列表

返回参数

参数 类型 是否必填 说明
code Int 状态码
data Object 分类结果列表
--row_count Int 实际修改数据量
message String 处理信息

请求样例

  1. # 请求
  2. {
  3. "id": [230, 231]
  4. }
  5. # 响应
  6. {
  7. "code": 0,
  8. "data": {
  9. "row_count": 2
  10. },
  11. "message": "删除成功"
  12. }

热度计算

热度计算方式可支持多种策略配置,当前的weight计算方式为

  1. (1 + view*view权重 + comment*comment权重 + forward*forward权重) * (多个)匹配分类权重 * 类型权重

示例

  1. # 假设此时有以下数据被聚为同一时间,参数为
  2. {
  3. "view": 100,
  4. "comment": 50
  5. "forward": 20,
  6. "media_type": 5,
  7. "classifications": ["宏观经济"]
  8. },
  9. {
  10. "view": 200,
  11. "comment": 10
  12. "forward": 5,
  13. "media_type": 4,
  14. "classifications": ["商业", "北京"]
  15. }
  16. # 同时有规则
  17. "HEAT": {
  18. "strategy": "weight",
  19. "value_weight": {"view": 1, "comment": 10, "forward": 20},
  20. "classification_weight": {"宏观经济": 2, "商业": 1.5, "北京": 5},
  21. "media_weight": {"5": 2, "4": 1.5}
  22. }
  23. 则聚类结果按"weight"策略计算时,计算方式为
  24. 数据1: (1 + 100 * 1 + 50 * 10 + 20 * 20) * 2 * 2 = 4004
  25. 数据2: (1 + 200 * 1 + 10 * 10 + 5 * 20) * 1.5 * 5 * 1.5 = 4511.25
  26. 则最终该事件热度为: 4004 + 4511.25 = 8515.25 ~= 8515

对外请求

[POST] **任务成功/失败Callback通知

请求方式

[POST](json) http://{CALLBACK_API}

设定CALLBACK_API流程
  1. 修改.env文件CALLBACK_API为指定API(不含http://)
  2. 重启服务

请求参数

参数 类型 是否必填 说明
status String 任务状态
succes: 任务成功
failed: 任务失败
batch_name String 传入的batch_name字段
batch_time String 传入的batch_time字段
incident_group Object 聚类关系
--{key} String 字符串形式INCIDENT.ID字段
--{value} List(String) 聚类数据ID
message String 错误信息

请求内容

  1. # 任务成功
  2. {
  3. "status": "sucess",
  4. "batch_name": "2",
  5. "batch_time": "2020-11-17 15:00:00",
  6. "incident_group": {
  7. "7185": ["6034", "7528"],
  8. "7186": ["2438", "2410"],
  9. "7187": ["9321"],
  10. "7188": ["6216", "6125"],
  11. "7189": ["6596", "6032"],
  12. "7190": ["9284"],
  13. "7191": ["3220"],
  14. "7192": ["7944"],
  15. "7193": ["8153"],
  16. "7194": ["4658"],
  17. "7195": ["5605"],
  18. "7196": ["7589"],
  19. "7197": ["2318"],
  20. "7198": ["3811", "3189"],
  21. "7199": ["7670"],
  22. "7200": ["9908"],
  23. "7201": ["5388"],
  24. "7202": ["9299"],
  25. "7203": ["9141"],
  26. "7204": ["5466"],
  27. "7205": ["8530"],
  28. "7206": ["8399"],
  29. "7207": ["3200"],
  30. "7208": ["2045"],
  31. "7209": ["4569"],
  32. "7210": ["2575", "2256"],
  33. "7211": ["2912"],
  34. "7212": ["2682"],
  35. "7213": ["9850"],
  36. "7214": ["4016"],
  37. "7215": ["7266"],
  38. "7216": ["2540"],
  39. "7217": ["5198"],
  40. "7218": ["5447"],
  41. "7219": ["7448"],
  42. "7220": ["9385"],
  43. "7221": ["4245"],
  44. "7222": ["7564"],
  45. "7223": ["5374"],
  46. "7224": ["5589"],
  47. "7225": ["6474"],
  48. "7226": ["3716"],
  49. "7227": ["6995"],
  50. "7228": ["6549"]
  51. }
  52. }
  53. # 任务失败
  54. {
  55. "status": "failed",
  56. "batch_name": "2",
  57. "batch_time": "2020-11-17 15:00:00",
  58. "incident_group": {},
  59. "message": "request tagging service time out error"
  60. }

存储表结构

注意: 以下所有列均有非空约束, 由于ORACLE非空约束不允许空字符串"",所有的字符空值为" "

INCIDENT

结构说明

参数 类型 索引 说明
ID NUMBER(*,0) 主键 热点数据ID
TASK_ID VARCHAR2(64 CHAR) 单列索引 任务UUID,用以识别一次任务产生的热点
BATCH_NAME VARCHAR2(64 CHAR) 单列索引 输入的batch_name参数;另以此参数处理去重逻辑
BATCH_TIME DATE 单列索引 输入的batch_time参数
DATA_ID CLOB 热点包含数据ID,多个ID以,区隔
MEDIA_TYPE NUMBER(*,0) 媒体类型
CLUSTER_TIME DATE 聚类时间,%Y-%m-%d %H:%M:%S格式
TITLE VARCHAR2(256 CHAR) 热点标题
KEYWORD CLOB 热点关键词,多关键词以,区隔
HEAT NUMBER(*,0) 热点热度值;缩放为[1, 100]
SENTIMENT VARCHAR2(64 CHAR) 热点情感
SECTION_LEVEL_1 VARCHAR2(64 CHAR) 热点板块一级分类,多个分类以,区隔,最多不超过6个
SECTION_LEVEL_2 VARCHAR2(64 CHAR) 热点板块二级分类,多个分类以,区隔,最多不超过6个
AREA VARCHAR2(64 CHAR) 热点地域(二级分类)
TOTAL_VIEW NUMBER(*,0) 热点总浏览(点击)量
TOTAL_COMMENT NUMBER(*,0) 热点总评论量
TOTAL_FORWARD NUMBER(*,0) 热点总转发量
TOTAL_COUNT NUMBER(*,0) 热点数据量
SORT_INDEX FLOAT(126) 热点排序位置
HOT_TYPE CHAR(1) 热点事件类型
0:热点 1:榜单
默认值: 0
HOT_STATUS CHAR(1) 关联关系更新solr状态
0:未完成 1:已完成
默认值: 0
CREATED_TIME DATE 数据创建时间
LAST_UPDATE_TIME DATE 上次更新时间
IS_DELETE NUMBER(*,0) 是否已删除
0: 未删除 1:已删除
IS_MANUAL NUMBER(*,0) 手动标记
0: 自动 1:手动

RAW_DATA

结构说明

参数 类型 索引 说明
ID (*,0) 主键 数据ID
INCIDENT_ID (*,0) 单列索引 热点数据ID
DATA_ID (*,0) 原始数据ID
HEAT (*,0) 数据热度(根据脚本实时获得数据计算)
view NUMBER(*,0) 数据浏览(点击)量(实时获得值)
comment NUMBER(*,0) 数据评论量(实时获得值)
FORWARD NUMBER(*,0) 数据转发量(实时获得值)
CREATED_TIME DATE 数据创建时间
LAST_UPDATE_TIME DATE 上次更新时间
IS_DELETE NUMBER(*,0) 是否已删除
0: 未删除 1:已删除

其他

媒体类型枚举

以下根据Solr数据生成

类型
1 新闻
2 论坛
3 博客
4 视频
5 微博
6 邮箱
7 图片
8 网盘
9 热搜词
10 热榜
11 两首
12 直播
13 自媒体
14 中小网站新闻
15 中小网站自媒体
16 中小网站新闻论坛
17 中小网站新闻博客
18 问答
19 微头条
20 两会论坛
51 热门微博
99 其他

一些正则逻辑

部分逻辑应用于算法聚类前的预处理,可能有帮助

  1. # 删除常规前端标签
  2. text = remove_tags(text)
  3. # 删除左右两边空格、换行符
  4. text = text.strip()
  5. # 标准化非utf-8编码,防止处理时一些编码问题
  6. text = unicodedata.normalize("NFC", text)
  7. ...
  8. # 低质量数据br换行其他unicode乱码耦合情况较多,先清除br/
  9. re.compile(r"br/")
  10. # 清除类似 !--{IMAGE_1}-- 等标签
  11. re.compile(r"!--[{}A-Z0-9_]*--")
  12. # 暴力清除可能的unicode字符
  13. # 会影响到以字符、数字开头的文章
  14. # 没有精准控制长度为4的原因是多前端标签耦合严重,如果不一次清除干净,段落间留下的p很难处理
  15. re.compile(r"\\u[0-9a-z=\\/-]*")
  16. # 清除常见来自新浪新闻的特别声明
  17. # 该声明后如有内容,基本都是其他文章的链接
  18. re.compile(r"特别声明:.*")
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注