@heavysheep
2021-04-01T03:55:27.000000Z
字数 10629
阅读 956
文档
新增了服务内部根据view的倒排,修改簇心生成优先级
修改了默认CLUSTER.threshold的默认参数为0.7,优先考虑准确率
增加了编辑距离算法,融合单一的群组外数据,强化召回
新增了携带配置参数的请求样例
INCIDENT.AREA为二级分类,枚举值包括: INCIDENT.HEAT为[1, 100]的区间。batch_time字段,字段格式为yyyy-MM-dd HH:mm:ss;回调时返回batch_time字段;同时增加INCIDENT.BATCH_TIME表字段;INCIDENT.HOT_TYPE和INCIDENT.HOT_STATUS表字段;SECTION字段为SECTION_LEVEL_和SECTION_LEVEL_2,字段仍以,作为切分,最多存储6个分类;incident_group的key部分改为String类型INCIDENT.ID字段,其他内容不变;IS_DELETE标注逻辑删除的数据转换为物理删除: 当库中有同名batch_name的数据,删除其IS_DELETE != 1或IS_MANUAL != 1的数据;根据需求,如5所述,当有同批次数据入库,且库中存在因IS_DELETE == 1或IS_MANUAL == 1而留库的数据时,如有事件名称相同,进行如下合并处理:
TASK_ID以标注,不更改原留库数据的其他字段,不插入同名新聚类数据;RAW_DATA指向旧的留库数据ID。根据新测试数据,增加了大量normalize逻辑,尽可能过滤无用unicode、乱码、前端标签、原数据分类等字符,防止影响聚类效果和聚类结果名称;尽可能过滤无用unicode等会影响关键词提取的内容;降低了由于乱码导致入库事务失败的可能性;
.env文件是项目部署的基础配置,示例说明如下
# [BASE]ENV=TEST # [环境标签] 枚举为DEV/TEST/PROD区别是日志颗粒度不同TZ=Asia/Shanghai # [时区配置] 正常不需修改# [ORACLE]ORACLE_HOST=172.16.5.129 # [ORACLE HOST] 按需修改ORACLE_USER=dgrd # [ORACLE USER] 按需修改ORACLE_PASSWORD=dgrd # [ORACLE PASS] 按需修改ORACLE_PORT=1521 # [ORACLE PORT] 按需修改ORACLE_CHARSET=UTF8MB4 # [ORACLE_CHARSET] 按需修改DB=orcl # [ORACLE_DB] 按需修改# [REDIS]REDIS_HOST=redis # [REDIS HOST] 指向同网络名为redis的容器,正常不需修改REDIS_PORT=6379 # [REDIS PORT] 正常不需修改REDIS_PASSWORD=xxadksll1 # [REDIS_PASSWORD] 正常不需修改DATA_CACHE=0 # [缓存DB索引] 正常不需修改CELERY_BROKER=1 # [队列DB索引] 正常不需修改# [Middle Platform]MP_SERVER=incident_cluster_server:10001 # [中台位置] 队列任务基于此地址找到中台,正常不需修改# [SERVICE]CLUSTER_SERVICE=cluster_service:8000 # [聚类服务位置] 正常不需修改TAGGING_SERVICE=tagging_service:9190 # [抽取服务位置] 正常不需修改# [CALLBACK API]# [回调API] 按需修改,填写可访问的API# 当任务成功时,会向此API发送JSON数据形式POST请求告知聚类枚举信息CALLBACK_API=incident_cluster_server:10001/comm/callback
_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 |
流程
注意点
[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应包含板块分类,地域分类,情感分类等三项分类业务中的二级分类枚举,枚举外的分类不会被处理,枚举如下
板块分类枚举
地域分类枚举
情感分类枚举
示例为:
{..."classifications": ["宏观经济", "中性", "国内"],...},{..."classifications": ["娱乐", "正面"],...}
| 参数 | 类型 | 是否必填 | 说明 |
|---|---|---|---|
| code | Int | 是 | 状态码 |
| data | Object | 是 | 分类结果列表 |
| --check | Bool | 是 | 检查是否通过 成功: True http状态码202 失败: False http状态码400 |
| message | String | 是 | 处理信息 |
# 请求数据{"batch_name": "2","batch_time": "2020-11-17 15:00:00","raw_data": [{"id": "6034","title": "中央发话后,公安系统揪出了7个“老政法”","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万元。 不过,也有员工表示,在没有发生此事前,世硕也有人员流动,各家工厂的人员流动性原本就比较大,","comment": 72897,"datetime": "2020-09-07 23:52:24","classifications": ["宏观经济", "商业", "金融", "国内", "正面"],"media_type": 1,"view": 7040,"forward": 3284},...]}# 请求携带任务配置,可在此基础进行修改{"batch_name": ...,"batch_time": ...,"raw_data": ...,"task_info": {"CLUSTER": {"size": 500,"strategy": "1v1","threshold": 0.7},"KEYWORD": {"keep_num": 10,"threshold": 0.4},"HEAT": {"strategy": "weight","value_weight": {"view": 1,"comment": 10,"forward": 20},"classification_weight": {"北京": 1,"宏观经济": 1},"media_weight": {"1": 1,"2": 1,"3": 1,"4": 1,"5": 1}}}}# 响应数据: 成功{"code": 0,"data":{"check": True}"message": "请求成功"}# 响应数据: 失败{"code": 1101,"data":{"check": False}"message": "index:[1] param [content] must be string"# 第二条数据的正文字段不为string}
此接口不会修改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 | 是 | 处理信息 |
# 请求{"id": 230,"title": "修改后的名字","heat": 2300,"section": ["政治", "科技"]}# 响应{"code": 0,"data": {"row_count": 1},"message": "更新成功"}
此接口不会删除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 | 是 | 处理信息 |
# 请求{"id": [230, 231]}# 响应{"code": 0,"data": {"row_count": 2},"message": "删除成功"}
热度计算方式可支持多种策略配置,当前的weight计算方式为
(1 + view*view权重 + comment*comment权重 + forward*forward权重) * (多个)匹配分类权重 * 类型权重
# 假设此时有以下数据被聚为同一时间,参数为{"view": 100,"comment": 50"forward": 20,"media_type": 5,"classifications": ["宏观经济"]},{"view": 200,"comment": 10"forward": 5,"media_type": 4,"classifications": ["商业", "北京"]}# 同时有规则"HEAT": {"strategy": "weight","value_weight": {"view": 1, "comment": 10, "forward": 20},"classification_weight": {"宏观经济": 2, "商业": 1.5, "北京": 5},"media_weight": {"5": 2, "4": 1.5}}则聚类结果按"weight"策略计算时,计算方式为数据1: (1 + 100 * 1 + 50 * 10 + 20 * 20) * 2 * 2 = 4004数据2: (1 + 200 * 1 + 10 * 10 + 5 * 20) * 1.5 * 5 * 1.5 = 4511.25则最终该事件热度为: 4004 + 4511.25 = 8515.25 ~= 8515
[POST](json) http://{CALLBACK_API}
| 参数 | 类型 | 是否必填 | 说明 |
|---|---|---|---|
| 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 | 否 | 错误信息 |
# 任务成功{"status": "sucess","batch_name": "2","batch_time": "2020-11-17 15:00:00","incident_group": {"7185": ["6034", "7528"],"7186": ["2438", "2410"],"7187": ["9321"],"7188": ["6216", "6125"],"7189": ["6596", "6032"],"7190": ["9284"],"7191": ["3220"],"7192": ["7944"],"7193": ["8153"],"7194": ["4658"],"7195": ["5605"],"7196": ["7589"],"7197": ["2318"],"7198": ["3811", "3189"],"7199": ["7670"],"7200": ["9908"],"7201": ["5388"],"7202": ["9299"],"7203": ["9141"],"7204": ["5466"],"7205": ["8530"],"7206": ["8399"],"7207": ["3200"],"7208": ["2045"],"7209": ["4569"],"7210": ["2575", "2256"],"7211": ["2912"],"7212": ["2682"],"7213": ["9850"],"7214": ["4016"],"7215": ["7266"],"7216": ["2540"],"7217": ["5198"],"7218": ["5447"],"7219": ["7448"],"7220": ["9385"],"7221": ["4245"],"7222": ["7564"],"7223": ["5374"],"7224": ["5589"],"7225": ["6474"],"7226": ["3716"],"7227": ["6995"],"7228": ["6549"]}}# 任务失败{"status": "failed","batch_name": "2","batch_time": "2020-11-17 15:00:00","incident_group": {},"message": "request tagging service time out error"}
注意: 以下所有列均有非空约束, 由于ORACLE非空约束不允许空字符串"",所有的字符空值为" "
| 参数 | 类型 | 索引 | 说明 |
|---|---|---|---|
| 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:手动 |
| 参数 | 类型 | 索引 | 说明 |
|---|---|---|---|
| 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 | 其他 |
部分逻辑应用于算法聚类前的预处理,可能有帮助
# 删除常规前端标签text = remove_tags(text)# 删除左右两边空格、换行符text = text.strip()# 标准化非utf-8编码,防止处理时一些编码问题text = unicodedata.normalize("NFC", text)...# 低质量数据br换行其他unicode乱码耦合情况较多,先清除br/re.compile(r"br/")# 清除类似 !--{IMAGE_1}-- 等标签re.compile(r"!--[{}A-Z0-9_]*--")# 暴力清除可能的unicode字符# 会影响到以字符、数字开头的文章# 没有精准控制长度为4的原因是多前端标签耦合严重,如果不一次清除干净,段落间留下的p很难处理re.compile(r"\\u[0-9a-z=\\/-]*")# 清除常见来自新浪新闻的特别声明# 该声明后如有内容,基本都是其他文章的链接re.compile(r"特别声明:.*")