Frone's Blog

技术小窝


  • 首页

  • 关于

  • 标签

  • 分类

  • 归档

  • 公益404

pip使用国内源

发表于 2018-07-27 | 分类于 算法 | 阅读次数:

安装 Pulp 等包时遇到问题

在安装一个不是很常用的python库时 遇到了长时间无法下载安装的问题,之前也有配置过国内的pip 源所以在这整理下

直接修改国内源为默认

创建或修改配置文件

linux的文件在~/.pip/pip.conf,

windows在%HOMEPATH%\pip\pip.ini)

1
2
3
4
[global]
index-url = http://pypi.douban.com/simple
[install]
trusted-host=pypi.douban.com

除了豆瓣还有其他的国内源:

  • 阿里云 http://mirrors.aliyun.com/pypi/simple/
  • 中国科技大学 https://pypi.mirrors.ustc.edu.cn/simple/
  • 豆瓣(douban) http://pypi.douban.com/simple/
  • 清华大学 https://pypi.tuna.tsinghua.edu.cn/simple/
  • 中国科学技术大学 http://pypi.mirrors.ustc.edu.cn/simple/

其他

此外在此mark一下 Pulp, 处理线性规划问题

  1. 文档主页
  2. 案例

如何在hexo中支持Mathjax

发表于 2018-07-16 | 分类于 Hexo | 阅读次数:

第一步: 使用Kramed代替 Marked

hexo 默认的渲染引擎是 marked,但是 marked 不支持 mathjax。 kramed 是在 marked 的基础上进行修改。我们在工程目录下执行以下命令来安装 kramed.

1
2
npm uninstall hexo-renderer-marked --save
npm install hexo-renderer-kramed --save

然后,更改/node_modules/hexo-renderer-kramed/lib/renderer.js,更改

1
2
3
4
5
// Change inline math rule
function formatText(text) {
// Fit kramed's rule: $$ + \1 + $$
return text.replace(/`\$(.*?)\$`/g, '$$$$$1$$$$');
}

为

1
2
3
4
// Change inline math rule
function formatText(text) {
return text;
}

第二步: 停止使用 hexo-math

首先,如果你已经安装 hexo-math, 请卸载它,然后安装 hexo-renderer-mathjax 包

1
2
npm uninstall hexo-math --save
npm install hexo-renderer-mathjax --save

第三步: 更改默认转义规则

因为 hexo 默认的转义规则会将一些字符进行转义,比如 _ 转为 , 所以我们需要对默认的规则进行修改.

1
vi node_modules/kramed/lib/rules/nline.js

1
2
3
4
5
6
7
8
9
// 替换11行
escape: /^\\([\\`*{}\[\]()#$+\-.!_>])/,
//修改为
escape: /^\\([`*\[\]()# +\-.!_>])/,

//替换20行
em: /^\b_((?:__|[\s\S])+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
//修改为
em: /^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,

第四步: 开启mathjax

1
vi themes/next/_config.yml

开启 mathjax功能

1
2
3
4
mathjax:
enable: true
perpage: false
cdn: //cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML

并在博客中使用mathjax

1
2
3
4
5
6
---
title: Testing Mathjax with Hexo
category: Uncategorized
date: 2017/05/03
mathjax: true
---

Jaro–Winkler算法原理和应用

发表于 2018-07-16 | 分类于 算法 | 阅读次数:

[TOC]

算法简介

The Jaro–Winkler distance (Winkler, 1990)是计算2个字符串之间相似度的一种算法。它是Jaro distance算法的变种。主要用于record linkage/数据连接(duplicate detection/重复记录)方面的领域,Jaro–Winkler distance最后得分越高说明相似度越大。Jaro–Winkler distance 是适合于串比如名字这样较短的字符之间计算相似度。0分表示没有任何相似度,1分则代表完全匹配。

算法定义

  1. The Jaro distance算法最后得分公式:其中:
  • s1、s2 是要比对的两个字符
  • $d_j$是最后得分
  • m是匹配的字符数
  • t 是换位的数目
  1. Match Window(匹配窗口)计算公式其中:
  • s1、s2 是要比对的两个字符
  • MW是匹配窗口值
  1. 上述公式解释
  • 字符串s1与字符串s2在做匹配计算时,当两个字符的距离不大于公式二的最后结果(匹配窗口)即认为是匹配的。
  • 当s1、s2中字符相匹配但是字符位置不一样时发生换位操作、而公式一中换位的数目t为不同顺序的匹配字符的数目的一半。比如:两个字符串CRATE和TRACE做匹配操作,字符串中仅有’R’ ‘A’ ‘E’三个字符是匹配的,即m=3。为什么’C’, ‘T’不算做是匹配的呢。因为虽然’C’, ‘T’都出现在两个字符串中,但是通过公式二得出匹配窗口值为 (5/2)-1=1.5。而两个字符串中’C’, ‘T’字符的距离均大于1.5。所以不算做匹配。因此t=0。在另一组字符串DwAyNE 与 DuANE 。匹配的字符D-A-N-E 在两个字符串中有相同的字符顺序,所以不需要进行换位操作,因此t=0,m=4。
  1. Jaro–Winkler distance算法公式
    Jaro-Winkler算法给予了起始部分就相同的字符串更高的分数,它定义了一个前缀范围p,对于要匹配的两个字符串,如果前缀部分有长度为L的部分字符串相同,则Jaro-Winkler Distance为:其中:
  • $d_j$是Jaro distance最后得分
  • L是前缀部分匹配的长度
  • P是一个范围因子常量,用来调整前缀匹配的权值,但是P的值不能超过0.25,因为这样最后得分可能超过1分.Winkler的标准默认设置值P=0.1。

例子

给出两个字符串 s1 MARTHA 和 s2 MARHTA、我们可以得出:

  • m = 6
  • |s1| = 6
  • |s2| = 6
  • 两组字符T/H和H/T要进行换位操作,因此t=2/2=1;
    我们可以根据公式一得出Jaro得分:如果使用Jaro–Winkler,并且取范围因子P=0.1,我们会得出:
    P=0.1
    L=3
    $d_w = 0.944 + (3 * 0.1(1 - 0.944))=0.961$

python 运行

  1. 安装lib

    1
    pip install jaro_winkler
  2. 程序运行

    1
    print(jaro.jaro_metric("MARTHA".decode("utf-8"),"MARHTA".decode("utf-8")))

优化

  1. 多进程
  2. pandas

名片别名标注

发表于 2017-05-08 | 分类于 IMORA | 阅读次数:

名片别名标注

一.业务整体流程

为满足整体橙子语音检索时的需要,为名片现有数据自动添加标签。目前主要包括四部分:

  • 根据职位头衔为高管级姓名后添加称呼,如总、董等。
  • 为公司名添加别名,如北京橙鑫数据科技有限公司的别名为橙鑫或IMORA
  • 从公司名通过切词来提取中心词,为公司名增加标签
  • 从公司基本信息表获取城市字段,加为标签

1.数据来源:
可能涉及到如下数据表

  • 别名信息表
    oradt_cloud_test2.contact_card_removeword_alias
  • 公司别名表
    oradt_cloud_test2.orange_company_alias

2.整体处理流程
本系统使用到名片基本信息,需要在名片基本信息拓展系统处理之后运行,处理流程如下图:

图片备份位置:/home/samba/share/mengqian/handover/名片信息拓展/alias-step.png

  • 对应到代码,整体的入口为main,主要用来通过时间区间来控制需要计算的数据起始时间。并调用jobContrl中的读取数据、处理数据及序列化的方法,控制程序流程。
  • 城市标签
    由于添加城市标签功能为后续添加,没有修改整体处理流程,添加到main中,其他任务结束后,追加更新别名表中的city字段。
  • 由jobContrl实现数据输入输出格式的转换,业务处理逻辑调用dataPreprocessing实现。
  • dataPreprocessing 调用各个功能模块,拼合结果数据。

二.功能模块说明

主要功能模块的包结构如下图:

图片备份位置:/home/samba/share/mengqian/handover/名片信息拓展/alias-classes.png

  • 公司名关键词提取
    orgKeyWords
  • 公司别名
    companyAlias
  • 姓氏后缀
    respectedTitle

三.项目部署

  • 当前每日任务部署于: 101.251.193.28:/home/mqian/orange_namecard_tagging
    由crontab每天凌晨4点执行,本系统的需要使用到名片基础信息,需要在名片拓展系统任务完成之后运行

    1
    2
    3
    ####为企业打别名、人名后加称呼等打标签
    0 4 * * * /usr/local/bin/python /home/mqian/orange_namecard_tagging/main.py >>
    home/mqian/aliaslog.log
  • git位置
    http://192.168.30.251:10086/git/mengqian/orange_namecard_tagging.git

名片信息拓展系统

发表于 2017-04-28 | 分类于 IMORA | 阅读次数:

名片信息拓展系统

一.业务整体流程

名片信息拓展系统主要包括两大任务:一.从json格式的数据源提取所需要字段,入dm库供数据挖掘等使用。二.在基础信息上进行拓展,以获得更丰富的数据。

现用到的json字段有:姓名,手机,公司名,公司电话,职位
拓展字段:手机→城市,公司名→行业,公司电话→城市,职位+行业→职能

1.数据来源:
可能涉及到如下数据表

  • 名片基本信息,json格式
    oradt_cloud_test2.contact_card
    oradt_cloud_test2.contact_card_extend
  • 手机、座机区号
    dm_test.province_city_unique_code
  • 行业职能对照表
    oradt_cloud_test2.account_basic_category

2.整体处理流程
本系统的处理流程如下图:

图片备份位置:/home/samba/share/mengqian/handover/名片信息拓展/step.png

  • 对应到代码,整体的入口为jobsAssigner,主要用来通过命令行参数实现运行每日任务,还是只计算给定区间的数据任务,将时间区间传给makeResultTables。
  • makeResultTables则查询不同数据源,拼合计算所需的数据格式,处理完毕后再拼合入库所需的数据格式,并执行入等库操作。
  • 其中makeResultTables会调用jsonPreprocess,jsonPreprocess主要任务为接受从makeResultTables所传递的时间区间,取出该区间中json数据的结果,拼合为后续信息拓展流程所需的数据格式。

二.功能模块说明

主要功能模块的包结构如下图:

图片备份位置:/home/samba/share/mengqian/handover/名片信息拓展/pakages.png

信息拓展的各个模块,结构类似,输入数据格式为pandas.Dataframe,通过prepare()方法转换格式后,传递给transform()方法进行计算。

三.项目部署

  • 当前每日任务部署于: 101.251.193.28:/home/mqian/3366
    由crontab每天凌晨3点执行(3388的暂时弃用)

    1
    2
    3
    #每天凌晨3点整执行,名片数据解析
    #0 3 * * * /usr/local/bin/python /home/mqian/3388/jobsAssigner.py -d 2>> /home/mqian/3388/log3388
    0 3 * * * /usr/local/bin/python /home/mqian/3366/jobsAssigner.py -d 2>> /home/mqian/3366/log3366
  • git位置
    http://192.168.30.251:10086/git/mengqian/namecard_info_extra_basic.git

月报会议模块

发表于 2017-03-02 | 分类于 IMORA | 阅读次数:

会议相关月报样板

您xx月共参加了xx ×x小时的会议,与xx个人进行过会晤,最近较为关注的公司有xx,xx,xx(公司名)
(数据取自日程,会晤人取日程参与人,关注公司取参与会议的人次较多的前三名公司;会议仅包括:橙子日程中从橙脉和手机日历获取的日程)

参加会议时间

oradt_cloud1520.contact_card_schedule 取会议开始结束时间;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
select user_id,SUM(meeting_time) as total_schedule_hour from(
select a.id as schedule_id,a.user_id,content,title,
FROM_UNIXTIME(start_time) as start_time,
FROM_UNIXTIME(end_time) as end_time,
(end_time - start_time)/(60*60*24) as day_diff,
case
-- 本月开始结束且一天之内结束
when (end_time - start_time)/(60*60*24) <= 1 and MONTH(FROM_UNIXTIME(start_time)) = 3 and MONTH(FROM_UNIXTIME(end_time))=3
then round((end_time - start_time)/(60*60))
-- 本月开始结束且一天之内没有结束
when (end_time - start_time)/(60*60*24) > 1 and MONTH(FROM_UNIXTIME(start_time)) = 3 and MONTH(FROM_UNIXTIME(end_time))=3
then round((end_time - start_time)/(60*60*24) * 8)
-- 结束时间不是本月,则取月初第一天为结束时间
when (end_time - start_time)/(60*60*24) > 1 and MONTH(FROM_UNIXTIME(start_time)) = 3 and MONTH(FROM_UNIXTIME(end_time))!=3
then round((UNIX_TIMESTAMP(last_day(curdate())) - start_time)/(60*60*24) * 8)
-- 开始时间不是本月,则取月初第一天为开始时间
when (end_time - start_time)/(60*60*24) > 1
and MONTH(FROM_UNIXTIME(start_time)) != 3 and MONTH(FROM_UNIXTIME(start_time)) != 3 and MONTH(FROM_UNIXTIME(end_time))=3
then round((end_time - UNIX_TIMESTAMP(DATE_ADD(curdate(),interval -day(curdate())+1 day)))/(60*60*24) * 8)
end as meeting_time
from oradt_cloud1520.contact_card_schedule a
right join oradt_cloud1520.contact_card_schedule_map b on a.id = b.schedule_id
left join(
select user_id,uuid
from oradt_cloud1520.contact_card
where self='true' and status = 'active'
) as c on c.user_id = a.user_id and c.uuid = b.uuid
WHERE a.start_time >0 and a.end_time > a.start_time
and b.status != 0 and b.uuid != '' and c.uuid is null and a.status = 1
and YEAR(FROM_UNIXTIME(start_time)) = 2017 and YEAR(FROM_UNIXTIME(end_time))=2017
and (MONTH(FROM_UNIXTIME(start_time)) = 3 or MONTH(FROM_UNIXTIME(end_time))=3)
order by user_id,schedule_id
)c GROUP BY user_id;

名片角色总会见人数

先统计每个人参加了几个会议(会议需要去重)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
select user_id, GROUP_CONCAT(DISTINCT(schedule_id)) as meeting_list from(
select a.user_id, a.id as schedule_id
from oradt_cloud1520.contact_card_schedule a
right join oradt_cloud1520.contact_card_schedule_map b on a.id = b.schedule_id
left join(
select user_id,uuid
from oradt_cloud1520.contact_card
where self='true' and status = 'active'
) as c on c.user_id = a.user_id and c.uuid = b.uuid
WHERE a.start_time >0 and a.end_time > a.start_time
and b.status != 0 and b.uuid != '' and c.uuid is null and a.status = 1
and YEAR(FROM_UNIXTIME(start_time)) = 2017 and YEAR(FROM_UNIXTIME(end_time))=2017
and (MONTH(FROM_UNIXTIME(start_time)) = 3 or MONTH(FROM_UNIXTIME(end_time))= 3)
order by schedule_id,user_id
) a GROUP BY user_id;

然后分别统计每个人的会议时长

1
2
select DISTINCT(count(uuid)) from oradt_cloud1520.contact_card_schedule_map where status != 0 and uuid != '' and
schedule_id in (3260,3890,3895,3915,4249,4252,4254,4255,4280,4822);

关注公司

oradt_cloud1520.contact_card_schedule_map 取uuid,即参与人;
与DM库中公司表关联得到参与人公司,统计公司前三位

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
select user_id, GROUP_CONCAT(companyName ORDER BY com_count desc,last_modified desc) as com_list from(
select user_id,companyName,count(*) as com_count,max(last_modified) as last_modified from(
select d.*,FROM_UNIXTIME(g.last_modified) as last_modified from(
select a.user_id,b.schedule_id,b.uuid,c.companyName
from oradt_cloud1520.contact_card_schedule a
right join oradt_cloud1520.contact_card_schedule_map b on a.id = b.schedule_id
left JOIN(select DISTINCT user_id,card_id,companyName from dm_test.company_info_jsonver) as c on b.uuid = c.card_id
left join(
select user_id,uuid
from oradt_cloud1520.contact_card
where self='true' and status = 'active'
) as f on f.user_id = a.user_id and f.uuid = b.uuid
WHERE a.start_time > 0 and a.end_time > a.start_time
and b.status != 0 and b.uuid != '' and f.uuid is null and a.status = 1
and YEAR(FROM_UNIXTIME(start_time)) = 2017 and YEAR(FROM_UNIXTIME(end_time))=2017
and (MONTH(FROM_UNIXTIME(start_time)) = 3 or MONTH(FROM_UNIXTIME(end_time))= 3)
and c.companyName !='' and c.companyName is NOT null
)d left join oradt_cloud1520.contact_card g on g.uuid = d.uuid) h
GROUP BY user_id,companyName ORDER BY com_count desc,last_modified desc
)e GROUP BY user_id;

相关表结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
CREATE TABLE `contact_card_schedule` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`user_id` char(40) CHARACTER SET utf8 NOT NULL DEFAULT '' COMMENT '创建人user_id',
`vcard_id` char(32) CHARACTER SET utf8 DEFAULT '' COMMENT '日程名片id',
`content` text NOT NULL COMMENT '日程内容',
`title` varchar(100) DEFAULT '' COMMENT '日程标题',
`address` varchar(300) DEFAULT '' COMMENT '地址',
`start_time` int(10) NOT NULL DEFAULT '0' COMMENT '日程开始时间',
`end_time` int(10) NOT NULL DEFAULT '0' COMMENT '日程结束时间',
`remind_time` int(10) NOT NULL DEFAULT '0' COMMENT '提醒时间',
`cycle` int(10) NOT NULL DEFAULT '0' COMMENT '提醒周期(例:15分钟为900单位为秒)',
`isallday` tinyint(1) NOT NULL DEFAULT '2' COMMENT '是否全天 :1是 2否 ',
`flag_time` int(10) NOT NULL DEFAULT '0' COMMENT '提醒计算字段(为时间戳)',
`last_modify` int(10) NOT NULL DEFAULT '0' COMMENT '最后修改时间',
`create_time` int(10) NOT NULL DEFAULT '0' COMMENT '创建时间',
`latitude` decimal(13,8) NOT NULL DEFAULT '0.00000000' COMMENT '坐标',
`longitude` decimal(13,8) NOT NULL DEFAULT '0.00000000' COMMENT '坐标',
`is_remind` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否提醒',
`status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '1为添加2为删除',
`flight_id` int(20) DEFAULT '0' COMMENT '行程卡id',
`schedule_from` tinyint(2) NOT NULL DEFAULT '1' COMMENT '日程来源:1.为橙脉2.为手机同步3.短信同步为4.为行程卡5.为还款同步6.航旅卡',
`schedule_info` text CHARACTER SET utf8 COMMENT '来源模块信息',
`orange_remind` int(10) NOT NULL DEFAULT '0' COMMENT '橙子专用提醒时间',
PRIMARY KEY (`id`),
KEY `user_id` (`user_id`),
KEY `v_cardid_idx` (`vcard_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=4771 DEFAULT CHARSET=utf8mb4

CREATE TABLE `contact_card_schedule_map` (
`id` int(20) unsigned NOT NULL AUTO_INCREMENT,
`uuid` char(32) NOT NULL DEFAULT '' COMMENT '邀请人cardid',
`schedule_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '日程id',
`last_modify` int(10) NOT NULL DEFAULT '0' COMMENT '最后更新时间',
`operation` enum('delete','modify','add') NOT NULL COMMENT '参与人状态',
`status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '0 不参与 1 未接受 2 已接受 3 完成',
PRIMARY KEY (`id`),
KEY `sch_id` (`schedule_id`) USING BTREE,
KEY `v_uuid_index` (`uuid`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=7093 DEFAULT CHARSET=utf8mb4

CREATE TABLE `orange_meeting_follow` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`user_id` varchar(42) NOT NULL COMMENT '用户id',
`meeting_hour` int(2) NOT NULL DEFAULT '0' COMMENT '会议小时数',
`meeting_people` int(2) NOT NULL DEFAULT '0' COMMENT '面谈人数',
`follow_comp` text COMMENT '关注公司列表',
`report_month` int(6) NOT NULL COMMENT '月报生成年月,存储格式例:201702',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8 COMMENT='用户会议相关及关注公司统计表'

月报各统计指标计算方法

发表于 2017-02-15 | 分类于 IMORA | 阅读次数:

月报各项目计算(初版)

一.消费记录

1.数据来源:月报表

CREATE TABLE `orange_monthly_report` (
  `id` int(10) NOT NULL AUTO_INCREMENT,
  `user_id` varchar(42) NOT NULL COMMENT '用户ID',
  `content` text NOT NULL COMMENT '月报内容',
  `created_time` int(10) NOT NULL COMMENT '月报创建时间',
  `modify_time` int(10) NOT NULL COMMENT '处理时间',
  `report_month` varchar(6) NOT NULL COMMENT '月报生成年月',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8 COMMENT='月报数据表';


CREATE TABLE `orange_consume_detail` (
  `id` int(10) NOT NULL AUTO_INCREMENT,
  `user_id` char(42) NOT NULL COMMENT '用户id',
  `card_id` char(32) NOT NULL COMMENT '卡片id',
  `bankcard_id` char(32) NOT NULL COMMENT '银行卡号',
  `bank_name` varchar(90) NOT NULL COMMENT '银行名',
  `bill_type` tinyint(1) NOT NULL COMMENT '消费类型:1、手机银行支付,2、支取,3、转账等',
  `bill` float(10,2) NOT NULL COMMENT '消费金额',
  `balance` float(10,2) NOT NULL COMMENT '余额',
  `created_time` int(10) NOT NULL COMMENT '创建时间',
  `modify_time` int(10) NOT NULL COMMENT '修改时间',
  `report_month` varchar(6) NOT NULL COMMENT '月报生成年月',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8 COMMENT='消费详情表';

2.消费记录详情SQL

得到指定月份的用户消费详情
提供各卡片当月消费金额

SELECT user_id, bankcard_id,bill_time,cons_type,bill FROM consume_details
WHERE  MONTH(bill_time) == "%s" AND user_id = "%s"
待定:短信去重

二.我在旅途

1.数据来源:里程卡,酒店卡

待定:
2.里程卡中可能无法得到飞行次数数据。
3.里程数可能无法涵盖所有公司。
4.酒店卡数据来源??

5.抵达城市算法,只用手机GPS位置

三.人脉动态

1.新增名片数,新增好友数
从数据库中获取新增名片数,新增好友数

新增好友数计算:contact_card(is_friend,from_uid,created_time)。从该表中按创建时间分组后取好友uid最早的记录,看是否落入统计区间。

2.被关注人数
来自谁看过我的消费结果
contact_card_see_me_source(未去重)
统计自然月的关注过用户的人数

3.参加会议时间

http://192.168.30.191/example/orange_schedule.txt
日程相关说明

oradt_cloud1520.contact_card_schedule 取会议开始结束时间;

4.关注公司

oradt_cloud1520.contact_card_schedule_map 取uuid,即参与人;    
与DM库中公司表关联得到参与人公司,统计公司前三位。如有参与人公司排名相同的情况,取名片更新时间最新的公司。

四.卡片统计

日志中获取卡片展示超过5秒的所有卡片,每找到一对展示开始时间超过5秒的记录,认为是一次使用,记入DM库

CREATE TABLE `card_used_log` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `user_id` char(40) DEFAULT '' COMMENT '用户id',
  `card_id` char(32) DEFAULT '' COMMENT '卡片id',
  `daily_used_count` int(10) DEFAULT '' COMMENT '卡片当日使用次数',
  `card_type` char(32) DEFAULT '' COMMENT '卡片类型',
  `used_time` datetime COMMENT '卡片使用时间',
  `batch_time` datetime DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='卡片使用次数表'

展示结果为按日别、卡别、用户统计使用次数
各类卡使用占比则先分组
常用卡列表来自于hive

附录

月报json存储格式

{
    "consume": {
        "totle": 58097.86,
        "bank": [
            {
                "bank_name": "招商银行",
                "card_num": 1234567898765,
                "amount": 300.23
            },
            {
                "bank_name": "招商银行",
                "card_num": 9876543212345,
                "amount": 451.8
            },
            {
                "bank_name": "工商银行",
                "card_num": 66436743634424,
                "amount": 670.83
            },
            {
                "bank_name": "建设银行",
                "card_num": 63762343254654,
                "amount": 1270.31
            }
        ]
    },
    "travel": {
        "flight": 28,
        "mileage": 10867,
        "stay": 15,
        "city": "北京、东京、纽约、斯德哥尔摩"
    },
    "connection": {
        "meeting_hour": 28,
        "meeting_people": 15,
        "new_friend": 98,
        "new_card": 887,
        "followed": 185,
        "follow_comp": "苹果、google、三星"
    },
    "card": {
        "category": [
            {
                "type": "行程卡",
                "freq": 90
            },
            {
                "type": "名片",
                "freq": 50
            },
            {
                "type": "酒店卡",
                "freq": 50
            },
            {
                "type": "系统卡",
                "freq": 10
            },
            {
                "type": "other",
                "freq": 100
            }
        ],
        "recent_use": "33829923329,53829923329,9829923380"
    }
}

** 此处的 other是取使用在4次以上,并不在前4位的卡片,非卡片类型的其它卡片

资讯推送|用户推广|活动管理

发表于 2017-02-14 | 分类于 IMORA | 阅读次数:

整体启动

main.py

通过多线程同时进行三个任务 (确保每个环境只有一个进程在运行)
nohup python main.py&

相关配置

配置写在文件 db.conf中
只需要根据运行环境更改数据库的配置名称即可,如:
oa = operationActivity.OperationActivity(“database_dev”) // 192
oa = operationActivity.OperationActivity(“database_prd”) // 125

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# !/Users/xieqj/py_env/venv python
# -*- coding: utf-8 -*-


import threading
from mg_handling import msgPushing, userPromotion, operationActivity
import util.comm as cm
import time

# 资讯推送
def msg_pushing():
while (True):
mp = msgPushing.MsgPushing()
msg_contents = mp.scanDBForSending()
mp.insert_msg2mq(msg_contents)
mp.mark_msg_as_sent(msg_contents)
mp.close_database()
time.sleep(8)

# 用户推广
def user_promotion():
while (True):
mp = userPromotion.UserPromotion()
msg_contents = mp.scanDBForSending()
mp.insert_msg2mq(msg_contents)
mp.mark_msg_as_sent(msg_contents)
mp.close_database()
time.sleep(8)

# 活动管理
def operation_activity():
while (True):
oa = operationActivity.OperationActivity()
msg_contents = oa.scanDBForSending()
oa.insert_msg2mq(msg_contents)
oa.mark_msg_as_sent(msg_contents)
oa.close_database()
time.sleep(8)


# 通过多线程同时启动两个步骤
if __name__ == "__main__":
cm.initLog("pushing.log", "INFO")
threads = []
t1 = threading.Thread(target=msg_pushing)
threads.append(t1)
t2 = threading.Thread(target=user_promotion)
threads.append(t2)
t3 = threading.Thread(target=operation_activity)
threads.append(t3)
for t in threads:
t.setDaemon(True)
t.start()
t.join()

资讯推送

读取表 sns_qa_push_setting 中的资讯,将其按照region,industry,func(职能)推送给对应群组的用户。
具体方法就是将表 sns_qa_push_setting 中的 content 1对1的推送给表 account_basic 中对应群组的用户,即插入 message_queue 表。

需要注意控制推送时间,和在推送后 update 表 sns_qa_push_setting 中 status 字段

仓库位置

git@192.168.30.251:message_handling.git

{“messagetype”: 230,”params”: { “data”: [{“newsid”: “ EwtNMSASOSvxjerhni98uQyEXnDIp9fS”,”title”: “发布到审核”,”url”: “资讯 URL”, “coverurl”: “https: //oradtdev.s3.cn-north- 1.amazonaws.com.cn/ukIv0BqxtnjRgjuhJcGKO6jze1liPmZE/gm9YtnBtvQ20160921132139.jpg”,”createdtime”: “1474435299” } ]}}

数据表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
CREATE TABLE `industry_category` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`category_id` char(8) NOT NULL,
`parent_id` char(8) NOT NULL,
`name` varchar(128) NOT NULL COMMENT '行业名称',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='国家统计局的两级行业分类标准'

# 保存从名片的json数据解析出来的数据 name * region
CREATE TABLE `card_info_jsonver` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`card_id` char(32) DEFAULT '' COMMENT '名片id',
`user_id` char(40) DEFAULT '' COMMENT '用户id',
`side` tinyint(4) DEFAULT '0' COMMENT '名片的正反面,0:正面,1:反面',
`name` varchar(128) DEFAULT '' COMMENT '名片上的名字',
`mobile` varchar(20) DEFAULT '' COMMENT '手机号',
`provinceM` varchar(64) DEFAULT '' COMMENT '手机号解出来的省份',
`provinceM_code` varchar(16) DEFAULT '' COMMENT '省份编码',
`cityM` varchar(64) DEFAULT '' COMMENT '城市',
`cityM_code` varchar(16) DEFAULT '' COMMENT '城市编码',
`created_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '名片创建时间',
`updated_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '名片更新时间',
`handle_state` varchar(16) DEFAULT '' COMMENT '处理状态',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=42333 DEFAULT CHARSET=utf8 COMMENT='保存从名片的json数据解析出来的数据'

# 从名片json数据解析出来的公司信息 companyName * func
CREATE TABLE `company_info_jsonVer` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`card_id` char(32) DEFAULT NULL COMMENT '名片id',
`user_id` char(40) DEFAULT NULL COMMENT '用户id',
`companyName` varchar(128) DEFAULT NULL COMMENT '公司名称',
`industry` varchar(128) DEFAULT NULL COMMENT '二级行业',
`ind_code` char(8) DEFAULT NULL COMMENT '二级行业编码',
`title` char(64) DEFAULT NULL COMMENT '职位',
`func_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '职能名称',
`func_code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '职能编号',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='从名片json数据解析出来的公司信息'


消息类型

{
"messagetype": 230,
"params": {
"data": [
{
"newsid": 资讯id,
"title": "资讯标题",
"url": "资讯URL",
"coverurl": "封面URL",
},
....
]
}
}
注:排序 按照data中数组的顺序

用户推广

基本流程与咨询推送相同

仓库位置

git@192.168.30.251:message_handling.git

git@192.168.30.251:effective.git

userPromotion.py

推广表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
CREATE TABLE `sys_user_promotion` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`pro_id` char(32) NOT NULL COMMENT '推广ID',
`type` tinyint(2) NOT NULL DEFAULT '0' COMMENT '推送方式:1:内部 2:邮件 3:短信',
`isalluser` tinyint(2) NOT NULL DEFAULT '1' COMMENT '1发送注册用户2发送全部用户',
`push_time` int(10) NOT NULL COMMENT '设置的推送时间',
`region` varchar(2000) NOT NULL DEFAULT '' COMMENT '地区(多个,号隔开)',
`industry` varchar(2000) NOT NULL DEFAULT '' COMMENT '行业(多个,号隔开)',
`func` varchar(2000) NOT NULL DEFAULT '' COMMENT '职能(多个,号隔开)',
`title` varchar(50) CHARACTER SET utf8mb4 DEFAULT '' COMMENT '标题',
`content` text NOT NULL COMMENT '推送的内容',
`created_time` int(10) NOT NULL COMMENT '添加时间',
`admin_id` char(40) NOT NULL DEFAULT '' COMMENT '设置人',
`status` tinyint(2) NOT NULL DEFAULT '1' COMMENT '状态 1:未发 2:已发',
`isntice` tinyint(2) DEFAULT '0' COMMENT '是否通知',
`url` varchar(256) NOT NULL COMMENT 'url地址',
`json_data` text NOT NULL COMMENT '推送json格式',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=58 DEFAULT CHARSET=utf8 COMMENT='运营后台-用户推广表'

-- 存储type为2,3的用户推广
CREATE TABLE `message_promotion` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`type` tinyint(4) NOT NULL DEFAULT '0' COMMENT '类型:1-内部,2-邮件,3-短信',
`mobile` varchar(18) DEFAULT '' COMMENT '手机号',
`email` varchar(256) DEFAULT '' COMMENT '邮箱',
`title` varchar(100) NOT NULL DEFAULT '' COMMENT '标题',
`content` text NOT NULL COMMENT '消息内容',
`created_time` int(11) DEFAULT NULL COMMENT '创建时间',
`modified_time` int(11) DEFAULT NULL COMMENT '修改时间',
`status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '状态:0-未发送,1-已发送,2-发送失败',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COMMENT='推广消息表'

推广消息类型

{
"messagetype":231,
"params":{
"id":"文章id",
"title": "资讯标题",
"content":"内容",
"createdtime": "1345764830"
}
}
{
"messagetype": 231,
"params": {
"content": "hello world!<br/>",
"createdtime": 1483620281,
"id": "zlJjJD6gDvjCdoMcibqCWOGrMo7vbB0b",
"image": "",
"title": "推送测试",
"type": "user",
"url": "h5/News/secretary?type=promotion&id=zlJjJD6gDvjCdoMcibqCWOGrMo7vbB0b"
}
}

活动管理

背景说明

系统中,内容管理-推送、运营管理-新增推广、运营管理-新增活动页面中,地区、行业、职能选择时,弹窗样式与“内容管理-推送”样式相同,具体请参见原型

进行推送时,匹配规则如下:
a) 行业:第一次使用APP时所选行业+当前默认身份的并集。采用1级行业-2级行业模式划分
b) 地区:第一次使用APP时所选手机号+当前默认身份的并集。采用1级地区-2级地区模式划分
c) 职能:当前默认身份。采用1级行业-职能(只有1级)模式划分

当前默认身份cardid需要通过表 account_basic_detail 的 card_id 字段得到

业务流程

仓库位置

git@192.168.30.251:message_handling.git

OperationActivity

活动表结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
CREATE TABLE `operation_activity` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`activity_id` char(32) CHARACTER SET utf8 NOT NULL COMMENT '活动id',
`type` tinyint(4) NOT NULL DEFAULT '1' COMMENT '类型 1:活动 2:资讯',
`isnotify` tinyint(4) NOT NULL DEFAULT '1' COMMENT '1:不通知 2:通知',
`push_state` tinyint(4) NOT NULL DEFAULT '1' COMMENT 'isnotify为2时有效,1:未推送,2:已推送',
`region` varchar(256) CHARACTER SET utf8 NOT NULL COMMENT '地区(多个,号隔开)',
`industry` varchar(256) CHARACTER SET utf8 NOT NULL COMMENT '行业(多个,号隔开)',
`func` varchar(256) CHARACTER SET utf8 NOT NULL COMMENT '职能(多个,号隔开)',
`show_id` varchar(400) CHARACTER SET utf8 DEFAULT NULL COMMENT '资讯shwo_id(多个,号隔开)type为2时有效',
`image` varchar(256) CHARACTER SET utf8 DEFAULT NULL COMMENT '标题图片',
`title` varchar(100) CHARACTER SET utf8 DEFAULT NULL COMMENT '活动标题 type为1时使用',
`content` text CHARACTER SET utf8 COMMENT '活动标题 type为1时使用',
`onlinetime` int(11) NOT NULL DEFAULT '0' COMMENT '上线时间',
`offlinetime` int(11) NOT NULL DEFAULT '0' COMMENT '下线时间',
`user_id` char(40) CHARACTER SET utf8 NOT NULL COMMENT '发布人用户id',
`created_time` int(11) NOT NULL DEFAULT '0' COMMENT '创建时间',
`modify_time` int(11) NOT NULL DEFAULT '0' COMMENT '修改时间',
`state` tinyint(4) NOT NULL DEFAULT '1' COMMENT '状态 1:未发布 2:已发布 3:已下线 4:已删除',
`click_count` int(11) NOT NULL DEFAULT '0' COMMENT '点击量',
`share_count` int(11) NOT NULL DEFAULT '0' COMMENT '分享量',
`share_user_count` int(11) NOT NULL DEFAULT '0' COMMENT '分享用户量',
`push_count` int(11) NOT NULL DEFAULT '0' COMMENT '推送用户量',
`url` varchar(256) NOT NULL COMMENT 'URL地址',
`json_data` text NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `activity_id` (`activity_id`)
) ENGINE=InnoDB AUTO_INCREMENT=94 DEFAULT CHARSET=utf8mb4 COMMENT='运营活动表'

推送类型
{
"messagetype":231,
"params":{
"id":"文章id",
"title": "标题",
"content":"内容",
"createdtime": "1345764830",
"image":"图片URL",
"type":"活动(activity)或者用户推广(user)"
}
}

带推送消息查询语句

资讯推送

select id,FROM_UNIXTIME(push_time) as push_time,status,region,industry,func,admin_id,content from oradt_cloud_test2.sns_qa_push_setting
where status <> 2 and industry != ‘’ and func != ‘’ and region != ‘’
and ROUND((UNIX_TIMESTAMP(SYSDATE()) - push_time)/60) >= -2;

用户推广

select id,FROM_UNIXTIME(push_time) as push_time,status,region,industry,func,admin_id,title,json_data from oradt_cloud_test2.sys_user_promotion
where status <> 2 and industry != ‘’ and func != ‘’ and region != ‘’
and ROUND((UNIX_TIMESTAMP(SYSDATE()) - push_time)/60) >= -2;

活动推广

select id,push_state, region, industry, func, title, json_data, user_id from oradt_cloud_test2.operation_activity
where push_state <> 2 and industry != ‘’ and func != ‘’ and region != ‘’ and ROUND((UNIX_TIMESTAMP(SYSDATE()) - push_time)/60) >= -2;


部署情况

125仿真环境

部署在IDC 云主机 /home/xieqj/python2.7_scenario/fangzhen

1
0 */1 * * * python2.7 /home/xieqj/python2.7_scenario/fangzhen/CardDeduplication/CardDeduplication3366.py

名片去重 60分钟运行一次
名片异常 5分钟运行一次
人脉更新 60分钟运行一次
消息推送 main.py 60分钟一次

python2.7 运行的是125 3366端口
python2.7 message_handling/main.py (消息推送)
python2.7 CardDeduplication/CardDeduplication.py
python2.7 CardExceptionHandling/CardException.py
python2.7 cardUpdateNotification/CardUpdateNote.py

python 运行的是3388端口
python CardDeduplication.py
python CardException.py

AWS

部署在ec2 54.223.28.119

1
0 0 */1 * * python2.7 /home/ec2-user/namecard/CardDeduplication/CardDeduplication_aws.py

名片异常 每5分钟运行一次
名片去重 每24小时运行一次
用户推广 每1分钟运行一次
消息推送 每1分钟运行一次

Hdfs的block块

发表于 2017-02-10 | 分类于 spark | 阅读次数:

Hdfs的block块

image

MapReduce shuffle过程

image

Spark RDD shuffle过程

image

Spark RDD

image

Spark 窄依赖 宽依赖

image

Hive优化以及数据倾斜问题

发表于 2017-02-10 | 分类于 Hive | 阅读次数:

Hive优化以及数据倾斜问题

HQL优化

1.调整Join顺序,确保以大表作为驱动表,即大表放在后面

2.去除查询中不需要的column

3.Where条件判断等在TableScan阶段就进行过滤

4.利用Partition信息,只读取符合条件的Partition

5.Map端join,以大表作驱动,小表载入所有mapper内存中

6.对于数据分布不均衡的表Group by时,为避免数据集中到少数的reducer上,分成两个map-reduce阶段。第一个阶段先用Distinct列进行shuffle,然后在reduce端部分聚合,减小数据规模,第二个map-reduce阶段再按group-by列聚合。

7.在map端用hash进行部分聚合,减小reduce端数据处理规模。

数据倾斜问题

数据倾斜
概念:数据倾斜是指,map /reduce程序执行时,reduce节点大部分执行完毕,但是

有一个或者几个reduce节点运行很慢,导致整个程序的处理时间很长,这是因为某一

个key的条数比其他key多很多(有时是百倍或者千倍之多),这条key所在的reduce

节点所处理的数据量比其他节点就大很多,从而导致某几个节点迟迟运行不完。

执行操作:

1.其中一个表较小,但是key集中,可能会导致分发到一个或几个Reduce上的数据远高于平均值
2.大表与大表关联,但是空值或者0比较多,这些控制都由一个reduce处理,非常慢。
3.group by维度过小,某值的数量过多。处理某值的Reduce非常耗时。
4.count distinct 某特殊值过多,处理此特殊值的Reduce耗时。

原因:

1.key分布不均
2.业务数据本身的特性
3.建表时考虑不周
4.某些语句本身就有数据倾斜

解决方案:

1.参数调节
hive.map.aggr=true
Map端部分聚合,相当于Combiner(合并器)。
hive.groupby.skewindata=true
有数据倾斜的时候进行负载均衡,当选项设定为 true,生成的查询计划会有两个 MR Job。

第一个 MR Job 中,Map 的输出结果集合会随机分布到 Reduce 中,每个 Reduce 做部分

聚合操作,并输出结果,这样处理的结果是相同的 Group By Key 有可能被分发到不同的 

Reduce 中,从而达到负载均衡的目的;第二个 MR Job 再根据预处理的数据结果按照 Group By Key 

分布到 Reduce 中(这个过程可以保证相同的 Group By Key 被分布到同一个 Reduce 中),最后完

成最终的聚合操作。

2.如何join?关于驱动表的选取,选用join key分布最均匀的表做为驱动表。做好列裁剪和filter操作,

以达到两表做join的时候数据量相对变小的效果。

3.使用mapjoin让小的维度表先进内存。在map端完成reduce。

4.大表join大表时,把空值的key变成一个字符串加上随机数,把倾斜的数据随机分布到不同的reduce上,

由于null值关联不上,处理后并不影响最终结果。

5.count distinct时,将值为空的情况单独处理,如果是计算count distinct,可以不用处理,直接过滤,

在最后结果中加1。如果还有其它计算,需要进行group by,可以先将值为空的记录单独处理,再和其他

结果进行union。

6.采用sum() group by的方式来替换count(distinct )进行计算。

7.在业务逻辑优化效果不大的情况下,有些时候是可以将倾斜的数据单独拿出来处理,最后union回去。

8.对于控制产生的倾斜问题,解决方案1:为空的数据不参与关联;方案2:随机(rand())赋予空值新的key。

把空值的key变成一个字符串加上随机数,就能把倾斜的数据分到不同的reduce上,解决数据的倾斜问题。

9.不同数据类型关联产生数据倾斜,默认的Hash操作会按int型的id来分配reduce,这样会导致所有的String

类型数据分配到同一个reduce。

10.使用 mapjoin 解决小表(记录数少)关联大表的数据倾斜问题,这个方法使用的频率非常高,但如果小表

 很大,大到map join会出现bug或异常,这时就需要特别的处理。
123

Frone Xie

29 日志
10 分类
45 标签
GitHub CSDN
© 2019 Frone Xie
由 Hexo 强力驱动
|
主题 — NexT.Pisces v5.1.4
本站访客数 人数 本站总访问量 次