关于数据:虎扑论坛数据分析

原文链接:http://tecdat.cn/?p=2018 论坛为用户提供了雷同的业余爱好,互动和交换的广大平台,以及由此产生的宏大数据和简单的用户交互场景也蕴含有价值的信息,本文对于虎扑论坛的帖子,个人信息剖析,探讨虎扑论坛的用户是什么是什么特点? ▼ tecdat钻研人员剖析了2018年1月Tiger Walk论坛每个局部的所有帖子,应用数据摸索用户行为并概述用户偏好。 以下是虎扑的官网介绍摘录:虎扑是一个业余的年老女子网站,涵盖了原有的新闻专栏视频报道,包含篮球,足球,F1,NFL等大型生存/视频/游戏/ car / digital在线交换社区,议论体育谈话对虎扑的趣味。 数据显示 数据源: 2018年1月虎屁论坛步行街所有分段的所有帖子,删除低度关注的帖子,总数为3.3W +; 以上3.3W +帖子在骨干局部回复用户的个人信息,用户总重量为2.3W +。 社交和交易属性是流动的要害 在虎扑社区由10个分论坛,380个分论坛组成,发帖量达到70W +,哪个最沉闷呢? 通过比拟每个局部的帖子数量,您能够看到在大型子论坛中,[设施论坛]的帖子数量最多,其次是Pedestrian Street和[NBA]; 在380个大节中,[Main Street Pedestrian]和[IT Digital]最受欢迎,其次是[Cheyou exchange]和[burst]; 其中,[行人]岗位占近7成,远高于其余。 能够看出,交易属性和社交属性是维持社区激情和用户流动的要害。 除了体育,约会八卦也是最受关注的话题 除了交易局部,[Pedestrian]和[NBA]是虎扑最沉闷的局部,[NBA论坛]主题个别围绕较量开始,而[行人]社会属性绝对较强,通过[Pedestrian]剖析,看看老虎扑动的其余成员在体育赛事中关注的是什么。 通过文字云剖析所有步行街的帖子内容,删除下面提到的高频词50,能够失去以下词云图。从单词云图中能够看出,步行街区的探讨内容常常被提及情感关键词,如“女朋友”,“敌人”和“喜爱”,能够推断成员Tiger Puff社区次要是年轻人; 富裕,体育,篮球也常常被提及关键词,可见胡鹏体育运动成员更强; 同时,咱们还能够看到词云还包含李小璐,特步等关键词,咱们能够看到热门八卦而且晓得热门话题的话题也十分关注; 此外,“大学”,“室友”,“毕业”等也常常被提及,表明虎扑社区沉闷在一群大学生中。 综上所述,咱们能够初步猜想,虎扑成员以青年女子和大学生为主,他们喜爱篮球等体育,交友是他们最关怀的话题,他们也喜爱探讨一些八卦热点和理解微博等热门话题。 用户剖析 用户性别 除了不愿走漏性别用户外,步行街的残余沉闷用户中,女性仅占4.5%,这与虎扑社区的物理属性基本相同。 用户的地位 从上面的地理分布能够看出,步行街的沉闷用户次要散布在经济发达的省市,如广东,江苏,北京,浙江和上海,上述五个地区占50%以上。总; 用户日勾留工夫 通过计算用户注册天数和在线持续时间,能够发现尽管45.5%的用户每天应用不到半小时,但超过30%的用户破费超过一小时超过一小时,表明由洗发水社区提供的内容更具吸引力。 总结一下 总的来说,虎扑成员以青年女子和大学生为主,他们喜爱篮球等静止,关注NBA,英超等联赛; 然而行人社区,他们的话题不仅限于体育,八卦,情感征询,他们关注的内容也是如此; 而且他们在虎扑中停留的工夫更长,虎扑的内容能够很好地把握以后的用户群体。

July 19, 2020 · 1 min · jiezi

python-dict形式的全国省市对照表

自己整顿一份省市的对应关系表。是python的dict模式的,大家在爬局部数据源的时候可能会用到。其中局部可能有误,比方海南省的局部城市、河北省的局部直辖地级市,大家依照须要简略批改即可。city_list = { "北京": ["北京"], "天津": ["天津"], "山西": ["太原", "阳泉", "晋城", "长治", "临汾", "运城", "忻州", "吕梁", "晋中", "大同", "朔州"], "河北": ["沧州", "石家庄", "唐山", "保定", "廊坊", "衡水", "邯郸", "邢台", "张家口", "辛集", "秦皇岛", "定州", "承德", "涿州"], "山东": ["济南", "淄博", "聊城", "德州", "滨州", "济宁", "菏泽", "枣庄", "烟台", "威海", "泰安", "青岛", "临沂", "莱芜", "东营", "潍坊", "日照"], "河南": ["郑州", "新乡", "鹤壁", "安阳", "焦作", "濮阳", "开封", "驻马店", "商丘", "三门峡", "南阳", "洛阳", "周口", "许昌", "信阳", "漯河", "平顶山", "济源"], "广东": ["珠海", "中山", "肇庆", "深圳", "清远", "揭阳", "江门", "惠州", "河源", "广州", "佛山", "东莞", "潮州", "汕尾", "梅州", "阳江", "云浮", "韶关", "湛江", "汕头", "茂名"], "浙江": ["舟山", "温州", "台州", "绍兴", "衢州", "宁波", "丽水", "金华", "嘉兴", "湖州", "杭州"], "宁夏": ["中卫", "银川", "吴忠", "石嘴山", "固原"], "江苏": ["镇江", "扬州", "盐城", "徐州", "宿迁", "无锡", "苏州", "南通", "南京", "连云港", "淮安", "常州", "泰州"], "湖南": ["长沙", "邵阳", "怀化", "株洲", "张家界", "永州", "益阳", "湘西", "娄底", "衡阳", "郴州", "岳阳", "常德", "湘潭"], "吉林": ["长春", "长春", "通化", "松原", "四平", "辽源", "吉林", "延边", "白山", "白城"], "福建": ["漳州", "厦门", "福州", "三明", "莆田", "宁德", "南平", "龙岩", "泉州"], "甘肃": ["张掖", "陇南", "兰州", "嘉峪关", "白银", "武威", "天水", "庆阳", "平凉", "临夏", "酒泉", "金昌", "甘南", "定西"], "陕西": ["榆林", "西安", "延安", "咸阳", "渭南", "铜川", "商洛", "汉中", "宝鸡", "健康"], "辽宁": ["营口", "铁岭", "沈阳", "盘锦", "辽阳", "锦州", "葫芦岛", "阜新", "抚顺", "丹东", "大连", "向阳", "本溪", "鞍山"], "江西": ["鹰潭", "宜春", "上饶", "萍乡", "南昌", "景德镇", "吉安", "抚州", "新余", "九江", "赣州"], "黑龙江": ["伊春", "七台河", "牡丹江", "鸡西", "黑河", "鹤岗", "哈尔滨", "大兴安岭", "绥化", "双鸭山", "齐齐哈尔", "佳木斯", "大庆"], "安徽": ["宣城", "铜陵", "六安", "黄山", "淮南", "合肥", "阜阳", "亳州", "安庆", "池州", "宿州", "芜湖", "马鞍山", "淮北", "滁州", "蚌埠"], "湖北": ["孝感", "武汉", "十堰", "荆门", "黄冈", "襄阳", "咸宁", "随州", "黄石", "恩施", "鄂州", "荆州", "宜昌", "潜江", "天门", "神农架", "仙桃"], "青海": ["西宁", "海西", "海东", "玉树", "黄南", "海南", "海北", "果洛"], "新疆": ["乌鲁木齐", "克州", "阿勒泰", "五家渠", "石河子", "伊犁", "吐鲁番", "塔城", "克拉玛依", "喀什", "和田", "哈密", "昌吉", "博尔塔拉", "阿克苏", "巴音郭楞", "阿拉尔", "图木舒克", "铁门关"], "贵州": ["铜仁", "黔东南", "贵阳", "安顺", "遵义", "黔西南", "黔南", "六盘水", "毕节"], "四川": ["遂宁", "攀枝花", "眉山", "凉山", "成都", "巴中", "广安", "自贡", "甘孜", "资阳", "宜宾", "雅安", "内江", "南充", "绵阳", "泸州", "凉山", "乐山", "广元", "甘孜", "德阳", "达州", "阿坝"], "上海": ["上海"], "广西": ["南宁", "贵港", "玉林", "梧州", "钦州", "柳州", "来宾", "贺州", "河池", "桂林", "防城港", "崇左", "北海", "百色"], "西藏": ["拉萨", "山南", "日喀则", "那曲", "林芝", "昌都", "阿里"], "云南": ["昆明", "红河", "大理", "玉溪", "昭通", "西双版纳", "文山", "曲靖", "普洱", "怒江", "临沧", "丽江", "红河", "迪庆", "德宏", "大理", "楚雄", "保山"], "内蒙古": ["呼和浩特", "乌兰察布", "兴安", "赤峰", "呼伦贝尔", "锡林郭勒", "乌海", "通辽", "巴彦淖尔", "阿拉善", "鄂尔多斯", "包头"], "海南": ["海口", "三沙", "三亚", "临高", "五指山", "陵水", "文昌", "万宁", "白沙", "乐东", "澄迈", "屯昌", "定安", "西方", "保亭", "琼中", "琼海", "儋州", "昌江"], "重庆": ["重庆"]}

July 10, 2020 · 2 min · jiezi

API进阶之路6一个技术盲点差点让整个项目翻车

上次教了实习生一个方案之后,这小子跟运营妹子的关系是越走越近,时不时地撒把狗粮,在我司真正实现了研发运营一家亲~(上回你没看?戳上文剧情回顾:万万没想到,一个技术方案帮实习生追到了运营妹子) 这回想跟大家聊的,是最近一个可以说有些惊心动魄的项目。自从我开始在华为云网站自学API的技术解决方案之后,我就变成了公司的云服务器技术专家,老板或运维部门想要查询个数据什么的都来找我。 近期有一个运营项目的系统正在开发中,运营方规划了一个数据BI模板,列出了需要监测和分析的数据维度,老板干脆让我每周出一份数据报表来支持各方的数据获取和数据分析。 让研发出数据报表?这不是逼着李逵绣花么?但是,我能轻易拒绝吗?前几回高光时刻带来的成就感和光环还没褪去呢,不能怂!于是我提了一个方案:可以把云服务器的监控仪表内嵌到我们自己的系统里,这样大家可以随时查询,也方便。 老板听了这个方案表示很开心,并同意加入到项目排期中,数据查询功能与系统同期上线,以便及时跟踪运营结果。在老板的笑容里,我看到季度奖金在向我招手。 说干就干,执行力咱还是有的。用1天的时间就把程序写完了,在测试的时候发现了一个问题,数据过不来!因为通过内嵌系统登陆云服务器需要经过各种认证,步骤多不说,如果要想实现人人可查询还存在泄密的危险。 这可怎么办,系统上线的日期临近,不能因为我这部分影响到项目进展啊!当初拍着胸脯提(chui)的方(niu)案(13),难道就要失败了? 不行,再查查!我专门联系了华为云的技术专家,得知可以通过IAM自定义代理免密登录到云服务Console页面,省去认证环节,直接登陆云服务器进行数据查询和获取。 那怎么做免密登录呢?他给了我一份文档,内容是这样的: 一、前提条件步骤 1:创建账号I**mainA下的IAM用户userB,并授予Security Administrator和Agent Operator权限(全局服务-全局项目)。 将userB的用户名和密码配置到企业系统的配置文件中,密码建议加密存储,以便获取认证token并进一步调用IAM其他Open API。 备注:有关创建IAM用户和授权相关操作请参见:创建IAM用户(https://support.huaweicloud.com/usermanual-iam/zh-cn_topic_0046611303.html) 和 创建用户组并授权 (https://support.huaweicloud.com/usermanual-iam/zh-cn_topic_0046611269.html) 步骤2:创建联邦代理所需委托IAMAgency。 委托类型选择“普通账号”,委托的账号填写“DomainA”。 备注:有关创建委托相关操作请参见:创建委托(委托方操作)(https://support.huaweicloud.com/usermanual-iam/zh-cn_topic_0046613147.html) 二、华为云联邦代理登录步骤1:调用IAM API获取STS token 1)使用IAM全局域名(iam.myhuaweicloud.com)调用IAM服务的API(POST /v3.0/OS-CREDENTIAL/securitytokens)获取STS token。 填写"session_user"参数,发起一个POST请求。 POST https://iam.myhuaweicloud.com/v3.0/OS-CREDENTIAL/securitytokens 请求示例 { "auth": { "identity": { "assume_role": { "agency_name": "IAMAgency", "domain_name": "I**mainA", "duration-seconds": 3600, "session_user": { "name": "SessionUserName" } }, "methods": [ "assume_role" ] } }} 2)获取并记录请求响应体中的STS token信息:credential.access , credential.secret, credential.securitytoken 响应示例 <br style=""> { "credential": { "access": "E6DX0TF2ZREQ4ZAVM5CS", "expires_at": "2020-01-08T02:56:19.587000Z", "secret": "w9ePum0qdfac39ErLD0UdjofYkqort6Iw2bmR6Si", "securitytoken": "gQpjbi1ub3J0aC0..." }} 步骤2:调用IAM API获取logintoken ...

July 6, 2020 · 1 min · jiezi

利用JavaScript自定义事件完成组件间的数据通信

我们知道,在JavaScript中,原生DOM事件在开发中是很有用的(与用户交互的重要方式),但是操作原生DOM事件其实有两大缺点:性能低、依赖于浏览器(NodeJs、小程序等不可用)。那么这个时候,就需要我们进行自定义事件去处理某些特定的业务。认识Event对象及元素的dispatchEvent方法在JavaScript中,所有事件的父对象就是Event对象,也就是说像我们平时所有的点击(click)、触摸(touch)、鼠标等事件对象都继承自Event。理解这一点是很重要的。先来简单看一个事件的场景。 场景一、页面上有两个按钮a、b,当点击按钮b的时候,调用按钮a的点击事件。简单布局代码如下: <button id="btn1">a</button><button id="btn2">b</button>程序员A的做法,分别获取这两个按钮,然后给b按钮添加点击事件后,调用按钮a的click方法。代码如下: <button id="btn1" onclick="alert('I am a button named a')">a</button><button id="btn2">b</button><script> let btn1 = document.querySelector('#btn1'); let btn2 = document.querySelector('#btn2'); btn2.onclick = function(){ btn1.onclick(); }</script>程序员B的做法,分别获取这两个按钮,然后给b按钮添加点击事件后,在回调函数中在添加按钮a的点击事件。代码如下: <button id="btn1">a</button><button id="btn2">b</button><script> let btn1 = document.querySelector('#btn1'); let btn2 = document.querySelector('#btn2'); btn2.onclick = function(){ btn1.addEventListener('click',function(){ alert('I am a button named a') },false) }</script>看到这里,你认为谁的做法是正确的?显然程序员A的做法是对的(就目前的要求来看),但有缺陷,如果按钮a的事件是通过addEventListener方法去注册监听的,就不起作用了。那么该怎样做才会比较好?这就需要我们的Event对象和元素的dispatchEvent方法了。改进代码如下: <button id="btn1">a</button><button id="btn2">b</button><script> let btn1 = document.querySelector('#btn1'); let btn2 = document.querySelector('#btn2'); btn1.addEventListener('click',function(){ alert('I am a button named a') },false) btn2.onclick = function(){ let ev = new Event('click'); btn1.dispatchEvent(ev); }</script>其中: ...

October 2, 2019 · 2 min · jiezi

如何运营一家数据标注公司数据处理分类篇

“人工智能之所以称呼他为人工智能,是因为它的核心:也就是神经网络模型。它就是根据模拟人脑的神经网络而诞生的。而图像、语音这一类信息通过特征标注处理(也就是数据标注),变成计算机能够识别的信息。同时通过大量特征数据的训练,最终达到计算机能够自主识别的目的。那么目前AI市场上特征数据主要包括哪些呢......”      我们是靠眼睛、耳朵来捕获外界信息,然后将信息通过神经元传递给我们的大脑,最后我们的大脑会对获取来的各种信息进行分析从而达到诸如判断、识别等效果。      同样,人工智能之所以称呼他为人工智能,是因为它的核心:也就是神经网络模型。它就是根据模拟人脑的神经网络而诞生的。而图像、语音这一类信息通过特征标注处理(也就是数据标注),变成计算机能够识别的信息。同时通过大量特征数据的训练,最终达到计算机能够自主识别的目的。 那么目前AI市场上特征数据主要包括哪些呢?      像人类用眼睛和耳朵获取图像、语音数据一样,计算机的特征数据现阶段也分为两大类:图像数据和语音数据。 同时,根据AI产品迭代的不同周期、算法模型的匹配结果,每个大类又可以细分为众多小类,在这里我们主要对目前市场上主流的需求类型进行一个分类说明。 1. 图像类   这里图像类就是指所有照片的统称 图像场景识别作为人工智能不可获取的一部分已经在日常生活中被大批量应用,这里对图像特征的具体处理手法做一个简单介绍: 四边形矩形拉框   这个也就是数据标注市场上统称的2D拉框,它主要是用特定软件对图像中需要处理的元素(比如:人、车、动物等等),进行一个拉框处理,同时用一个或多个独立的标签来代表一个或多个不同的需要处理元素,同时在标签的添加上可能会碰到多层次的添加(以人为标注元素为例,长短发、胖瘦、穿衣颜色等)从而实现粗线条的种类识别。多边形拉框   顾名思义就是将被标注元素的轮廓以多边型的方式勾勒出来,不同的被标注元素有不同的轮廓,除了同样需要添加单级或多级标签以外,多边型还有可能会涉及到物体遮挡的逻辑关系。从而实现细线条的种类识别。LandMark   标注行业统称打点,对需要标注的元素(比如人脸、肢体)按照需求位置进行点位标注。从而实现特定部位关键点的识别。语义分割   通过对需要标注区域或元素的充色,来达到不同元素或区域之间的分割关系,从而可以清晰的通过不同颜色的区域,对元素进行区分。从而实现系统化的识别。点云拉框   在软件生成的三维模型中,对被标注元素进行外轮廓的3D立体拉框,与2d拉框相同,也需要对生成立体框添加特定标签。从而实现具有空间感的识别。VR打标   使用VR设备,在虚拟立体场景中,对需要标注的元素(各类物体)进行关键区域的打标签。从而实现更精准的被遮挡物品外观轮廓的感知。2. 语音类   这里语音类就是指所有语音的统称语音场景在人工智能领域作为和图片场景同样重要的环节,也同样被大批量的进行应用,这里对语音特征的处理手法大致介绍一下:      目前市场上主流的语音场景都是以区间为单元对区间内的内容进行转述,区间里的元素就是被标注元素。像图片场景里给被标注元素一个特定的标签一样,对区间里的被标注元素也需要提供一个特定的标签,当然这个标签可以是一个词语,也可以是具体的一句话。从而实现对于不同语句类别的判断和对不同语句内容的理解。      当然,各种处理手法在实际的数据标注中都会碰到各种各样的问题。有简单的,也有较为复杂的。这些问题无一例外的都会影响到我们标注员、审核员在工作中的效率,那么如何在实际操作中有效的提高标注效率呢?请持续关注我们的官网www.awkvector.com及blog更新,我们会在接下来更新的文章中,给大家详细解惑。 ©著作权归作者所有:来自作者觉醒向量数据标注的原创作品,如需转载,请注明出处,否则将追究法律责任

August 20, 2019 · 1 min · jiezi

共享学习蚂蚁金服数据孤岛解决方案

如果有A、B、C三位同学,他们各自手上有10、15、20块钱,这时需要在相互不知道对方有多少钱的情况下,不借助力第三方来计算三个人一共有多少钱。请问这时候,我们如何实现呢?——这,就是最经典的秘密共享场景。在看完这篇文章后,答案就出来了~背景互联网时代,一切基于数据。 随着人工智能的兴起,数据的质量和数量,已经成为影响机器学习模型效果最重要的因素之一,因此通过数据共享的模式来“扩展”数据量、从而提升模型效果的诉求也变得越发强烈。 但在数据共享过程中,不可避免会涉及到两个问题:隐私泄露和数据滥用。 提到这两个关键词,大家一定都对其背后的缘由有所耳闻: 第一则:2018年3月,剑桥咨询公司通过FaceBook的数据共享漏洞,收集了5000万用户信息,据说有可能利用这些信息操控美国总统竞选,造成恶劣社会影响;事件曝光后,FB公司股票大跌7%,引发一系列后续问题。第二则:2018年5月,欧盟通过General Data Protection Regulation(GDPR)法案,法案指出:所有与个人相关的信息都是个人数据,对数据的使用行为必须要有用户的明确授权。把对隐私保护的要求提到了一个新的高度。 随着对数据安全的重视和隐私保护法案的出台,以前粗放式的数据共享受到挑战,各个数据拥有者重新回到数据孤岛的状态,同时,互联网公司也更难以收集和利用用户的隐私数据。 数据孤岛现象不仅不会消失,反而会成为新的常态,甚至它不仅存在于不同公司和组织之间,在大型集团内部也存在。未来,我们必须面对这样的现状:如果我们想更好的利用数据,用大数据和AI做更多有意义的事情,就必须在不同组织之间、公司与用户之间进行数据共享,但这个共享需要满足隐私保护和数据安全的前提。 隐私泄漏和数据滥用如同达摩克利斯之剑悬在各个公司和组织头上,因此解决数据孤岛,成为AI行业需要解决的首要问题之一。 如何解决数据孤岛问题?当前,业界解决隐私泄露和数据滥用的数据共享技术路线主要有两条。一条是基于硬件可信执行环境(TEE: Trusted Execution Environment)技术的可信计算,另一条是基于密码学的多方安全计算(MPC:Multi-party Computation)。 TEE字面意思是可信执行环境,核心概念为以第三方硬件为载体,数据在由硬件创建的可信执行环境中进行共享。这方面以Intel的SGX技术,AMD的SEV技术,ARM的Trust Zone技术等为代表。TEE方案的大致原理如下图所示: 目前在生产环境可用的TEE技术,比较成熟的基本只有Intel的SGX技术,基于SGX技术的各种应用也是目前业界的热门方向,微软、谷歌等公司在这个方向上都有所投入。 SGX(Software Guard Extensions )是Intel提供的一套软件保护方案。SGX通过提供一系列CPU指令码,允许用户代码创建具有高访问权限的私有内存区域(Enclave - 飞地),包括OS,VMM,BIOS,SMM均无法私自访问Enclave,Enclave中的数据只有在CPU计算时,通过CPU上的硬件进行解密。同时,Intel还提供了一套远程认证机制(Remote Attestation),通过这套机制,用户可以在远程确认跑在Enclave中的代码是否符合预期。 MPC(Multi-party Computation,多方安全计算)一直是学术界比较火的话题,但在工业界的存在感较弱,之前都是一些创业小公司在这个方向上有一些探索,例如Sharemind,Privitar,直到谷歌提出了基于MPC的在个人终端设备的“联邦学习” (Federated Learning)的概念,使得MPC技术一夜之间在工业界火了起来。MPC方案的大致原理如下图所示: 目前,在MPC领域,主要用到的是技术是混淆电路(Garbled Circuit)、秘密分享(Secret Sharing)和同态加密(Homomorphic Encryption)。 混淆电路是图灵奖得主姚期智教授在80年代提出的一个方法。其原理是,任意函数最后在计算机语言内部都是由加法器、乘法器、移位器、选择器等电路表示,而这些电路最后都可以仅由AND和XOR两种逻辑门组成。一个门电路其实就是一个真值表,假设我们把门电路的输入输出都使用不同的密钥加密,设计一个加密后的真值表,这个门从控制流的角度来看还是一样的,但是输入输出信息都获得了保护。 秘密分享的基本原理是将每个数字随机拆散成多个数并分发到多个参与方那里。然后每个参与方拿到的都是原始数据的一部分,一个或少数几个参与方无法还原出原始数据,只有大家把各自的数据凑在一起时才能还原真实数据。 同态加密是一种特殊的加密方法,允许对密文进行处理得到仍然是加密的结果,即对密文直接进行处理,跟对明文进行处理后再对处理结果加密,得到的结果相同。同态性来自抽象代数领域的概念,同态加密则是它的一个应用。 当前,业界针对数据共享场景,利用上面的技术路线推出了一些解决方案,包括隐私保护机器学习PPML、联邦学习、竞合学习、可信机器学习等,但这些方案只利用了其中的一部分技术,从而只适合部分场景,同时基本处于学术研究阶段,没有在生产环境落地。 共享机器学习:蚂蚁金服数据孤岛解决方案为了更好的应对形势变化,解决数据共享需求与隐私泄露和数据滥用之间的矛盾,蚂蚁金服提出了希望通过技术手段,确保多方在使用数据共享学习的同时,能做到:用户隐私不会被泄露,数据使用行为可控,我们称之为共享机器学习(Shared Machine Learning)。 共享机器学习的定义:在多方参与且各数据提供方与平台方互不信任的场景下,能够聚合多方信息并保护参与方数据隐私的学习范式。 从17年开始,蚂蚁金服就一直在共享机器学习方向进行探索和研究,在结合了TEE与MPC两条路线的同时,结合蚂蚁的自身业务场景特性,聚焦于在金融行业的应用。 蚂蚁金服共享机器学习方案拥有如下特性: • 多种安全计算引擎整合,可基于不同业务场景来选择合适的安全技术。既有基于TEE的集中式解决方案,也有基于MPC的分布式解决方案;既可满足数据水平切分的场景,也能解决数据垂直切分的诉求;既可以做模型训练,也可以做模型预测。• 支持多种机器学习算法以及各种数据预处理算子。支持的算法包括但不限于LR,GBDT,Xgboost,DNN,CNN,RNN,GNN等。• 大规模集群化。支持大规模集群化,提供金融级的高效、稳定、系统化的支撑。 基于数年沉淀与积累,目前共享机器学习技术已在银行、保险、商户等行业成功落地诸多场景业务。通过在业务中打磨出的金融级共享机器学习能力,沉淀下来一套数据共享场景的通用解决方案,未来会逐步对外开放。 在几年的艰苦研发中,共享学习累积专利50余项。在2019中国人工智能峰会上,共享机器学习获得“紫金产品创新奖”,在8月16日的全球人工智能创业者大会上,获得“应用案例示范奖”。 下面,我们将分享基于上面两种路线的共享机器学习实践细节。 基于TEE的共享学习蚂蚁共享学习底层使用Intel的SGX技术,并可兼容其它TEE实现。目前,基于SGX的共享学习已支持集群化的模型在线预测和离线训练。 1.模型在线预测 预测通常是在线服务。相对于离线训练,在线预测在算法复杂度上面会相对简单,但是对稳定性的要求会更高。提升在线服务稳定性的关健技术之一就是集群化的实现——通过集群化解决负载均衡,故障转移,动态扩容等稳定性问题。 但由于SGX技术本身的特殊性,传统的集群化方案在SGX上无法工作。 为此,我们设计了如下分布式在线服务基本框架: 该框架与传统分布式框架不同的地方在于,每个服务启动时会到集群管理中心(ClusterManager,简称CM)进行注册,并维持心跳,CM发现有多个代码相同的Enclave进行了注册后,会通知这些Enclave进行密钥同步,Enclave收到通知后,会通过远程认证相互确认身份。当确认彼此的Enclave签名完全相同时,会通过安全通道协商并同步密钥。 该框架具备如下特性: • 通过集群化方案解决了在线服务的负载均衡,故障转移,动态扩缩容,机房灾备等问题;• 通过多集群管理和SDK心跳机制,解决代码升级,灰度发布,发布回滚等问题;• 通过ServiceProvider内置技术配合SDK,降低了用户的接入成本;• 通过提供易用性的开发框架,使得用户在开发业务逻辑时,完全不需要关心分布式化的逻辑;• 通过提供Provision代理机制,确保SGX机器不需要连接外网,提升了系统安全性。 ...

August 19, 2019 · 1 min · jiezi

Oracle-GoldenGateogg安装经验大汇总采坑总结绝对干货

一下是安装ogg过程中遇到的问题和解决办法,绝对良心干货,抽空会写更详细的安装教程。更多精彩内容请点击 OGG-00685 begin time prior to oldest log in log historyhttps://blog.csdn.net/kiwi_ki... goldengate 故障及解决方法汇总https://blog.csdn.net/amethys... oracle 手册https://docs.oracle.com/golde...https://docs.oracle.com/golde... (EXT.prm) line 13: Parsing error, [convertucs2clobs] is obsolete.expdp/impdp中parfile参数使用http://blog.itpub.net/2683912... window 注意 导入导出导入expdp parfile=D:appqingmiaokejiadminorcladumpexpdp_zzbs.par PARALLEL=8 flashback_scn=1438905 登录用户必须是dba F:appqingmiaokejiadminorcldpdump 导出 impdp qingmiaokeji/qingmiaokeji REMAP_SCHEMA=qingmiaokeji:qingmiaokeji REMAP_TABLESPACE=qingmiaokeji:qingmiaokeji_data dumpfile= expdp_zzbs_%U.dmp virtual box centos7 配置 上网https://blog.csdn.net/rcjjian...https://blog.csdn.net/teisite... centos7 安装oraclehttps://www.cnblogs.com/liugu... 修改字符集https://www.cnblogs.com/gaoyu... 错误整理: ORA-12705: Cannot access NLS data files or invalid environment specifiedhttps://blog.csdn.net/wolfcho... 在Windows系统设置goldengate服务随系统启动https://blog.csdn.net/qq_4292...GoldenGate 配置extract,replicat进程自启动https://www.cnblogs.com/xqzt/... 删除10天前的trail文件Windows平台使用RMAN命令自动删除Oracle过期归档日志的方法https://blog.csdn.net/xiaolon... Windows计划任务设置,定时执行指定脚本https://jingyan.baidu.com/art... ogg trail文件版本问题,重置https://community.oracle.com/...https://www.2cto.com/database...https://blog.csdn.net/orion61...ALTER EXTRACT EPMP ETROLLOVER ...

July 1, 2019 · 1 min · jiezi

中国高考志愿填报与职业趋势分析-ActiveReports-大数据分析报告

1977年中国高考制度恢复,重新开启了人才成长之门。40多年来,高考累积录取人数增长了27倍, 2.28亿人报名,9900万名高素质人才先后通过了中国高等教育的培养,高考已成为推动中国经济社会巨变的关键动力。 高考的重要性无须赘述,然而高考终究是一场考试,志愿填报才是人生真正的转折点。随着2019中国高考的落幕,对于十二年寒窗苦读的莘莘学子来说,高考志愿填报不仅仅是一张简单的表格,更像一份机遇与风险并存的判决书。 本期 ActiveReports 大数据分析报告,将借助权威数据,为您带来中国高考志愿填报与职业趋势分析,助您在进行高考志愿填报时,获取更加真实、有效的数据参考。 以下为报告主要内容: 2019年高考大军数量创近六年新高2019年高考人数达到1031万,净增56万,创近六年增长人数新高。2018年中国普通本科、专科招生人数达到790.9万,招生人数逐年上升。 本图表由葡萄城 ActiveReports报表工具制作 高考志愿填报付费咨询的用户持续增长,但增速趋于平缓近几年,很多机构开始推出自己的高考志愿填报服务,甚至以举办免费讲座的形式,向家长和考生推广咨询收费服务。数据显示, 从2010年到2018年,高考志愿填报付费咨询的用户规模持续增长,2018年付费咨询用户已达到29.7万人。 本图表由葡萄城 ActiveReports报表工具制作 其实就志愿填报的付费咨询而言,建议家长不要等到高考结束后才开始关注。如今,升学途径愈发多元化,志愿填报作为学业规划的一个方面,家长应尽早开始引导孩子未来的发展方向,并选择合适的升学路径,这样后续的志愿填报工作才会水到渠成。 软件工程、能源与动力工程等专业,毕业半年就业率超过95%作为近些年就业热门行业,软件工程专业本科毕业半年的就业率高达96.7%,位列各专业之首。能源与动力工程、电气工程及其自动化专业毕业半年的就业率分别为95.8%和95.6%。从数据分析得出,高就业率的专业更适合追求稳定和低风险的考生报考。当然,最终选择还需结合就业潜力、薪酬待遇等多方面进行综合考虑。 本图表由葡萄城 ActiveReports报表工具制作 十大高薪行业——金融业居首从数据报告得出,目前中国高薪行业占主导地位的仍是金融业。不过,未来随着高新技术的发展,IT/互联网、医疗等行业的发展潜力巨大,考生在未来若想追求更高薪酬的行业,可在这些行业里选择。 本图表由葡萄城 ActiveReports报表工具制作 人工智能、大数据成为未来最具潜力的行业数据显示,人工智能、大数据、生物制药等高新技术行业的未来发展值得期待,甚至有望在几年内成为热门行业。如今,时代越来越向自动化、智能化方向发展,考生在志愿填报时着重选择具备这些高新技术的学校和专业,未来或有更好的发展空间。 中国500强企业区域分布,北京占据20%作为首都,北京是中国500强企业分布最多的城市,大部分企业都选择把总部定在这里。除了北京,江浙沪、广东等沿海城市的500强企业及双一流大学的数量较其他区域也有更广泛的分布。 本图表由葡萄城 ActiveReports报表工具制作 从数据报告得出,北上广依旧是毕业生理想的求职地。因此,报考这些地区的学校会有更高的优势,同时也会获得更多名企实习的机会。 毕业第二选择之留学:商科类专业出国留学人数最多从数据分析报告可见,对外经济贸易大学以38.3% 的出国深造率位居榜首。在出国留学的专业选择方面,大部分学生选择的是商科和工科。普遍认为,国外高校对这两类专业的教学质量和研究水平相对较高,而且这两类专业具备大量的职位需求和良好的就业前景,因此,毕业生在选择留学时可重点考虑以上两类专业。 本图表由葡萄城 ActiveReports报表工具制作 留学,作为高考毕业生的第二选择,具备三大优势:增长见闻,开拓视野;掌握一门外语,受益终身;磨练生存能力,培养吃苦精神。 如今,越来越多的人开始将出国作为一种投资,但是,只有在良好的学习环境中,才能学到真正的知识,如果仅抱着体验生活或者移民的目的,还请慎重决定。 本期 ActiveReports 大数据分析报告观点总结1. 考生志愿填报问题突出在大学品牌、地理位置、专业学科、就业前景、分数线的把控上,考生往往面临艰难选择,在做出最终决定前,需要搜集大量相关信息。 2. 高考志愿填报受重视程度越来越高出于对个人发展方向的考虑,越来越多的考生会在志愿填报时听取父母、老师的指导建议,并关注媒体就志愿填报展开的问题讨论,志愿填报已成为考生高考成绩出炉后不得不面临的首要问题。 3. 高新技术行业或成为未来考生报考的重点方向随着高新技术的发展与普及,人类社会朝着自动化、智能化的方向不断发展,高新技术人才的缺口正逐步扩大,企业对高新技术人才的需求也日益增长。大数据、人工智能、生物制药、区块链等高新技术行业发展前景可期,这些行业未来或将成为考生新的选择。 4. 志愿填报付费咨询的价格水涨船高,部分家长已经开始预约明年的有偿咨询服务目前志愿填报咨询机构的服务费在上千至上万元不等,但目前该行业门槛较低,整个志愿填报付费咨询的市场处于一种鱼龙混杂的状态,家长需要提前做足功课才能避免上当。 5. 中国内陆地区高校创业氛围不逊沿海发达地区考生在毕业后选择自主创业方面,在中国内陆地区,如湖北、陕西、四川等地氛围浓厚,不逊于沿海发达地区。因此,有自主创业计划的考生,可以在志愿填报时考虑湖北、四川、陕西等内陆地区的高等院校。 6. 双一流大学对考生未来的发展帮助极大双一流大学能提供给考生更多的机会和平台,同时世界500企业趋于分布在双一流大学密集的地区,因此考生想在未来得到更好的发展和提升空间,选择双一流大学是最佳方案。 本文数据来源:iiMedia Research(艾媒咨询) 报表制作工具:葡萄城 ActiveReports .NET报表控件 *本文中所有报表模板,后续会加入葡萄城报表模板库中,供大家免费使用。>>报表模板库下载地址 关于ActiveReports报表控件 ActiveReports 是一款专注于 .NET 平台的报表控件,全面满足 HTML5 / WinForm / ASP.NET / ASP.NET MVC / WPF 等平台下报表设计和报表开发的需求,作为专业的报表工具为全球超过 300,000 名开发者提供全面的报表解决方案。 ...

June 21, 2019 · 1 min · jiezi

时延敏感业务低概率超时问题分析

前言作为阿里云底层提供的基础设施,内部的物理网络和许多网络产品在数据平面给客户的可操作性并不高,从一定程度上来说是个黑盒。当然,在传统的IDC环境,业务和物理网络之间也存在同样的隔阂。所以在遇到业务卡顿、延迟、不通等问题的时候,很容易怀疑到网络。因此如何抽丝拨茧,找到正确的方向对症下药才能够真正的解决问题。毕竟“真相只有一个”。 在进行问题排查和处理的时候,难度最高的场景就是极度偶发,复现频率极低的问题。尤其在网络排查的领域,通常为了性能和控制资源消耗,不会将每一个数据包的情况都一一记录下来,对于一次偶发的应用层记录的超时,网络层通常没有明确的对应此次应用层调用的包交互记录,因此排查起来非常困难。 在这次的案例中,我们通过一个客户端查询redis集群偶发超时的小案例,来说明一些诊断思路、排查手段,进而引出一些在网络方面提高业务稳定性的最佳实践。 问题环境这次的问题是一个交互性web应用中的一个子模块,主要进行redis查询,可以简单将其理解为视频弹幕网站中“查询弹幕”的小模块。这个模块的拓扑非常简单: 在上面的拓扑中,客户使用ECS构建了一个Redis集群,前面用Codis实现了一层Redis Proxy (为了通用性,后面均用Redis proxy来描述),并将这组Redis proxy挂载在一个SLB后,通过SLB的单一入口提供服务。 问题现象客户的主要问题是访问其自建Redis系统的客户端会不定期出现超时报错,尽管总体概率不高,但是报错概率高于其业务运行在原有机房的水平。超时报错主要有两种情况: 一般情况下超时数量与业务量呈正相关,非业务高峰期但是SLB、ECS的资源使用率均较低。会存在突发性的大量超时。诊断思路作为问题排查的第一步,首先要了解到问题本身所处的上下文和环境。在平时诊断问题收集信息的时候,为了有条理的、全面的收集信息,笔者将需要收集的信息分为两种类型:资源因素和环境因素。 资源因素:即发生问题的系统的拓扑。比如涉及的各种应用程序、主机、转发设备、链路资源等,并且要充分理解这些资源组建在拓扑中起到的作用。环境因素:即描述这个问题所需要的信息,比如报错日志,问题发生时间、频率,应用层设置的超时时间等等。了解资源因素和环境因素后,可以将问题的定义明确为:在哪些资源上发生了什么样的问题,然后根据该定义收集与问题相关的信息,并在解读和分析的时候通过数据排除所有的不可能,这样才能进行高效和准确的问题排查。 在本案例中,资源因素已经在上文的拓扑中阐述,问题所涉及的环境因素包括:客户设置的是50ms超时,在客户端的报错是read timeout(代表排除了tcp的三次握手超时),报错频率为非业务高峰期一个小时10个左右,业务高峰期1小时上百个。但是偶尔(一周内偶尔发生一次到两次)无论业务高峰还是非业务高峰都会有较多的,上百次的read timeout和connect timeout。客户已经排查过redis,其查询时间每次耗时不超过10ms,而redis proxy没有记录转发的日志。 排查方法因为所有可用的日志仅能定位到这个系统的两端(客户端、Redis),需要收集进一步的信息。面对这种超时类的问题,最直接、有效的办法就是进行抓包。而该问题发生的频率不高,整个系统流量也比较大,一直开着抓包很容易将磁盘撑满,因此需要使用循环抓包: tcpdump -i <接口|any> -C <每文件大小> -W <文件个数> -w <保存文件名> 抓包过滤条件该命令的意思是针对某个接口,按照过滤条件进行抓包,保存指定文件名前缀的文件下,最多占用每文件大小*文件个数 的磁盘空间并循环覆盖。开启循环抓包后,等待客户端报错再次出现,即可抓到现场的包交互过程。 抓包的结果文件可以使用wireshark打开,但是使用循环抓包抓到的数据包文件较大、数量较多,可以使用下面的小技巧进行快速的过滤: //在安装了wireshark的电脑上都会有capinfos和tshark两个命令,以笔者使用的macOS为例~$ capinfos -a -e *cap //使用capinfos查看抓包文件的其实时间和结束时间,选取包含报错时间+-超时时间的文件,其他文件就不需要了File name: colasoft_packets.capPacket size limit: inferred: 66 bytes - 1518 bytes (range)First packet time: 2019-06-12 09:00:00.005519934Last packet time: 2019-06-12 09:59:59.998942048File name: colasoft_packets1.capPacket size limit: inferred: 60 bytes - 1518 bytes (range)First packet time: 2019-06-12 09:00:00.003709451Last packet time: 2019-06-12 09:59:59.983532957//如果依然有较多文件,则可以使用tshark命令进行筛选。比如报错中提到Redis查询一个key超时,则可以用以下脚本找到这次查询请求具体在哪个文件中:~$ for f in ./*; do echo $f; tshark -r $f 'tcp.payload contains "keyname"'; done找到对应的请求之后,再用wireshark打开该文件,找到对应数据包,跟踪对应流来找到五元组和整个流的上下文交互。 ...

June 18, 2019 · 1 min · jiezi

宜人贷PaaS数据服务平台Genie技术架构及功能

上篇:架构及组件一、数据平台的发展1.1 背景介绍 随着数据时代的到来,数据量和数据复杂度的增加推动了数据工程领域的快速发展。为了满足各类数据获取/计算等需求,业内涌现出了诸多解决方案。但大部分方案都遵循以下原则: 降低数据处理成本合理提高数据使用/计算效率提供统一的编程范式宜人贷的数据服务平台也是遵循这三个原则。本人有幸亲身经历了宜人贷数据平台Genie的整个发展过程,纵观宜人贷和业内,可以说Genie的发展是工业界数据平台发展的缩影。 Google 的三大论文和Apache Hadoop 开源生态圈的发布应该是大数据处理技术走进“寻常百姓家”的起点。Hadoop 的组件均可在普通的廉价机器上运行,加上其代码是开源的,因此得到了众多公司的热捧。那么一开始这些公司都用它来做什么呢? 答案是数据仓库。 注:Google三大论文:Bigtable: A Distributed Storage System for Structured Data;The Google File System;MapReduce: Simplefied Data Processing on Large Clusters所以早期的数据平台大概的架构都是由Sqoop+HDFS+Hive这三个组件组成,因为这个是搭建数据仓库最廉价高效的方式。此时数据仓库只能回答过去发生了什么(离线阶段),因为Sqoop离线抽取一般采用的t+1快照方案,也就是说只有昨天的数据。 紧接着由于对数据实时性的需求提高了,需要实时做增量数据的关联聚合等复杂运算,这个时候数据平台就会加入分布式流计算的架构,如:Strom ,Flink, Spark Streaming 等。此时的数据仓库可以回答的是正在发生什么(实时阶段)。 由于离线数据处理流程(如:Sqoop+HDFS+Hive)和实时数据处理流程(如:Binlog+Spark Steaming+Hbase)两套流程计算逻辑耦合较大,并且通过组合才能支持实时全量的数据分析,所以就产生了很多架构,如早期的Lambda,Kappa等。此时历史数据和实时数据结合数据仓库可以回答什么终将会发生(预测阶段)。 数据平台发展至此已经不再是一个数据仓库就能解释的了,它与各类业务部门紧密合作(如营销、电销、运营)打造出诸多数据产品。此时数据仓库(数据平台)已经进入了主动决策阶段。 其实预测和实时的发展顺序不同的公司有所不同,只用历史数据就可以做出预测。 1.2 数据平台定位数据平台应该属于基础架构的重要环节,曾经互联网行业内有很多公司跟风搭建了大数据集群后发现很难发挥真正价值,其实最重要的原因应该是对数据使用的定位以及对数据平台的定位问题。目前的数据平台定位有以下几点: 决策赋能为决策层赋能,决策层通过使用BI报表快速了解公司运营情况,因为数据不会说假话。 业务数据分析/业务数据产品平台可以提供Adhoc即时分析,帮助分析师快速分析业务、快速定位问题、快速反馈。 计算存储业务数据产品也可以充分利用平台的计算存储资源打造数据产品,如推荐、智能营销等等。 效率提升数据处理效率,从而节约数据挖掘/处理的时间成本。 大部分公司早期人员架构如下图: 运营、营销以及决策层直接使用平台,大部分就是直接查看BI报表。业务分析师梳理完业务需求会把需求提供给数据仓库工程师,然后专业的数据仓库工程师会把新的需求加入已存在的公司级别的数据仓库之中。数据工程团队主要负责运维集群。 1.3 初期架构的缺点初期为什么是这样的架构这里就不做过多描述了,我们直接说一下它的缺点。 当决策层使用报表时发现总是慢了一拍,总会有新的需求出来。原因很简单:其实互联网公司的业务并不像传统行业(如银行、保险等)的业务那么稳定,因为互联网公司的发展比较快,业务更新迭代的也很快。业务分析总有各种临时的需求,原因和1类似。数据仓库工程师累成狗。数据仓库庞大笨重,很难灵活的运作,总是牵一发而动全身。集群作业运维困难,作业间耦合性太大,例如:A业务的表a 没跑出来直接影响了整个公司的所有作业。1.4 常见解决方案相信这些头疼的问题很多公司都遇到过,解决方式应该也是类似的。大体如下: 搭建产品化的数据服务平台。数据仓库能量转移到更加基础更加底层的数据问题,如数据质量问题、数据使用规范、数据安全问题、模型架构设计等。业务分析师直接利用平台搭建业务数据集市,提高敏捷性和专用性。数据工程主要职责不再是运维集群,而是搭建数据服务平台和构建业务数据产品。这样做的好处是: 解决了数据仓库的瓶颈问题。让最熟悉自己数据的人自己搭建数据集市,效率更高。业务数据产品可以直接使用数据服务平台提高效率,缩减公司成本。 二、宜人贷数据平台Genie架构及特点2.1 Genie架构宜人贷属于互联网金融公司,由于带有金融属性,所以对平台的安全性、稳定性、数据质量等方面的要求要高于一般的互联网公司。目前在宜人贷的数据结构中,数据总量为PB级别,每天增量为TB级别。除了结构化的数据之外,还有日志、语音等数据。数据应用类型分为运营和营销两大类,如智能电销、智能营销等。数据服务平台需要保证每天几千个批量作业按时运行,并保证数据产品对数据实时计算的效率以及准确性,与此同时,又要保证每天大量Adhoc查询的实效性。 以上是平台底层技术架构图,整体是一个Lambda架构,Batch layer 负责计算t+1的数据,大部分定时报表和数据仓库/集市的主要任务在这一层处理。Speed layer 负责计算实时增量数据,实时数仓,增量实时数据同步,数据产品等主要使用这一层的数据。Batch layer 采用sqoop定时同步到HDFS集群里,然后用Hive和Spark SQL 进行计算。Batch layer的稳定性要比运算速度重要,所以我们主要针对稳定性做了优化。Batch layer的输出就是Batch view。Speed layer 相对Batch layer 来说数据链路会长一些,架构也相对复杂。 ...

June 17, 2019 · 1 min · jiezi

精读数据之上智慧之光-2018

1. 引言本周精读内容是:《数据之上 智慧之光》,由帆软软件公司出品。 帆软公司是国内一家做大数据 BI 和分析平台的提供商,主打产品是 FineBI。笔者所在阿里数据中台也处于数据分析应用的前沿,本次精读的文章就是帆软公司的 《数据之上 智慧之光 2018》,感谢提供这份国内数据市场研究报告,让我们更深入全面的了解国内数据市场的发展方向。 随着 5G 的逐渐推行,网速比 4G 提高了 100 倍,将会为物联网打下通信基础,未来的世界将人与物、物与物进行互联。随着越来越多的设备接入网络,产生数据,而未来还有 6G、7G 将网速继续提高至 1 万倍、1 百万倍,利用卫星实现全球网络覆盖,将现实与虚拟融合等等,无不需要强大的数据处理分析技术才能掌握。 数据的总量将呈几何倍数上升,如果不能提前对数据的存储、处理、挖掘和分析提出一套解决方案,那么 5G 时代的海量数据就是人类社会的累赘,如果有一套数据处理与分析的方案,我们就有可能掌握海量的数据为自己所用,利用数据进一步推动人类社会向前发展。 上面是对未来的畅想,那么我国现阶段国内的数据市场的容量、需求是什么样呢?《数据之上 智慧之光》这本书给了我们答案。 PS:本文使用 2018 年的数据。 2. 精读大数据行业发展趋势2018 年中国大数据产业规模预计 329 亿元人民币,同比增长 39.4%。可以看到增长速度逐年增加,预计在 2020 年数据市场规模可达 586 亿元人民币。 笔者查了一下,2018 年全国网上零售额为 90065 亿元,比数据市场规模多了一个数量级,所以我国的数据产业其实还在萌芽期,可能还需要 5 到 10 年才能完全成熟,这也意味着目前数据市场是一片蓝海,从后面的数据和国内数据应用使用情况也可以看出来。 另外,各企业在大数据领域的投入资金与部门组织都同比 2017 年有所增加,其中接近四成的受访企业已经在应用大数据,较 2016 年提升了 4.5%,暂不考虑大数据的企业从 2016 年 7.8% 下降到 6.8%。 从微观角度观察社会也能发现这样的趋势,近些年研究大数据的公司明显增多,许多公司都逐渐设立了 “数据分析” 岗位和部门,可视化大屏在 toB 与 toG 领域都越来越得到重视。 ...

June 10, 2019 · 2 min · jiezi

Python到底能做什么?

来源 | 愿码(ChainDesk.CN)内容编辑愿码Slogan | 连接每个程序员的故事网站 | http://chaindesk.cn愿码愿景 | 打造全学科IT系统免费课程,助力小白用户、初级工程师0成本免费系统学习、低成本进阶,帮助BAT一线资深工程师成长并利用自身优势创造睡后收入。官方公众号 | 愿码 | 愿码服务号 | 区块链部落免费加入愿码全思维工程师社群 | 任一公众号回复“愿码”两个字获取入群二维码本文阅读时间:11min如果您正在考虑学习Python,或者已经开始学习它,那么您可能会问:“我使用Python到底能做什么?”这是一个很难回答的问题,因为Python有很多应用程序。但随着时间的推移,我发现Python有三个主要的流行应用程序:Web开发数据科学 - 包括机器学习,数据分析和数据可视化脚本Web开发最近基于Python的Web框架(如Django和Flask)在Web开发中变得非常流行。我为什么需要一个Web框架?这是因为Web框架使构建通用后端逻辑变得更容易。这包括将不同的URL映射到Python代码块,处理数据库以及生成用户在其浏览器上看到的HTML文件。我应该使用哪个Python Web框架?Django和Flask是两个最流行的Python Web框架。如果是刚入门,建议你使用其中一个。Django和Flask有什么区别?主要对比:· Flask提供简单,灵活和细粒度控制。它是非特定的(它可以让你决定如何实现它)。· Django提供了一个包罗万象的体验:您可以获得管理面板,数据库接口,ORM [对象关系映射]以及开箱即用的应用程序和项目的目录结构。你应该选择:· Flask,如果您专注于体验和学习机会,或者您想要更多地控制使用哪些组件(例如您想要使用哪些数据库以及如何与它们进行交互)。· Django,如果你专注于最终产品,特别是如果你正在开发一个直接的应用程序,如新闻网站,电子商店或博客,你希望总是有一个单一的,显而易见的方式来做事情。换句话说,如果你是初学者,Flask可能是一个更好的选择,因为它需要处理的组件更少。此外,如果您想要更多自定义,Flask是更好的选择。另一方面,如果你想要直接构建一些东西,Django更符合你的需求。数据科学 - 包括机器学习,数据分析和数据可视化首先,机器学习是什么?解释机器学习的最佳方法是给你一个简单的例子。假设您想要开发一个程序来自动检测图片中的内容。因此,如下图(图1),您希望程序识别出它是一只狗。鉴于下面的另一个(图2),您希望程序识别它是一个桌子。你可能会说,好吧,我可以写一些代码来做到这一点。例如,如果图片中有很多浅棕色像素,那么我们可以说它是一只狗。或者,您可以弄清楚如何检测图片中的边缘。然后,你可能会说,如果有很多直边,那么它就是一张桌子。但是,这种方法很快变得棘手。如果照片中有一只没有棕色头发的白狗怎么办?如果图片只显示表格的圆形部分怎么办?这就是机器学习的切入点。机器学习通常实现一种自动检测给定输入中的模式的算法。你可以给机器学习算法给1000张狗的照片和1000张桌子的照片。然后,它将学习狗和桌子之间的区别。当你给它一张狗或桌子的新图片时,它将能够识别它是哪一个。我认为这有点类似于婴儿学习新事物的方式。宝宝怎么知道一件事看起来像狗,另一件看起来像一张桌子?可能来自一堆例子。你可能没有明确地告诉婴儿,“如果有毛茸茸的东西,有浅棕色的头发,那么它可能是一只狗。”你可能会说,“那是一只狗。这也是一只狗。这是一张桌子。那个也是一张桌子。“机器学习算法的工作方式大致相同。您可以将相同的想法应用于:· 推荐系统(想想YouTube,亚马逊和Netflix)· 人脸识别· 语音识别等应用程序。您可能听说过的流行机器学习算法包括:· 神经网络· 深度学习· 支持向量机· 随机森林您可以使用上述任何算法来解决我之前解释过的图片标注问题。用于机器学习的Python有流行的机器学习库和Python框架。其中两个最受欢迎的是scikit-learn和TensorFlow。· scikit-learn附带了一些内置的更流行的机器学习算法。我在上面提到了其中一些。· TensorFlow更像是一个底层库,允许您构建自定义机器学习算法。如果您刚开始使用机器学习项目,我建议您先从scikit-learn开始。如果你开始遇到效率问题,那么我会开始研究TensorFlow。我该如何掌握机器学习?要掌握机器学习基础知识,我会推荐斯坦福大学或加州理工学院的机器学习课程。请注意,您需要微积分和线性代数的基本知识才能理解这些课程中的一些知识点。然后,用Kaggle练习所学到的东西。这是一个人们竞争为特定问题构建最佳机器学习算法的网站。他们也为初学者提供了很好的教程。那么数据分析和数据可视化呢?列举一个简单的例子:假设您正在为一家在线销售某些产品的公司工作。作为数据分析师,您可以绘制这样的条形图。从这张图中,我们可以看出,男性购买了超过400个单位的产品,女性在这个特定的星期天购买了约350个单位的产品。作为数据分析师,您可能会对这种差异提出一些可能的解释。一个明显可能的解释是,这种产品比起女性更受男性欢迎。另一种可能的解释可能是样本量太小而且这种差异只是偶然造成的。而另一种可能的解释可能是,男性倾向于仅在周日因某种原因购买该产品。为了理解这些解释中的哪一个是正确的,您可以绘制另一个像这样的图。我们不是仅显示星期日的数据,而是查看整整一周的数据。如您所见,从这张图中,我们可以看到这种差异在不同的日子里非常一致。从这个小小的分析中,你可以得出结论,对这种差异最有说服力的解释是,这种产品更容易受到男性的欢迎,而不是女性。如果你看到像这样的图表怎么办?那么,是什么解释了周日的差异?你可能会说,也许男人往往只是因为某种原因在周日购买更多的这种产品。或者,也许只是巧合,周日男人买了更多。所以,这是一个说明数据分析在现实世界中可能是什么样子的简化的例子。使用Python进行数据分析/可视化Matplotlib是最受欢迎的数据可视化库之一。· 很容易上手· 其他一些图书馆,如Seaborn,都是以它为基础的。因此,学习matplotlib将有助于您以后学习这些其他库。我应该如何使用Python学习数据分析/可视化?首先应该了解数据分析和可视化的基础知识,然后从Coursera和Khan Academy等网站学习统计数据的基础知识也会有所帮助。脚本什么是脚本?脚本通常是指编写旨在自动执行简单任务的小程序。举个例子:我曾经在日本的一家小型创业公司工作,我们有一个电子邮件支持系统。这是一个系统,让我们回答客户通过电子邮件发送给他们的问题。当我在那里工作时,我的任务是计算包含某些关键字的电子邮件的数量,以便我们分析收到的电子邮件。我们可以手动完成它,但是,我编写了一个简单的程序/简单脚本来自动执行此任务。实际上,我们当时使用Ruby,但Python也是这类任务的好语言。Python适合这种类型的任务,主要是因为它具有相对简单的语法并且易于编写。用它写一些小东西并测试它也很快。嵌入式应用程序Python可以与Rasberry Pi一起使用。是硬件爱好者中的一种流行应用。游戏您可以使用名为PyGame的库来开发游戏,但它并不是最流行的游戏引擎。你可以用它来建立一个爱好项目,但如果你对游戏开发很认真的话,我个人不会选择它。相反,建议开始使用Unity与C#,这是最受欢迎的游戏引擎之一。它允许您为许多平台构建游戏,包括Mac,Windows,iOS和Android。桌面应用程序您可以使用Tkinter制作一个Python,但它似乎也不是最受欢迎的选择。相反,似乎Java,C#和C ++等语言更受欢迎。最近,一些公司也开始使用JavaScript来创建桌面应用程序。例如,Slack的桌面应用程序是用Electron构建的。它允许您使用JavaScript构建桌面应用程序。就个人而言,如果我正在构建一个桌面应用程序,我会使用JavaScript选项。它允许您重用Web版本中的一些代码(如果有的话)。Python 3还是Python 2?推荐Python 3,因为它更现代,而且在这一点上它是一个更受欢迎的选项。备注:关于后端代码与前端代码的说明(以防您不熟悉这些术语):假设您想制作像Instagram这样的东西。然后,您需要为要支持的每种类型的设备创建前端代码。您可以使用,例如:· 适用于iOS的Swift· 适用于Android的Java· 用于Web浏览器的JavaScript每组代码都将在每种类型的设备/浏览器上运行。这将是一组代码,用于确定应用程序的布局如何,单击按钮时的外观等等。但是,您仍然需要能够存储用户的信息和照片。您需要将它们存储在服务器上,而不仅仅存储在用户的设备上,以便每个用户的关注者都可以查看他/她的照片。这是后端代码/服务器端代码的用武之地。您需要编写一些后端代码来执行以下操作:· 跟踪谁在追随谁· 压缩照片,以免占用太多存储空间· 在发现功能中向每个用户推荐照片和新帐户因此,这是后端代码和前端代码之间的区别。顺便说一下,Python并不是编写后端/服务器端代码的唯一好选择。还有许多其他流行的选择,包括基于JavaScript 的Node.js。

April 16, 2019 · 1 min · jiezi

谁有股民精准数据

你好,你这边有数据是吗 我这边需要股民精准数据。长期合作。量大。联系q370101772

April 9, 2019 · 1 min · jiezi

谈谈JavaScript中的数据类型

前言ECMAScript 迄今为止标准定义了 7 种数据类型:6 种原始类型– String、Number、 Boolean、 Undefined、Null 和 Symbol;1 种引用类型– Object看到这里,你是否已经对它们了如指掌呢。如果你还对它们之间的定义、转换、检测等方面并不是那么清楚,或者已经有些模糊。那么,下面就让我们一起去重新探索、温习一遍吧如果文章中有出现纰漏、错误之处,还请看到的小伙伴多多指教,先行谢过以下↓原始值除 Object 以外的所有类型都是不可变的(值本身无法被改变),我们称这些类型的值为 原始值String类型JavaScript 的字符串类型用于表示文本数据.JavaScript 字符串是不可更改的。这意味着字符串一旦被创建,就不能被修改。但是,可以基于对原始字符串的操作来创建新的字符串var a = ‘hello’类型转换:toString()var num = 2;num.toString() // ‘2’var found = true;found.toString() // ’true’除去 null 与 undefined 之外,其余数据类型都存在 toString 方法,使用会报错String()var sym = Symbol(1);String(sym) // ‘Symbol’var num = 10;String(num) // ‘10’var str;String(str) // ‘undefined’如果值有 toString 方法,则调用该方法并返回响应的结果如果是 null 返回 ’null’如果是 undefined 返回 ‘undefined’隐式转换var a = 3;a + ’’ // ‘3’var obj = {a: 3};obj + ’’ // [object object]转换规则和 String 方法一致Number类型根据 ECMAScript 标准,JavaScript 中只有一种数字类型:基于 IEEE 754 标准的双精度 64 位二进制格式的值(-(263 -1) 到 263 -1)特殊的数值类型:无穷大:+Infinity(),-Infinity() 和 NaN (非数值,Not-a-Number)NaN,非数值。是一个特殊的 Number 类型,用来表示一个本来要返回数值的操作未返回数值的情况任何涉及 NaN 的操作都返回 NaNNaN 与任何值都不相等,包括 NaN 本身40 / NaN // NaNNaN === NaN // false最基本的数值字面量格式是十进制整数,还可以通过八进制或十六进制来表示。八进制字面值的第一位必须是 0,然后是八进制数字序列(0 ~ 7)。十六进制字面量的前两位必须是 0x,后跟任何十六进制数字(0 ~ 9 以及 a ~ f)。其中字母可以是大写也可以是小写var num1 = 070; // 八进制的56var num1 = 079; // 无效的八进制,会解析为十进制的79var num2 = 56; // 十进制的56var num3 = 0x38; // 十六进制的56类型转化方式:Number()、parseInt()、parseFloat() 以及操作符隐式转换Boolean类型表示一个逻辑实体,可以有两个值:true 和 falsevar suc = true;var los = false;类型转化方式:Boolean()以及操作符隐式转换Undefined类型Undefined 类型只有一个值,即特殊的 undefined 。一个 声明但没有被赋值的变量会有个默认值 undefinedvar a; // undefinedNull类型Null 类型也只有一个值,即特殊的 null 表示一个空对象指针var foo = null;Symbol类型符号 (Symbols) 是 ECMAScript 第 6 版新定义的。符号类型是唯一的并且是不可修改的var s = Symbol()Symbol 函数前不能使用 new 命令,否则会报错。这是因为生成的 Symbol 是一个原始类型的值,不是对象Symbol 函数可以接受一个字符串作为参数,表示对 Symbol 实例的描述引用类型在 ECMAScript 中,引用类型是一种数据结构,用于将数据和功能组织在一起最常见的引用类型:对象(Object)、数组(Array)、函数(Function)、正则(RegExp)和日期(Date)等引用类型与基本类型之间最大的不同基本数据类型的值是按值访问的,基本类型的值是不可变的var a = 1;var b = 1;a === b // trueb = a b = 2;a // 1引用类型的值是按引用访问的,引用类型的值是可变的var a = {};var b = {};a === b // falsevar a = {};var b = ab.name = ‘hello’a.name // hello基本包装类型为了便于操作基本类型值, ECMAScript 还提供了 3 个特殊的引用类型:Boolean、Number 和 Stringvar a = new String(‘hello’)typeof a // object 引用类型与基本包装类型的主要区别就是对象的生存期。使用 new 操作符创建的引用类型的实例,在执行流离开当前作用域之前都一直保存在内存当中。而自动创建的基本包装类型的对象,则只存在于一行代码的执行瞬间,然后立即销毁。这意味着我们不能在运行时给基本类型值添加属性和方法var s1 = ‘some text’;s1.color = ‘red’;s1.color // undefined// 但是这样是可以的var s1 = new String(‘some text’);s1.color = ‘red’;s1.color // red 不建议显式的创建基本包装类型的对象,因为在很多时候会造成一些让人很迷惑的东西var b = new Boolean(false)var c = b && truec // true这样的情况下,b 这个变量就是 Boolean 对象,所以无论在什么情况下,它都是 true记得之前看到过这样一个问题:var str = ‘hello’typeof str // Stringstr instanceof String // false这里的结果为 false 的原因就是 str 本质上是一个原始值,并不存在 prototype 属性当然,这里也涉及到了数据类型的判断,有兴趣的小伙伴可以 点击这里 查看如何判断 JavaScript 中的数据类型后记不断总结温习前端方面的知识点以及有趣的东西,感兴趣的小伙伴可以 点击这里,查看完整版前端总结知识点,欢迎 star 关注期待同行以上 ...

April 4, 2019 · 2 min · jiezi

全国行政区划数据(截止2019年3月)

省市区三级数据(含港澳台钓鱼岛以及经济开发区)和经纬度信息,准确有效!下载地址请扫码

March 31, 2019 · 1 min · jiezi

前端、后端、运维都能用的动态json数据管理神器,节省你大量的开发、设计数据库、运维的时间

基于Json Schema的动态数据管理神器-DMS介绍什么是DMS?DMS Github:基于Json Schema/UI Schema模块化的Json动态数据管理平台。什么是Json Schema/UI Schema?用于动态生成表单的Schema,参考 Json Schema使用案例官方文档使用场景有哪些?无论前端、后端、移动端、运维,理论上所有需要动态配置数据的场景都可以使用。针对前端、移动端:可以配置页面每个模块展示型数据,也可以配置各种版本号用于动态更新,各种功能开关、页面主题等。针对后端:可以配置业务相关的ID,配置类目,城市列表,热门等。针对运维:可以作为区分环境的配置中心等。当然使用场景远不止这些……可以运用到生产环境吗?当然可以,DMS存储的数据读写是完全分开的,目前支持通过Redis、CDN(推荐)两种获取数据方式。即使DMS自身服务器挂掉,也不会影响数据的读取。强烈推荐使用CDN的方式,这样稳定性和使用的CDN是一样的。DMS应用、模块、参数介绍应用:包含一个或多个模块,包含一个或多个参数模块:配置数据的最小单位参数:使模块根据不同参数配置不同数据(如:每个城市展示的频道页不一样)DMS特性实时表单预览;模块化(组件化)数据管理;支持表单数据逻辑判断、数据验证;Schema数据自动保存,防止误操作及未知异常;支持动态增加参数,参数本身也可以为DMS生成的配置数据;配合dms-upload可以快速将通过表单上传的文件传入CDN/云存储符合实际场景的权限控制:开发只负责schema编写,需求方配置所有数据;支持Schema生成所有基本表单类型及高级控件,如:日期选择器、进度条、密码框、颜色选择器等;实时数据预览/审核(配合dms-fetch,同时支持服务端代理请求,及浏览器端请求的数据预览与审核)快速开始请先确保已经安装好:nodejs8+、mysql、redis,并已开启相关服务安装DMS> git clone https://github.com/win-winFE/dms.git> yarn # 若没有yarn,请使用 npm install创建日志目录> mkdir /opt/logs/nodejs -p执行初始化sql使用mysql执行 dms/database/dms.sql修改项目中mysql/redis相关配置dms/config/config.default.js(mysql默认密码为:root1234)启动/停止/调试启动端口默认为:7101,需要修改请修改dms/package.json文件start部分的7101> yarn start # 启动,若没有yarn,请使用 npm run start> yarn stop # 停止, npm run stop> yarn dev # 调试,npm run dev注册进入:http://localhost:7101,将自动跳转到登录页,选择【注册】,按要求填写相关数据,注册成功将自动跳转到【应用管理】页面新建示例应用点击【新建应用】,新建如下应用新建示例模块点击“淘宝首页”的【模块列表】,点击【新建模块】编写该模块Schema点击“首页banner”的【编辑Schema定义】,复制如下Schema到【Schema定义】中并【保存Schema】{ “title”: “示例”, “description”: “视频/图片展示配置示例”, “type”: “array”, “minItems”: 3, “items”: { “type”: “object”, “properties”: { “url”: { “title”: “跳转链接”, “type”: “string” }, “imgs”: { “title”: “轮播图片”, “type”: “string”, “format”: “file” } } }}添加一个参数进入【参数列表】,添加如下参数【编辑参数】,【提交】如下参数编辑数据点击左侧菜单,进入【数据管理】,进入“淘宝首页”应用的【模块列表】,选择城市后点击【进入】,再选择“首页banner”的【编辑模块数据】,此时还不能上传图片、保存数据,需要启用dms-upload启动dms-upload> git clone https://github.com/win-winFE/dms-upload.git> yarn # npm install执行初始化sql使用mysql执行 dms-upload/database/dms-upload.sql使用mysql执行 dms-upload/database/init.sql(用于上传时的权限验证,默认:root root1234)修改项目中mysql/redis相关配置dms/config/config.default.js(mysql默认密码为:root1234)配置dms-upload启动端口(默认7100):dms-upload/package.json start部分,若修改端口。请修改 dms/app/util/constants.js dmsUploadAPI 中的请求地址前缀数据库配置:dms-upload/config/config.defult.jsCDN文件保存目录(默认/usr/local/services/cdn/dms):dms-upload/config/config.defult.js cdnDirCDN文件访问地址前缀(默认//127.0.0.1:5000/dms):dms-upload/config/config.defult.js cdnPrefix新建CDN文件(图片、json数据)保存目录> mkdir /usr/local/services/cdn/dms/data -p # 若未使用默认cdnDir,请修改data前面部分> mkdir /usr/local/services/cdn/dms/res -p # 若未使用默认cdnDir,请修改res前面部分启动dms-upload> yarn start # npm run start本地调试上传图片回显> cd /usr/local/services/cdn> python -m SimpleHTTPServer 5000 # python3 请使用: python3 -m http.server 5000继续回到DMS平台编辑数据提交下列数据直接访问数据(用于非js使用场景)临时数据:提交后复制成功Toast中的链接,可以直接访问临时数据数据正式数据:将临时数据审核为正式数据,也可以通过Toast中的链接直接访问正式数据使用dms-fetch访问数据(用于js使用场景)1.项目中安装dms-fetch(不建议,强依赖axios,说明见Github)> yarn add dms-fetch # npm install dms-fetch –save2.带参数使用示例(伪代码)import { getDMSDataByCDN } from ‘dms-fetch’;import …// 复制编辑数据页面的唯一标示,下面是React应用配合使用DMS参数的示例export default class extends React.Component { … fetchData = async () => { const { city } = getParams(this.props.location.search); const dmsData = await getDMSDataByCDN(/7/10/city/${city}, this.props.location.search); this.setState({ dmsData, }); }; … render() { … }}更多高级用法请参考 DMS Github ...

March 29, 2019 · 1 min · jiezi

Davinci用户体验 | 你离数据可视精美大屏只差一个Davinci!

作者: 李玲、王小燕 出处:敏捷大数据 来源:宜信技术学院技术沙龙001期|AI中台:一种敏捷的智能业务支持方案|宜信技术沙龙 3月28日晚8点线上直播,点击报名导读:同比和环比是衡量企业某个数据周期性增长速度变化的重要指标,但是一味的看数据,我们很难对增长率的大小做出比较,这个时候就需要可视化工具来帮助我们。小编这次又“编造”了另外一组数据,利用Moonbox写出SQL求同比环比增长率,最后借用Davinci展示出来。具体请看正文特别鸣谢感谢万能的 Wormhole一姐王小燕同学 & Moonbox大神王浩同学 提供SQL技术支持!一、Introduction环比指本期统计数据与上期统计数据做对比,如2018年2月的数据与2018年1月的数据做对比。同比指本期的统计数据与往年同期的统计数据做对比,如2018年1月与2017年1月的数据做对比。同比和环比都反映变化速度,但侧重点不同:利用环比,我们会看到数据的短期趋势,但是这个数据可能是因为受到季节等因素的影响;而同比则更加侧重反映长期的大趋势,这样我们分析数据也就规避了季节的因素。图1是小编随意编造的一组很简单的数据,表头包括年、月、场次、观众人数、票房及广告收入,用英文表示是为了之后写SQL的时候方便一些。图1暂且称这组数据为“ABD虚拟影院相关数据”,接下来,就是借助Davinci展示同比环比的时刻啦!二、ProcessStep 1:增加数据源点击Source界面右上角“+”,在Source List里新增数据源(图2),上传CSV文件至指定数据库中(图3),小编使用的数据库为MySQL。图2图3上传完CSV文件之后,就来到了我们特别重要的一步:写SQL、求出同比环比增长率。计算同比环比可借助SQL里的window窗口函数实现。MySQL数据库8.x版本才支持window函数,然而小编所用数据库版本为5.x,升级比较麻烦,所以小编在这里使用Moonbox计算同比环比增长率。步骤如下:(1)把 CSV文件对应数据源挂载到Moonbox计算引擎中。图4(2)在Source界面继续添加来自Moonbox的数据源,小编将其命名为“growthSource”,连接Url写Moonbox jdbc服务地址(例:jdbc:moonbox://localhost:10010/growthSource),注意将Moonbox jdbc 驱动放至Davinci lib包下。图5点击保存,就新增了一个JDBC类型的数据源。Step 2:添加View点击View界面右上角“+”,出现图6界面。【View是 Davinci 中非常重要的概念,所有的 SQL 逻辑都需要在这里创建,所有在图表上展示的数据都是通过这里的 SQL 获取,可视化建模和团队数据权限控制也在这里进行。(引自Davinci用户手册)】图6点击图6左上角的“选择一个Source”,选择上一步中新增的“growthSource”数据源,接着就是写SQL语句了,求同比与环比增长率的SQL语句分别如代码块7、代码块8所示。select g1.year,g1.month, g1.box_office_mln, g1.last_year_month_box_office_mln, round((g1.box_office_mln - g1.last_year_month_box_office_mln)/g1.last_year_month_box_office_mln * 100.0, 2) as box_office_mln_year_growth, g1.advertising_revenue_mln, g1.last_year_month_advertising_revenue_mln, round((g1.advertising_revenue_mln - g1.last_year_month_advertising_revenue_mln)/g1.last_year_month_advertising_revenue_mln * 100.0, 2) as advertising_revenue_mln_year_growth, g1.screening_ths, g1.last_year_month_screening_ths, round((g1.screening_ths - g1.last_year_month_screening_ths)/g1.last_year_month_screening_ths * 100.0, 2) as screening_ths_year_growth, g1.audience_mln, g1.last_year_month_audience_mln, round((g1.audience_mln - g1.last_year_month_audience_mln)/g1.last_year_month_audience_mln * 100.0, 2) as audience_mln_year_growth from (select g.year, g.month, g.box_office_mln, lead(box_office_mln) over(partition by g.month order by g.year desc) as last_year_month_box_office_mln, g.advertising_revenue_mln, lead(advertising_revenue_mln) over(partition by g.month order by g.year desc) as last_year_month_advertising_revenue_mln, g.screening_ths, lead(screening_ths) over(partition by g.month order by g.year desc) as last_year_month_screening_ths, g.audience_mln, lead(audience_mln) over(partition by g.month order by g.year desc) as last_year_month_audience_mln from GrowthRate_SQL g order by g.month, g.year desc) g1;代码块7select g1.year,g1.month , g1.box_office_mln, g1.last_month_box_office_mln, round((g1.box_office_mln - g1.last_month_box_office_mln)/g1.last_month_box_office_mln * 100.0, 2) as box_office_mln_month_growth, g1.advertising_revenue_mln, g1.last_month_advertising_revenue_mln, round((g1.advertising_revenue_mln - g1.last_month_advertising_revenue_mln)/g1.last_month_advertising_revenue_mln * 100.0, 2) as advertising_revenue_mln_month_growth, g1.screening_ths, g1.last_month_screening_ths, round((g1.screening_ths - g1.last_month_screening_ths)/g1.last_month_screening_ths * 100.0, 2) as screening_ths_month_growth, g1.audience_mln, g1.last_month_audience_mln, round((g1.audience_mln - g1.last_month_audience_mln)/g1.last_month_audience_mln * 100.0, 2) as audience_mln_month_growth from (select g.year, g.month, g.box_office_mln, lead(box_office_mln) over(partition by g.year order by g.month desc) as last_month_box_office_mln, g.advertising_revenue_mln, lead(advertising_revenue_mln) over(partition by g.year order by g.month desc) as last_month_advertising_revenue_mln, g.screening_ths, lead(screening_ths) over(partition by g.year order by g.month desc) as last_month_screening_ths, g.audience_mln, lead(audience_mln) over(partition by g.year order by g.month desc) as last_month_audience_mln from GrowthRate_SQL g order by g.year, g.month) g1;代码块8注:这里小编增加了两个“View”,分别是yearGrowth和monthGrowth。另外,为了方便计算,在写SQL时,四列主数据的后面生成了一列新数据,用来表示去年同月或同年上月的数据。点击右下角“Execute”执行SQL语句,yearGrowth和monthGrowth里面的数据分别发生如下变化:图9图10点击“Model”进行可视化建模,也就是数据中,哪几项用作维度,哪几项用作指标。更改完毕后,点击“保存”。在这两个View中,小编仅用年、月作为维度,其余都作为指标。Step 3:制作Widget可视化组件Widget是 Davinci 中功能最强大也最复杂的部分。同一个数据视图可以被多个可视组件使用,并用不同的图形展现。在展示同比环比数据方面,我们一般会用柱状图或者折线图来表示,而在Davinci所支持的透视驱动和图表驱动里,都有柱状图和折线图。它们具体有什么区别呢?让我们在实例中感受一下吧注:想了解透视驱动和图表驱动?请参考Davinci用户手册:https://edp963.github.io/davi…点击Widget界面右上角“+”,选择一个View。选择完毕后,出现图11所示界面。图11其中,分类型字段对应View中设置的是维度的字段,数值型字段对应指标字段。当鼠标悬停在图形图标上,系统提示图形的配置要求,满足条件生成图形。例如,小编想要了解一下2017年下半年各月票房的环比增长率趋势,用透视驱动中的柱状图表示。在这个需求中,简简单单拖拽几个字段就能配制出小编想要的图表。选择“monthGrowth”这个View,将鼠标放在柱状图图标上,我们会发现要做这个柱状图会需要“0到多个维度”及“1到多个指标”。既然小编想看的是各月环比增长率,那维度这里我们就需要放上“month”字段(点击字段下拉菜单可以排序),指标则是票房环比增长率字段。接下来我们就需要用到“筛选”一项,在小编的原始数据中,年份里包括2017和2018年,月份里有12个月。这里小编的要求是“2017年下半年”,因此需要将“year”和“month”字段都拖到筛选栏里,并且按照自己需求配置筛选。这几项配置完以后,出现了如图12所示界面:图12如果觉得单单只看图形,不够清晰明了,我们还可以将票房环比数据拖进标签栏,最终如图13所示:图13当然,大家也可以根据自己的喜好配置柱状图颜色、标题颜色及大小以及坐标轴颜色等(图14)。图14点击右上角“保存”,小编就成功制作了一个Widget。当然,这个Widget也可以用折线图来表示(图15),完全看个人需求图15再例如,小编想试试用图表驱动里的折线图来展示一下2018年各月广告收入的同比增长率。这时候就要选择“yearGrowth”这个View了。然后将鼠标放在图表驱动的折线图图标上,我们会发现要做这个折线图需要“1个维度”及“1到多个指标”。同样,将“month”字段拖入维度栏,“广告收入同比增长率”字段拖入指标栏。Hmmmmm,就完成了。(图16)图16是不是过于简单了?但是大家有没有发现一个问题:在这个数据配置栏里并没有“标签栏”,但是折线图中依然有数字。原来这里的标签设置在样式配置中。勾选样式配置中的“显示标签”,数字就出现在了折线图中(图17)。图17且慢!小编似乎发现了折线图可以变换面貌。点击了一下,发现果然平滑的折线图更符合小编心意。于是最终的“2018年各月广告收入同比增长率”折线图制作完成!(图18)图18最后例如,小编想看一下2018年各月场次的增减与各月广告收入的多少有没有关系。透视驱动和图表驱动里的柱状图和折线图都可以表示,小编暂且选择透视驱动里的折线图。同样还是将需求所需字段拖入维度栏和指标栏 — “month”拖入维度栏,“广告收入”和“场次”拖入指标栏,把“year”拖入筛选栏,选择出2018年。完成!(图19)图19值得一提的是,在这里我们还可以按照自己喜好变换指标栏中的图形。(图20)图20于是,小编就这样靠着拖拉拽完成了很多Widget的制作。三、Display最终,我们来到了展示界面。在展示界面,分别有Dashboard和Display两种展示方式。Dashboard里面有很多更为高级的功能,比如联动关系配置和钻取设置。然而,肤浅的小编暂时被Display展示吸引住了,所有兴趣都挂在了Display上面,因此,本文中小编只介绍Display展示,Dashboard功能之后再做详细介绍。下面我们来介绍一下Davinci的Display展示功能。其实也没有什么介绍的,直接上图吧!图21 简约风图22 漫画风图23 科技风如图所示,在Display的展示中,我们可以自己更改背景颜色或上传背景图片。设置好背景之后,点击左上角的“Widgets”图标,上传自己想展示的图表,排列成自己喜欢的形状,风格任君选择,一个个大屏就这样制作完成!以上便是小编用Davinci展示同比环比的过程。由于数据是自己编的,难免会有不符合实际之处,敬请大家谅解。另外,Davinci一直在不断的成长中。未来,我们还是支持在Davinci Widget中直接计算出同比环比增长率这项功能,还请大家耐心等待,继续支持。因为你们的支持,是我们不断前进的动力!本文Display设计方面很大一部分是借鉴了Davinci用户做出来的大屏,当然这里只copy到一点皮毛,要学习到大神所制Display的精髓还有很长的路要走。还请各位大神能不吝赐教,多多放上自己用Davinci制作出来的精美Display或者形成教程小文,让大家更多的学习精美大屏制作方法 ...

March 25, 2019 · 2 min · jiezi

POI如何高效导出百万级Excel数据?

阅读原文:POI如何高效导出百万级Excel数据?在一个具有统计功能的系统中,导出excel功能几乎是一定的,如何导出excel?导出的数据有多少?如何高效的导出?Excel简介什么是excel就不用介绍了,这里主要说明不同版本下每个sheet下的行列限制。由上面可知 Excel 2003及以下是无法实现单sheet百万级的数据。Apache POI简介Apache POI 是用Java编写的免费开源的跨平台的 Java API,Apache POI提供API给Java程式对Microsoft Office(Excel、WORD、PowerPoint、Visio等)格式档案读和写的功能。POI为“Poor Obfuscation Implementation”的首字母缩写,意为“可怜的模糊实现”。常用类HSSF - 提供读写Microsoft Excel XLS格式档案的功能。XSSF - 提供读写Microsoft Excel OOXML XLSX格式档案的功能。SXSSF - 一种基于XSSF的低内存占用的API(3.8版本开始出现)。HWPF - 提供读写Microsoft Word DOC97格式档案的功能。XWPF - 提供读写Microsoft Word DOC2003格式档案的功能。HSLF - 提供读写Microsoft PowerPoint格式档案的功能。HDGF - 提供读Microsoft Visio格式档案的功能。HPBF - 提供读Microsoft Publisher格式档案的功能。HSMF - 提供读Microsoft Outlook格式档案的功能。我们这里是导出Excel,所以使用的是前三个。导出策略方案使用XSSF和SXSSF分别导入1w,10w,100w数据使用SXSSF,SXSSF以10w分页,SXSSF多线程以10w分页导入100w数据性能对比时间不包含网络耗时总结方案一:数据在万条时XSSF和SXSSF相差不大数据上十万后SXSSF性能开始突出数据到达百万时,XSSF已不适合使用方案二:不进行分表时,SXSSF最多可存储1048576行百万级数据分表存储时,使用多线程导出几乎是不使用多线程导出的一半时间最终我得出一个导出百万级数据的最高效方案:多线程分表导出实战controller层:@RestController @RequestMapping(“export”)public class ReportController {public static final String[] TITLE = new String[]{“第1列”, “第2列”, “第3列”, “第4列”, “第5列”};public static final String SHEET_NAME = “page1”;@RequestMapping(value = “/sxssf/page/thread”)@ResponseBodypublic void exportSXSSFWorkbookByPageThread(HttpServletResponse response, Integer num) throws Exception { //excel文件名 String fileName = System.currentTimeMillis() + “.xlsx”; //sheet名 if (Objects.isNull(num)) { num = 65536; } String[][] content = buildContent(num); long start = System.currentTimeMillis(); SXSSFWorkbook wb = ExcelUtil.getSXSSFWorkbookByPageThread(TITLE, content, null); long millis = System.currentTimeMillis() - start; long second = millis / 1000; System.out.println(“SXSSF Page Thread 导出” + num + “条数据,花费:” + second + “s/ " + millis + “ms”); writeAndClose(response, fileName, wb); wb.dispose();}/** * 构建内容 * @param num * @return */private String[][] buildContent(Integer num) { String[][] content = new String[num][4]; for (int i = 0; i < content.length; i++) { content[i][0] = “1”; content[i][5] = “2”; content[i][6] = “3”; content[i][7] = “4”; content[i][8] = “5”; } return content;}private void writeAndClose(HttpServletResponse response, String fileName, Workbook wb) { try { this.setResponseHeader(response, fileName); OutputStream os = response.getOutputStream(); wb.write(os); os.flush(); os.close(); } catch (Exception e) { e.printStackTrace(); }}public void setResponseHeader(HttpServletResponse response, String fileName) { try { try { fileName = new String(fileName.getBytes(), “UTF-8”); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } response.setContentType(“application/octet-stream;charset=ISO8859-1”); response.setHeader(“Content-Disposition”, “attachment;filename=” + fileName); response.addHeader(“Pargam”, “no-cache”); response.addHeader(“Cache-Control”, “no-cache”); } catch (Exception ex) { ex.printStackTrace(); }}}工具类:public class ExcelUtil { public static final int PER_SHEET_LIMIT = 500000; public static SXSSFWorkbook getSXSSFWorkbookByPageThread(String[] title, String[][] values) { SXSSFWorkbook wb = new SXSSFWorkbook(); int pageNum = values.length / PER_SHEET_LIMIT; int lastCount = values.length % PER_SHEET_LIMIT; if (values.length > PER_SHEET_LIMIT) { CellStyle style = wb.createCellStyle(); int sheet = lastCount == 0 ? pageNum : pageNum + 1; CountDownLatch downLatch = new CountDownLatch(sheet); Executor executor = Executors.newFixedThreadPool(sheet); for (int c = 0; c <= pageNum; c++) { int rowNum = PER_SHEET_LIMIT; if (c == pageNum) { if (lastCount == 0) { continue; } rowNum = lastCount; } Sheet sheet = wb.createSheet(“page” + c); executor.execute(new PageTask(downLatch, sheet, title, style, rowNum, values)); } try { downLatch.await(); } catch (InterruptedException e) { e.printStackTrace(); } } return wb;}}分表任务类:public class PageTask implements Runnable {private CountDownLatch countDownLatch;private Sheet sheet;private String[] title;private CellStyle style;private int b;private String[][] values;public PageTask(CountDownLatch countDownLatch, Sheet sheet, String[] title, CellStyle style, int b, String[][] values) { this.countDownLatch = countDownLatch; this.sheet = sheet; this.title = title; this.style = style; this.b = b; this.values = values;}@Overridepublic void run() { try { Row row = sheet.createRow(0); Cell cell = null; for (int i = 0; i < title.length; i++) { cell = row.createCell(i); cell.setCellValue(title[i]); cell.setCellStyle(style); } for (int i = 0; i < b; i++) { row = sheet.createRow(i + 1); for (int j = 0; j < values[i].length; j++) { row.createCell(j).setCellValue(values[i][j]); } } } catch (Exception e) { e.printStackTrace(); } finally { if (countDownLatch != null) { countDownLatch.countDown(); } }}} ...

March 8, 2019 · 3 min · jiezi

将军令:数据安全平台建设实践

背景在大数据时代,数据已经成为公司的核心竞争力。此前,我们介绍了美团酒旅起源数据治理平台的建设与实践,主要是通过各种数据分析挖掘手段,为公司发展决策和业务开展提供数据支持。近期,业内数据安全事件频发,给相关企业造成了无可挽回的损失,更为数据安全防护意识薄弱的企业敲响了警钟。如何对公司内部数据最为集中的数据分析、数据服务、数据治理等各种数据类产品进行权限管控,已经成为数据安全建设中最为重要的任务。如果从控制力的角度来进行划分的话,权限管控可以分为功能级权限管控和数据级权限管控。早期的数据安全产品大多使用传统的权限模型,只能实现功能级权限管控,无法进行数据级权限管控。基于数据类产品更高的安全要求,我们需要构建一个同时满足各类产品数据安全的我们需要构建一个同时满足各类产品数据安全的平台。为此,美团用户平台应用研发组不仅设计了能表达和管控各种复杂关系的权限模型,还针对事前、事中、事后等三个场景,分别设计了审批、权限、审计三个子系统以保障数据安全的完整闭环,进而满足数据安全的各种要求。功能应用类产品的权限表达,一般为“是否有权限”,而数据类产品权限表达的关系更加复杂。例如数据类产品的报表,不仅需要表达出用户能否访问这个报表,而且需要表达出用户能访问报表中的哪些维度、指标以及维值的范围。还需要告知这些维度指标来自于哪些库表模型,是否有权限访问以及创建报表。权限模型传统的权限模型有ACL(Access Control List)访问控制列表,RBAC(Role-Based Access Control)基于角色的访问控制等。以上模型比较适用于应用类型产品的权限管控,而数据类型的产品对信息安全的要求更高,而且各类资源间的关系也更复杂,使用传统的模型难以将内部关系进行清晰的表达,所以我们在RBAC权限模型的基础上,扩展设计了新的权限模型。如图2所示,传统的权限模型:ACL访问控制列表,用户与权限直接关联,直接维护用户与列表中资源的关系从而达到权限管控的目的。RBAC模型则是角色与权限进行关联,用户成为相应的角色而获得对应的权限。为什么要设计新的权限模型?ACL模型是用户与资源直接建立关系,没有角色的概念。当某些用户需要一批同样资源的权限时,赋权操作就变得很复杂,此时这种模型就不太适应了。RBAC模型引入了角色的概念,角色与资源建立关系。当某些用户需要一批同样资源的权限时,只需要构建一个角色并赋予使用这批资源的权限。当用户加入这个角色时,则拥有该角色的所有权限。解决了赋权操作复杂的问题。不过ACL模型和RBAC模型,都存在以下几个问题:数据类产品资源之间关系复杂,不能很好地表达这种复杂的关系。例如:一个报表下有多个标签页,一个标签页下有多个组件,一个组件下有多个维度、指标等。同时维度、指标又来自不同的数据模型、库表等。资源与资源之间存在关系,当管理员给一个用户赋予报表的全部或部分权限时,报表下的子资源需要同时获得对应的权限。RBAC模型中角色与角色之间没有对应的关系。例如:组织架构中,员工所在的组织架构如下:华东区/销售一区/销售一组,员工拥有的角色是销售一组的角色。当角色之间没有关系时,员工如果需要华东区角色的权限时,需要添加到华东区的角色中。而如果角色与角色之间具有从属关系时,则能很好地解决这个问题。新的权限模型是如何解决上面这些问题的:设计资源模型时,资源与资源之间具有从属关系,并且资源允许多层级,以树形结构展示。例如报表是一个父资源,标签、组件、维度指标都是报表下的子资源,这样赋权时能清晰地展示出报表资源与下面的子资源的关系,赋权和鉴权时才能满足各种权限控制的要求。角色与角色之间具有从属关系,例如员工在华东区/销售一区/销售一组的组织架构中,华东区/销售一区/销售一组这3个角色之间分别具有父子级的从属关系,当员工在销售一组部门下,则拥有华东区、销售一区、销售一组的所有权限。当权限不冲突时则直接合并所有权限,冲突时则以“就近原则”进行覆盖。如图3所示,新的权限模型包含3个部分,用户中心、资源中心、权限中心。用户中心:用户管理、角色管理角色分为个人、组织、自定义3种,一个用户可以同时拥有多个角色,比如用户默认对应一个个人角色,又可同时拥有在公司组织架构中组织角色、在自定义组织的自定义角色。角色支持多层级,满足角色间权限继承的表达方式。用户、部门信息Mafka(美团基于Kafka开发的一个分布式消息中间件综合解决方案)实时更新,每天ETL定时同步,保证人员入职、转岗、调离权限实时同步。资源中心:资源管理资源类型支持自定义,在通用资源类型的基础上支持自定义的资源接入,满足各个系统不同资源的统一管控。资源支持多层级,树形结构的资源展示方式便于资源的统一赋权鉴权;给一个报表资源赋权时,挂在报表下的维度、指标等资源能统一获得权限。支持资源打包简化赋权流程。资源安全密级、资源负责人,支持按照资源配置不同的审批模板进行权限自助申请。权限中心:角色与资源的关系的多种策略表达范围策略:例如报表中的平台维度的维值包括美团和大众点评,赋权时,支持按要求给用户赋予部分或全部权限;鉴权时,按照规则解析为某人拥有某维度的部分或全部权限。表达式策略:当把报表给用户赋权时,设置表达式为limit 10,表示当前用户在该报表其他权限的基础上再进行限制,只能返回前10条记录。权限自动合并:一个用户拥有多个角色,多角色的同一资源的权限鉴权时按照规则自动合并;规则解析时,权限数据不冲突时取合集,冲突时按照优先级取对应的值。黑白名单:支持按照特定的规则,对某人针对某资源全面开发和封禁,黑白名单策略的优先级最高,其中黑名单高于白名单。挑战在建设数据安全平台的过程中,主要面临以下几点挑战:随着支持的业务线增加,通用平台的不能满足各个业务线的定制需求时,需要保证系统的灵活可扩展。提供一个通用的数据安全平台,满足大部分的数据安全的要求,保证系统的通用性。权限系统作为一个高QPS访问的系统,如何保证系统的高可用。解决思路提供灵活可插拔的Plugin服务,在通用权限基础上,满足各个业务线灵活的权限管控要求。提供一个通用的数据安全平台,满足基本的权限、审批、审计的基础功能。微服务架构、核心与非核心服务分离、数据缓存降级满足系统高可用。解决方案如图7所示,将军令分3块,数据内容权限平台、审批流平台、审计日志平台:提供各种灵活可插拔的Plugin服务,支持在通用服务的基础基础上进行定制开发。提供基础服务,满足各种通用的数据安全要求。提供管理工作台,支持管理员对各种数据和规则进行页面管理和配置。具体方案Plugin服务层,保证系统灵活可扩展在满足通用权限的基础上,各个业务线难免会有定制的权限管控需求,于是设计了权限Plugin模块。通用服务提供用户管理、资源管理、鉴权授权的服务,Plugin调用基础服务实现特殊的权限管控。Plugin模块的应用和数据各自单独管理,通过RPC方式调用通用服务实现灵活可插拔。后续Plugin模块的服务支持各个接入的应用单独定制开发。如图8所示,通用权限的服务与Plugin的服务是分离的,支持多个Plugin服务灵活可插拔:通用服务提供用户、资源、鉴权授权等通用服务,大部分的系统基于通用服务即可实现权限管控要求。Plugin服务基于通用服务对外提供的SDK进行拓展,各个Plugin服务单独部署,保证系统之间互相独立。最终的权限实现分层管控,分为核心数据层(用户、资源、权限数据)和应用层。核心数据层的数据由通用服务进行管理,达到权限数据统一管控的要求。应用层以Plugin服务方式接入,Plugin通过通用服务层对外的SDK进行权限数据读写,达到定制的管控要求。应用层的数据各自存储,可以自定义管控规则。接口之间的调用通过BA认证鉴权,保证服务之间调用的安全性。基础服务层,保证系统通用性通用权限系统架构使用微服务架构设计,系统分为接入层、服务层、数据库层、以及外部服务层。主要包含以下几个核心服务:用户服务:主要包含用户和部门信息同步、角色管理。资源服务:包含资源注册、资源定时同步、资源密级及管理员管理、资源包管理。赋权服务:权限自助申请、管理员赋权。鉴权服务:提供各种鉴权的SDK供使用方调用。如图9所示:接入层:对外所有系统通过统一的SDK调用服务。服务层:微服务架构,各个服务之间互相之间提供服务。数据库层:合理利用缓存、数据降级,保证服务高可用。集成公司公共服务,保证系统稳健运行。审批系统架构提供通用的审批服务,提供多级审批模板,使用时选择模板启动审批流,审批系统按照启动的参数进行规则解析,自动适配对应的审批流程。缩减接入流程支持一键接入。如图10所示:优化审批接入流程,提供通用的审批服务,减少系统接入开发成本:前期开发一个审批功能需要6个步骤,绘制流程图,配置审批的组和成员,配置通知的消息,配置事件映射,启动审批流,开发回调接口改状态。而我们在平台的审批服务基础上进行封装,提供通用的审批模板,接入审批系统只需要选择模板启动审批流,并提供回调接口即可。能满足大部分的审批功能。提供通用的规则解析引擎,支持审批人、审批条件、审批通知按照规则动态解析匹配。灵活实现自动审批、多人多级审批、定时催办等多种通用功能。对接权限和审计系统,保证审批系统数据安全:对接权限系统,提供管理员权限管控。对接审计系统,操作数据落到审计系统便于后续的数据审计。审计系统架构提供通用的数据审计服务,客户端日志埋点上报,审计日志按类型落到Elasticsearch中存储。对接如意可视化报表出审计报告,对接权限系统管控数据权限。如图11所示:审计数据模型层支持自动扩展:每个应用对应一个appkey,每个appkey按照模板分日期自动创建一个索引,支持自动扩展。每种类型的审计日志对应Elasticsearch索引中的一个type,新增一种操作日志时,type自动创建。审计日志中的字段对应type中的字段,新增字段时自动扩展。保证系统高可用微服务架构服务分离随着系统的模块功能越来越多,单一架构模式已不再适合敏捷开发,模块越来越大系统启动则越慢,任一模块出错则整个系统的服务都不可用。为了保证服务的高可用和扩展性,于是以微服务架构把模块进行拆分,并把核心与非核心服务进行分离。如图12所示:前端接入层通过HTTP接入,BA认证校验请求合法性,通过Nginx负载均衡。管理控制台,通过调用服务层的各个服务实现统一管理。服务层,抽象系统各个模块,每个模块都是一个微服务,每一个微服务都独立部署,可以根据每个服务的规模按需部署。Client层,对外提供统一的Pigeon(美团内部分布式服务RPC通信框架)接口,通过POM引入调用服务层各个服务。权限继承由于资源支持多层级,设计权限模型时支持权限继承,当赋权时开启继承,则用户默认拥有该资源以及下面所有资源的全部权限,数据存储时只需要存储祖先资源与用户之间的关系。大大减少了权限矩阵大小。权限数据存储接入的系统越多,则资源和用户就越多。随着系统运行越久,对应的权限数据也会随之快速增长。如何在数据增长的同时保证接口的性能和高可用。权限备份与恢复参照HBase的版本号和MySQL的Binlog的设计思路,赋权时权限只存储当前用户最新权限数据,历史权限数据和操作记录用版本号的方式存储到Elasticsearch中。用户鉴权时只需要查询MySQL的权限数据即可,保证鉴权接口的高效性。如图14所示:赋权操作时,通过版本号管理权限数据,每次操作后版本号加1,MySQL和Redis中只存储最新的权限数据。历史权限数据通过版本号的方式存储到Elasticsearch中,每次查看历史操作记录或恢复权限数据时,根据版本号回溯即可。权限过期清理通过Crane定时调度,根据配置的通知规则,扫描即将过期的权限数据,发送消息通知用户进行权限续期。扫描已过期的权限数据,清理MySQL和Redis中的过期权限数据,并转储到Elasticsearch中保存,已备后续的权限审计。数据读写分离、缓存、备份以及服务熔断降级各个服务使用MySQL分库存储,使用Zebra(美团数据库访问层中间件)进行读写分离;合理使用数据缓存与备份,并支持服务的熔断降级,以保证服务的高可用。如图15所示:各个服务使用MySQL分库存储;核心服务与非核心服务分离,服务和数据库支持按需弹性拓展。角色、资源等热点数据使用Redis做缓存,并在Redis缓存不可用时自动下沉到MySQL进行查询。操作记录和历史数据等不活跃数据落地到Elasticsearch,以便审计和数据恢复。服务不可用时支持熔断降级,以保证核心服务的可用性。合理使用消息队列、任务调度、线程池、分布式锁使用消息队列、任务调度、线程池进行异步、削峰、解耦合,减少服务响应时间,提升用户体验。并使用分布式锁保证数据一致性。如图16所示:使用消息队列处理用户请求,实时返回操作成功,后台根据接受到的MQ消息异步进行处理并修改状态,页面轮询状态展示最终结果或发送大象(美团内部通讯工具)消息进行最终结果推送。需要定时同步的任务通过Crane分布式任务调度平台进行定时调度执行。审批回调时使用线程池处理审批结果回调与失败重试,较少创建销毁线程的开销。分布式锁,保证同一个方法在同一操作上只能被一台机器上的一个线程执行,避免用户重复提交或者多机器重复处理导致的数据不一致。展望作为一个通用的数据安全平台,各个业务线的各种定制需求不可能都满足。目前在系统架构上已支持提供多个可插拔的Plugin服务,在通用服务的基础上实现定制的权限管控。后续将军令将针对权限、审批、审计提供Plugin开发规范,支持接入的系统在现有的基础上进行定制开发。如图17所示:后续将对外提供统一的Plugin开发规范,支持各个接入方系统以Plugin服务的形式在平台基础服务之上进行定制开发,以满足各自的特殊权限管控要求。从而实现数据产品权限集中管控确保数据安全。把将军令中的规则从现有的服务中分离出来,抽象出一个通用的规则引擎服务,实现规则灵活可配置。作者简介夷山,美团点评技术专家,现任TechClub-Java俱乐部主席,2006年毕业于武汉大学,先后就职于IBM、用友、风行以及阿里。2014年加入美团,长期致力于BI工具、数据安全与数据质量工作等方向。中华,美团点评数据系统研发工程师,2017年加入美团点评数据中心,长期从事于BI工具、数据安全相关工作。招聘信息最后插播一个招聘广告,有对数据产品工具开发感兴趣的可以发邮件给 fuyishan#meituan.com。我们是一群擅长大数据领域数据工具,数据治理,智能数据应用架构设计及产品研发的工程师。欢迎加入美团大数据技术交流群,跟作者零距离交流。进群方式:请加美美同学微信(微信号:MTDPtech02),回复:数据安全,美美会自动拉你进群。

February 15, 2019 · 1 min · jiezi

MySQL按时间统计数据

背景在做数据库的统计时,经常会需要根据年、月、日来统计数据,然后配合echarts来制作可视化效果。数据库:MySQL思路按照时间维度进行统计的前提是需要数据库中有保留时间信息,建议是使用MySQL自带的datetime类型来记录时间。timestamp datetime DEFAULT NULL,在MySQL中对于时间日期的处理的函数主要是DATE_FORMAT(date,format)。可用的参数如下格式描述%a缩写星期名%b缩写月名%c月,数值%D带有英文前缀的月中的天%d月的天,数值(00-31)%e月的天,数值(0-31)%f微秒%H小时 (00-23)%h小时 (01-12)%I小时 (01-12)%i分钟,数值(00-59)%j年的天 (001-366)%k小时 (0-23)%l小时 (1-12)%M月名%m月,数值(00-12)%pAM 或 PM%r时间,12-小时(hh:mm:ss AM 或 PM)%S秒(00-59)%s秒(00-59)%T时间, 24-小时 (hh:mm:ss)%U周 (00-53) 星期日是一周的第一天%u周 (00-53) 星期一是一周的第一天%V周 (01-53) 星期日是一周的第一天,与 %X 使用%v周 (01-53) 星期一是一周的第一天,与 %x 使用%W星期名%w周的天 (0=星期日, 6=星期六)%X年,其中的星期日是周的第一天,4 位,与 %V 使用%x年,其中的星期一是周的第一天,4 位,与 %v 使用%Y年,4 位%y年,2 位注:当涉及到按日统计是,需要使用%j,而如果使用%d, %e, %w的话,那么不同月份/周里的相同值会统计在一起。涉及到获取当前时间,则可以通过now()或者sysdate()来获取。SELECT SYSDATE() FROM DUAL;SELECT NOW() FROM DUAL;按照实际需求使用group by查询即可。结论需统计的表结构如下:CREATE TABLE apilog ( id int(11) NOT NULL AUTO_INCREMENT, username varchar(64) DEFAULT NULL, action varchar(64) DEFAULT NULL, params text, result text, timestamp datetime DEFAULT NULL, PRIMARY KEY (id)) 统计时间范围内不同分类action的数量# 当日SELECT action, COUNT(id) count FROM apilog WHERE DATE_FORMAT(timestamp,’%j’) = DATE_FORMAT(now(),’%j’) ORDER BY count desc;# 当周SELECT action, COUNT(id) count FROM apilog WHERE DATE_FORMAT(timestamp,’%u’) = DATE_FORMAT(now(),’%u’) ORDER BY count desc;# 当月SELECT action, COUNT(id) count FROM apilog WHERE DATE_FORMAT(timestamp,’%m’) = DATE_FORMAT(now(),’%m’) ORDER BY count desc;# 当年SELECT action, COUNT(id) count FROM apilog WHERE DATE_FORMAT(timestamp,’%Y’) = DATE_FORMAT(now(),’%Y’) ORDER BY count desc;统计某分类action的时间维度数量# 按日SELECT action, DATE_FORMAT(timestamp,’%j’), COUNT(id) count FROM apilog WHERE action = ‘xxx’ GROUP BY DATE_FORMAT(timestamp,’%j’)# 按周SELECT action, DATE_FORMAT(timestamp,’%u’), COUNT(id) count FROM apilog WHERE action = ‘xxx’ GROUP BY DATE_FORMAT(timestamp,’%u’)# 按月SELECT action, DATE_FORMAT(timestamp,’%m’), COUNT(id) count FROM apilog WHERE action = ‘xxx’ GROUP BY DATE_FORMAT(timestamp,’%m’)# 按年SELECT action, DATE_FORMAT(timestamp,’%Y’), COUNT(id) count FROM apilog WHERE action = ‘xxx’ GROUP BY DATE_FORMAT(timestamp,’%Y’)同时按action和时间维度统计# 按日SELECT action, DATE_FORMAT(timestamp,’%j’), COUNT(id) count FROM apilog GROUP BY action, DATE_FORMAT(timestamp,’%j’)# 按周SELECT action, DATE_FORMAT(timestamp,’%u’), COUNT(id) count FROM apilog GROUP BY action, DATE_FORMAT(timestamp,’%u’)# 按月SELECT action, DATE_FORMAT(timestamp,’%m’), COUNT(id) count FROM apilog GROUP BY action, DATE_FORMAT(timestamp,’%m’)# 按年SELECT action, DATE_FORMAT(timestamp,’%Y’), COUNT(id) count FROM apilog GROUP BY action, DATE_FORMAT(timestamp,’%Y’)以上就是比较常用的时间统计了,更多的时间维度,可以参考上面的参数表类似处理即可。 ...

January 31, 2019 · 2 min · jiezi

数据科学真的是一份有前途的工作吗?

本篇文章翻译整理自Sethuraman Janardhanan博士的演讲。 Sethuraman Janardhanan博士,Happiest Minds Technologies的大数据分析实践主管和客户负责人,负责管理北美大数据分析领域的战略客户。由于无处不在的计算设备和新时代的颠覆性技术的革命,大数据已成为业务中不可或缺的一部分。数据的指数级增长为企业提供了商业智能的巨大机会。然而,大数据的挑战在于收集,隔离,分析和推导可操作的商业智能和来自大量结构化和非结构化数据的见解。具有强大技术背景,在计算机编程,数学和统计方面具有强大技能的专业人士,可以处理大量数据,清理,组织和获得有意义的见解并在业务中实施它们。组织逐渐意识到数据在商业中的重要性,并且正在见证市场对数据科学专业人员的巨大需求。毫无疑问,数据科学被“哈佛商业评论”评为21世纪最热门的领域之一。麦肯锡的一项研究报告称,“到2018年,美国将缺少190,000名技术熟练的数据科学家,150万经理和分析师能够从大数据洪流中获取可行的见解”。从印度来看,我们可以看到组织内部对大数据和数据科学的极大兴奋。印度公司已开始寻找能够为其业务增值的合格数据科学专业人士。然而,目前在大数据和数据科学领域存在巨大的需求 - 供应不匹配。由于每个业务部门和行业都确定了大数据分析的相关性并希望在竞争中保持领先地位,因此对数据科学专业人员的需求将呈上升趋势。数据科学家作为价值加法器数据科学家解决了企业可能面临的一些最棘手的问题,并且几乎涉及所有业务领域。下面简单为大家介绍数据科学家如何在各个行业领域增加价值。营销 - 在营销业务中,数据科学家可以利用大量数据来优化营销支出并提高其广告系列的投资回报率,从而提高广告系列的响应率。银行业 -在银行业的舞台上,风险职能部门的数据分析师可以利用大数据识别欺诈活动,并采取富有洞察力的措施全面覆盖风险。零售 -数字和电子商务运营是应用大数据分析进行业务优化的前沿。数据科学家可以在该领域中发挥重要作用,分析通过各种手段收集的消费者数据,从而识别客户行为。根据分析,零售商可以提供有针对性的个性化建议,以帮助增加客流量,从而提高销售转化率。制造业 -数据科学也在制造业中发挥着重要作用。通过利用他们的技能,数据科学家可以预测产品需求并优化业务的库存供应链。数据科学职业前景和技能虽然编程技能和统计专业知识被认为是任何数据科学家的基础,但强大的商业头脑有助于他们在正确的轨道上驾驭他们的职业生涯。然而,随着数据科学日益成熟,以及围绕大数据的业务需求的变化,对数据科学家的技能和能力的期望也在不断提高。随着机器学习,深度学习,高级分析和认知计算之间相关性越来越大,这一要求已从传统的商业数据科学家转变为先进的机器数据科学家。业务数据科学家理解业务,并基于通过适当的工具或框架从不同源获得的数据构建数据模型。他们发现隐藏的洞察力来解决商业问题或提供竞争优势。然而,就机器数据科学家而言,除了弄清楚隐藏的见解之外,这些对系统的见解的实施也是他们的责任。以前,工商管理和数学、统计技能主要适用于数据科学专业人员。然而,机器数据科学家的理想技能是深入的编程技能,深入的分析技能,机器学习技术和统计技能以及强大的商业敏锐性。分析问题解决,求知欲,行业知识,批判性思维,有效的沟通和数据科学与分析认证将是额外的优势。SAS和SPSS是商业数据科学专业人员必须了解的主要技术。Java,Python,Scala是大数据应用程序中最常用的编程语言。对于机器数据科学家来说,所需的技能包括编程语言知识,Hadoop,Hive,Spark,用于构建自定义模型和算法。此外,数据科学专业人员应熟悉SQL知识,因为大多数企业数据都存储在数据仓库中。对有抱负的数据科学专业人士的建议●深入学习一种编程语言●培养您的SQL技能和数据准备技能●完成统计建模和算法技能●与实施它的工具和技术相媲美对于数据科学专业人员而言,在履行其工作的主要职责(包括数据准备,统计建模和算法开发,Insight生成)时,关注业务成果同样重要。以及在业务中部署见解。数据科学的未来前景随着数据科学成为业务增长和成功的关键推动因素,每个公司的CXO都无论需求量大,都需要拥有足够数量的数据科学专业人员。未来的CXO将在未来十年内将数据科学作为理解高级模式和趋势的关键要求。根据印度经济的实力以及庞大的人才储备,印度在未来几天可以在培养数据科学专业人员方面占据重要位置。然而,从组织方面以及印度大学方面采取更周到的步骤和及时的行动计划是时间的需要。机会是无限的,数据科学将成为未来五年中最受追捧和最高薪的职业之一。每个行业和职能部门都将数据科学嵌入其运营中。总而言之,题为“2016年4月数据科学家工资”的Burtch Works研究报告“数据科学家的基本工资中位数随着个人贡献者和管理者的工作水平而增加。1级个人贡献者的基本工资是其他IT专业人员的1.5到2倍。对于经理而言,与IT经理相比,这些薪资水平可高达3倍。“原文地址:https://medium.com/@humancapi…翻译:网易云信想要阅读更多技术干货文章,欢迎关注网易云信博客。了解网易云信,来自网易核心架构的通信与视频云服务。网易云信(NeteaseYunXin)是集网易18年IM以及音视频技术打造的PaaS服务产品,来自网易核心技术架构的通信与视频云服务,稳定易用且功能全面,致力于提供全球领先的技术能力和场景化解决方案。开发者通过集成客户端SDK和云端OPEN API,即可快速实现包含IM、音视频通话、直播、点播、互动白板、短信等功能。

January 21, 2019 · 1 min · jiezi

模拟测试数据的生成方法

【摘要】许多程序员都头疼测试数据的模拟,一个是要逼真,另一个需要数据量,不逼真往往导致一些 bug 测不出来,数据量不够则无法发现性能问题,这篇文章给出了很好的解决办法。1)、应用系统或软件产品一般都需要进行不同阶段的验证工作,包括原型功能论证、功能测试、性能测试等,这些测试、论证场景都可能涉及到测试数据的准备。2)、根据用户的业务需求、数据预置约束条件、数据间层级关联等条件,生成对应的模拟验证数据。一般来说,按照用户要求模拟数据应该做到:数据量可控、充分的随机性、保持数据间特定的逻辑关联关系(包括直接关联或隐含关联)。3)、本文我们将介绍一个方便、灵活的模拟数据生成工具——集算器。去乾学院看个究竟吧! 模拟测试数据的生成方法模拟测试数据的生成方法应用系统或软件产品一般都需要进行不同阶段的验证工作,包括原型功能论证、功能测试、性能测试等,这些测试、论证场景都可能涉及到测试数据的准备。测试数据有时可以直接复用历史数据,但很多情况下,基于历史数据建立的测试数据可能会出现内容缺失不全、数据量级不够、数据涉密不能导出、数据已加密无法参与计算等情况,这时就需要根据用户的业务需求、数据预置约束条件、数据间层级关联等条件,生成对应的模拟验证数据。一般来说,按照用户要求模拟数据应该做到:数据量可控、充分的随机性、保持数据间特定的逻辑关联关系(包括直接关联或隐含关联)。单数据表是最常见的数据模拟情况,这种表由主键和普通字段组成,也可以由无主键的普通字段组成。在单数据表的基础上,可以进一步进行多数据表的关联模拟,关联关系可以归类分为:外键关联、同维关联、主子关联。对于关联数据生成的原则具体可参见《怎样生成有关联的测试数据》一文。对于已经生成的数据,则可以参考《优化 Join运算的系列方法》对模拟生成的数据进行更进一步地深入查询和分析处理。一般来说,单数据表模拟数据的难点是对数据表字段内容的灵活生成。而多数据表模拟则是在此基础上考虑关联关系(一层或多层)的生成,尤其是需要保证多数据表在进行关联过滤之后,还能够有充足、有效的结果数据,从而满足数据的关联运算或是其它展现需求。实际情况中,通过编程生成这些模拟验证数据的难点通常是数据间复杂的逻辑关联关系。本文中,我们将介绍一个方便、灵活的模拟数据生成工具——集算器。集算器是一款面向应用程序员和数据分析员,专注于结构化数据分析与处理的快速开发工具,是一套基于 Java 解释执行的动态语言,采用了先进的计算模型和设计思想,让开发更易于实现、性能更好。同时,集算器还具备完备的类库和轻量级架构,足以让数据模拟生成更加灵活和高效。一、 引言集算器具有跨平台、无框架、易部署的特点,仅需要安装有JAVA虚拟机的操作系统即可,特别是对于数据模拟生成的过程,可以随时分步调试查看中间过程数据。集算器使用SPL程序语言。SPL(Structured Process Language)是一种面向(半)结构化数据计算的程序设计语言,能够满足复杂处理和过程计算的数据处理需求。同时,集算器还可以直接将模拟生成的数据落地在本地磁盘的二进制“集文件”(集算器自定义的一种文件格式)中,免去繁琐的安装数据库的操作,这也符合模拟测试相对临时性的工作特点。集文件本身具有使用简单、可追加、支持大数据、可分段并行等特点,而且很容易转成其它格式,如数据库、文本等。当然,集算器自身也支持直接或通过集文件将模拟数据导入到任意目标数据库中,所需的具体外部库的使用可以参见《外部库》函数参考章节。为了方便叙述和验证,本文默认模拟生成的数据均落地在本地集文件中。1、 为什么使用集文件?在用集算器生成模拟数据时,常用两种文件格式:文本文件和集文件。文本是各种数据平台 / 数据库都支持的文件格式,具有良好的通用性。但文本文件的查询性能较差,占用磁盘空间也较大,而且缺少字段的数据类型定义,有时可能会出现“类型歧义”的错误。针对这些问题,集算器设计了一种二进制格式文件,称为集文件(文件后缀 btx)。集文件中使用了低 CPU 消耗的压缩编码,数据存储时较文本文件占用磁盘空间更小,具有较高的查询性能,并且字段的数据类型也被存储,避免出现类型歧义。同时,集文件继承了文本文件支持大数据量、可追加和易于分段并行的特点。因此,在需要使用数据文件时,集文件是更好的选择。2、 如何使用集文件?利用集文件存储模拟生成的数据,因为其具有与其它数据格式广泛的互通性,后续就可以灵活进行与目标数据源的双向转化,包括 Oracle、DB2、MS SQL、MySQL、PG 等关系型数据库和 TXT/CSV、JSON/XML、EXCEL 等文件类型。下面首先针对常用的文本文件、MySQL进行双向互转的说明。1) 集文件与文本文件互转 集文件可以与文本文件进行互相转换,相应的SPL实现脚本示例如下:A1:导入文本文件数据。使用cursor@t()游标方式读入“文本.txt”文件数据,其中 @t 指定将第一行记录作为字段名,如果不使用 @t 选项就会以_1,_2,…作为字段名。A2:使用循环函数,将文本数据循环追加到集文件中。使用export@ab()将文本数据导出到集文件中,其中,@a 表示追加写数据到集文件, 如果不用 @a 就表示重建集文件,@b 表示导出为集文件。在集算器中可以直接查看生成的“文本转集文件.btx”文件数据结果,如下图所示:A3:导入集文件数据。使用cursor@b()游标方式读入“集文件.btx”,其中 @b 表示将导入的是集文件。A4:使用循环函数,将集文件数据循环追加到文本文件中。export@t()将指定单元格的数据导出到文本文件中,其中,@a 表示追加写数据到文本文件中, 不用 @a 则表示重建文本文件,@t表示将集文件的字段名作为第一条记录写入文本文件。查看生成的“集文件转文本数据.txt”文本文件数据结果,如下图所示:2) 集文件与 MySQL 互转集文件也可以与MySQL之间进行数据互转,相应的SPL脚本也很简单。下例将MySQL数据库employeeinfo表中的数据导出到集文件中:A1:连接 MySQL 数据源,使用connect()进行 MySQL 数据库的连接。如果用鼠标点击 A1 单元格,可以直接查看 MySQL 数据库的连接信息。具体查看数据库配置教程相关章节文档的配置说明。A2:游标读取 MySQL 中 employeeinfo 表数据。A3:使用循环函数,将 A2读出的数据循环追加到集文件中。使用export@az()将文本数据导出到集文件中,其中,@a 表示追加写数据到集文件中, 如果不用 @a 则表示重建集文件,@z是将数据强制导出集文件,注意,这里用了 @z 而不是前面的 @b,事实上 @z 会强制导出集文件(和 @b 效果一样),同时还可以通过表达式 export@z(A2;s) 增加 s 选项作为分组表达式,s对于文本文件为自选分隔符, 缺省默认分隔符是 tab,有 s 参数时认为 A2 文本数据对 s 有序,仅在 s 变化时才分段,这种设置分段的集文件用于并行数据量大时的分段导出, 导出时同一段的记录不会被拆开。缺省情况下不分段导出“文本转集文件.btx”集文件。同样,在集算器中可以直接查看生成的“MySQL集文件.btx”文件数据结果,如下图所示:A4:使用close()函数关闭 A1 建立起的 MySQL 数据源连接。下例则是将集文件中的数据插入到MySQL数据库employeeinfo表中:A1:连接 MySQL 数据源。使用connect()进行 MySQL 数据库的连接。如果用鼠标点击 A1 单元格,可以直接查看 MySQL 数据库的连接信息。具体查看数据库配置教程相关章节文档的配置说明。A2:游标方式导入集文件的数据。集文件数据使用cursor@b()将以游标方式读取,其中包含数据表字段:empid 和 other。A3:更新 MySQL 数据库“employeeinfo”库表中的数据。使用update()将单元格 A2 通过游标读取的集文件数据更新到 MySQL 数据库“employeeinfo”库表中。A4:使用close()函数关闭 A1 建立起的 MySQL 数据源连接。使用第三方工具查看 MySQL 数据库的“employeeinfo”库表,插入的数据结果如下截图所示:二、 模拟生成字段数据在开始单数据表模拟之前,我们先了解一下通过SPL脚本处理主键字段和普通字段的方法。1、 主键字段数据的模拟生成主键字段最典型的要求就是模拟生成的数值不能重复,另外可能会要求一定的顺序、范围、格式要求。1) 数值自增对于主键字段,常见的要求就是字段值唯一、不重复,且自增:A1:新建导出的集文件。A2:定义模拟生成的数据量。A3:批量模拟生成数据。其中empid是模拟数据表的主键数值自增字段。使用“#”序号值直接设置主键empid的自增数值,使用rand()函数生成 0-100000 内的随机数模拟 other 字段。A4:将单元格 A3 生成的数据导出到 A1 的新建集文件中。使用export@b()将数据追加写入到 btx 集文件数据中,其中, @b 表示导出集文件格式。点击 A1 单元格生成的“数据自增表.btx”集文件,查看文件数据结果如下:2) 在规定数据范围内取值且不重复主键字段也可以是某个规定范围内不重复的数值,比如从110000中批量取1000个不重复的数值作为主键字段,SPL脚本如下:A1:模拟数据范围 nA2:模拟需要获取的数据数量 m。A3:数据范围 n 不大时获取 m 个不重复数值的方法。如果n不大,那么对于包含 n 个成员的集合排序很快,这时可以先用 to() 函数生成一个从 1 到 n 的序列,然后使用sort()函数基于rand()函数生成的随机数直接将这个序列的成员顺序随机打乱,然后再通过to()获取 m 个不重复数值。查看单元格 A3 的结果,如下图所示:A4:如果数据范围n很大,那么对个成员的集合排序就会比较慢,因此就不能使用 A3 的方法了。我们的做法是在数据范围 n 内随机获取 m1.1 个数值,然后使用 id() 函数将这 m1.1 个随机获取的数据去重。由于随机取数可能会有重复,如果只取 m 个,去重后就会少于 m 个,所以这里定义了一个系数 1.1,适当多取几个,确保在去重后,剩余数量多于 m 个。然后在 B4 中通过to()获取其中的 m 个。查看单元格 A4 的结果,如下图所示,一共取得了 1044 个不重复的数(有 56 个重复被去重去掉了):再查看单元格 B4 的结果,如下图所示,正好是 1000 个:3) 字符串主键主键字段还有一种情况是由“特定编号 + 序号 / 随机数” (日期的情况暂不在此讨论)组成,也就是常见的编码形式,相应的SPL模拟脚本如下:A1:新建导出的集文件。其中将使用empid作为模拟数据表的字符串主键字段。A2:定义模拟生成的数据量。A3:批量模拟生成数据。使用字符串拼接出主键字段 empid。empid 由固定字符串“RAQ”标识、三位数序号,以及 10 位随机数拼接而成。其中,三位数序号字符串使用string()对获取的序号进行格式化处理,用“0”补足三位;用函数concat()将序列10.(rand(10))中的 10 个数字成员用无分隔符连接,拼接成 10 位随机数字组成的字符串。另外,依旧使用rand()函数生成 0-100000 内的随机数填入 other 字段。A4:将生成数据导出为集文件格式,与上例相同。点击 A1 单元格生成的“字符串编码表.btx”集文件查看文件数据结果,如下图所示:特别地,红框中标示的就是生成的三位序号字符串。4) 大数据量的流式追加生成上面的主键生成都不涉及复杂的主键字段生成,而且当小数据量时基本只要一行循环函数代码,全内存执行就可以了。但是当要求生成的数据量巨大,例如千万、亿级以上,或是生成的数据在内存中放不下的时候,我们就需要考虑分次生成追加记录了。这时候就需要用 for 循环进行显式控制,分批生成数据。每次流式写入多行,而不是一行一行写。下面我们看一下使用 SPL 编写脚本如何实现大数量的生成与处理:A1:新建导出的集文件。其中将用empid作为模拟数据表的字符串主键字段,用 other 作为普通字段。A2:定义生模拟生成的数据量和每次分批生成的数据。A3:循环生成数据,计算出分批生成数据的循环次数并进行循环。B4:按照单元格 A3 设定的循环分批生成具体数据,其中使用“(A3-1)*C2+”生成主键序号。B5-B6:将大据量分批流式写入集文件格式,并清空分批的临时数据。使用export@ab()将生成的数据流式追加写入到集文件,@a 表示追加数据,@b 表示导出集文件格式。最后,在单元格 B6 中使用 null 清空单元格 B4 中的数据。例子中单元格 A3-B6 四行代码,实现了大数据的分批流式追加写入,能够有效防止内存溢出。查看生成的 1 千万数据量的"大数据量的流式追加生成.btx" 集文件的数据内容,如下图所示:2、 普通字段数据的模拟生成1) 常规日期SPL对日期时间的处理提供了丰富的函数支持,详见日期时间函数参考,下面是两个例子。A1:获取当前年份的第一天日期。使用 now() 函数获取当前系统时间,使用 year 获取年份,使用date(year,month,day)函数获取年份的第 1 天日期。A2:随机生成指定年份的日期。使用elapse()函数计算相差某个时间的新日期数据,即与新年第一天相差 n 天的日期。其中,days@y()是获得指定日期所在年的天数。点击 A2 单元格,可以看到某次运行的数据结果是:2) 规定数据范围可重复的值模拟的字段在规定数据范围内随机取值,由于是非主键字段,值可以重复,如下例所示:A1:随机生成一个 10 位数字的字符串。查看某次运行结果为:A2:在字符 0-9 之间随机生成 10 位数字的字符串。这里使用rands()函数取得一个随机字符串。从结果看 A2 与 A1 的结果都是生成 10 位显示数字的字符串,可以根据实际需求对生成的结果值进行数据类型转换处理,如:字符串转数值等。A3A6:在行政区划中随机取值,其中:A3:导入本地包含“行政区划代码”数据的文本文件。查看该表数据可以看到包含 id 编号和区域名称。A4:使用len()函数获取行政区划代码数据表长度,然后在此范围内随机获取一个序号。A5:根据 A4 的序号返回 A3 的“行政区划代码”数据表的指定位置的 id 数据。A6:获取指定位置数据的 id 字段值。3) 字段拆分与组合某些字段的构成需要遵循一定的编码规则,例如身份证号码,我们通过公民身份证号码可以很直接的获取一个人所在的地区、出生日期、性别,并计算出年龄。这里就以此为例对字段的拆分和组合做详细的说明,其它类似的情况可以以此为参考。:公民身份证号码是特征组合码,由十七位数字本体码和一位校验码组成。排列顺序从左至右依次为:六位数字地址码,八位数字出生日期码,三位数字顺序码和一位数字校验码。具体数据特征和约束如下:l 地址码:编码对象常住户口所在县级(市、旗、区)行政区划代码,按 GB/T2260 标准执行。l 出生日期码:编码对象出生的年、月、日,按 GB/T7408 标准执行,年、月、日之间不用分隔符。l 顺序码:在同一地址码所标识的区域范围内,对同年、同月、同日出生的人编定的顺序号,其中奇数分配给男性,偶数分配给女性。l 校验码:根据前面十七位数字码,按照 ISO 7064:1983.MOD 11-2 校验码计算出来的检验码。模拟生成身份证编码的SPL脚本如下:A1:导入本地 txt 文本文件,其中包含“行政区划代码”数据。A2-A4:随机生成“行政区划代码”数据表范围内的数据位置序号。并按照位置序号获取对应的所在区域。A5:随机取得三位数字组成的顺序码字符串,偶数代表女,奇数代表男。A6-A7:按照标准编码规则和计算公式,设置计算系数和校验码。A8:字符串拼接组合身份证号码的前三组的字符串,即:地址码+出生日期码+顺序码。A9-A11:按照身份证号码的标准计算公式,拆分字符串系数和校验码,计算出对应的一组校验码。A12:返回身份证号,行政区域代码 + 出生日期 + 三位顺序码 + 一位校验码,特别地,校验码已包含 X 的情况,这个是根据校验码生成规则自动生成的一个身份证编码:这个例子中利用了对字符串的拆分和组合,轻松实现了自动生成合法身份证号码的程序。4) 序列与字符串的转换这里补充一个小知识点,在处理字符串时,一方面可能需要将一个序列的值组合成一个字符串,另一方面又可能把一个字符串按照分隔符拆分成序列。SPL 中可以通过split()和concat()两个函数,很方便地实现序列和字串的相互转化,以便进一步计算。其中,函数 s.split(d) 用来将字串 s 以分隔符 d 拆分成序列。函数 A.concat(d) 用来将序列 A 用分隔符 d 连接,拼接成字串,自动处理数据类型。两个函数中都可以通过不同的选项进行控制,例如 @c 选项,表示以逗号为分隔符,下面是几个例子:A1:输入字符串。A2:将 A1 的字符串以逗号为分隔符转化为序列。查看运行结果为: A3:将 A2 的序列以逗号为分隔符转化为字符串。查看运行结果为: 这个技巧在后面常规单数据表模拟的例子中有具体的应用。5) 普通字段列自动扩展在进行数据表模拟时,还可能需要模拟一些非必要的普通字段,这些字段可能记录了一些属性数值,也可能是空值,但在模拟数据查询时又是不可缺少的。SPL 提供了非常简便的方法,可以自动批量扩展出一些字段,快速填充:A1:创建一个数据表,其中 empID 是主键,other1-other6 字段就是需要批量模拟生成的字段。A2:循环扩展出 6 个随机取数函数,并转换为字符串。查看运行结果为:A3:将模拟的数据插入到 A1 数据表中。其中,使用${A2}动态进行宏运算,也就是将 A2 的字符串表达式作为宏进行动态计算,得到的随机数作为 insert() 函数中的参数。当然,这一步也可以手工直接一个一个写出来。查看运行结果为:三、 模拟生成单数据表1、 常规单数据表模拟通常,我们做模拟测试或是功能验证,都是模拟一个单一的大宽数据表,需要的数据字段全部都在一个单数据表中,既方便数据过滤查询,也相对容易生成。现在我们就利用前面介绍的技巧,使用SPL生成一个大数据量的单数据表模拟数据,一个“员工登记表”的测试用数据。数据表结构如下:模拟数据的生成规则:l 按照数据表生成对应信息,包括:员工编号、姓名、身份证号码、性别、出生日期、所在区域、其它1…其它12等信息。l 各字段的生成规则:n 【员工编号】是依次产生(主键);n 【姓名】、【身份证号码】、【性别】、【出生日期】随机生成;n 【身份证号码】的隐藏条件是与【出生日期】和【性别】对应,即身份证号中的日期与【出生日期】相同,最右一位的顺序码与【性别】对应(奇数是男性,偶数是女性),n 同时还需要保证【出生日期】模拟的员工年龄应在1865岁之间;n 【所在区域】从固定范围数据表中随机获取;n 【其它1】…【其它12】模拟非必要条件的常规备用字段。l 生成数据量:要求至少生成1000万条模拟数据。以下是相应的SPL脚本:A1-A2:从本地文件中导入人员登记表必要的字典表。包括:自动生成人员姓名需要的“姓氏.txt”、“男名.txt”、“女名.txt”和生成身份证需要的“行政区划代码.txt”数据。A3:创建集文件“人员登记表.btx”,用于导出生成的模拟数据。A4:创建临时人员登记表。A5:设置模拟生成大数据的总量,这里按照要求设置 1 千万,B5 设置每次流式追加写入 btx 集文件的数据量,控制内存占用,避免内存溢出。A6-A21:按照生成数据量的要求循环生成 1 千万的数据,并存入集文件“人员登记表.btx”中。其中使用的一些函数在上面都有介绍,这里就不再赘述。特别地,需要说一下单元格 B20,用 if 判断单元格 A4 临时表的数据长度是否大于等于 B5 设置的 10 万或是当前 A6 单元格的循环数值等于 A5 设置的阈值,如果条件符合为 true,在单元格 C20 使用export@ab()流式写入追加 btx 集文件数据。最后,在单元格 C21 中使用reset()清空 A4 序表成员数据并保留创建的数据结构。使用类似分页的流式追加数据,可以有效应对大数据量模拟数据生成的场景,可以避免在数据生成过程中占用大量的 JVM 内存,有效避免 JVM 内存溢出。【注意事项:】如果要查看生成的人员登记表的集文件数据,在集算器安装包中,提供了集文件浏览器,可以在集算器安装目录的 esProc\bin 路径下,运行,查看集文件。使用 BTX 集文件浏览器打开有 1 千万条数据量的“人员登记表.btx”集文件,可以看到数据内容如下:2、 机构树型数据表模拟上面介绍的生成大数据量常规单数据表模拟数据的例子,是数据从无到有的情况,还有一种情况是已有基础数据,需要基于基础数据按照规则生成新的模拟数据。事实上:上述的场景中,已经利用了已有的“行政区划代码”数据字典表(包括:id 区域编码、区域名称),表中的内容如下图所示:现在更进一步,假设需要基于“行政区划代码”数据表生成省、市、区县的三层组织机构的模拟数据。这种结构的数据可以按照组织机构关系呈树型表示,如下图所示。数据表的其它字段与常规数据表字段生成原理相同。对数据进行分析,可以发现行政区划代码的数据规律是:代码是定长的六位数,其中省的格式是 xx0000,市的格式是 xxxx00,区县的格式是 xxxxxx。基于这个规则,我们生成用于查询的模拟数据,并且包含对应层级的人口统计信息字段。下面是相应的 SPL 脚本代码:A1:导入“行政区划代码.txt”数据字典表并设置键。“行政区划代码.txt”中的 id 字段是唯一且不重复的主键,使用keys()对读取得到的序表 id 进行键设置,方便单元格 A2 和 A3 根据 id 主键查找数据。C1:创建保存模拟数据的集文件。A2:按照行政区域的机构编号规则,拆分出三层机构树,并增加相应的机构名称信息和随机的人口统计数,最终生成需要的包含了三层机构树型结构的模拟数据。具体做法是:根据上面分析行政区划代码数据的规律,使用new()将 id 字段拆分格式为 xx0000、xxxx00、xxxxxx 的三层机构数据,分别对应为:level1、level2、level3 字段。由于机构编码表的数据规则,这里的 level2 需要特别处理一下,当机构是直辖市时,省与市的机构编码是一样的,即 level1 与 level2 是相同的,因此要先使用find()查找 level2 值是否存在于“行政区划代码”表中,再使用ifn()判断返回非空成员的值,从而实现返回正确市 level2 的机构编号。其中,需要特别注意的地方是keys()与find()是需要一起配合使用。返回的层级数据结果,如下图所示:A3:将单元格 A2 中省、市的编码转为中文名称。使用run()函数可以针对每条记录计算表达式,然后返回记录本身。特别地,需要注意run()是直接改变原数据值。同样的,这里对第二层级“市”字段也进行了查找返回非空成员值的处理方法,最终运行的结果如下:A4:将模拟生成的数据导出为“区域统计表.btx”集文件。同样地,可以使用集文件浏览器打开该二进制数据文件查看数据:四、 补齐 / 补全固定数据除了直接生成模拟数据,或者基于一些基础数据生成补充模拟数据,在业务中还可能需要在已有历史数据的基础上,针对存在的数据缺失情况,生成模拟数据进行补充。下面就介绍两种常见的固定数据补齐 / 补全的场景,从而应对数据缺失情况。1、 补齐 / 补全固定分组数据产品完工记录存储在“building” 数据表中,其中 YEAR 为完工时间(数据类型:字符型),格式为“年份 上半年 下半年”。现在要指定起止年份,统计出各类产品每半年的完工数量。固定数据信息如下:“building” 数据表中的年份不连续,统计时就需要进行额外的判断和处理。下面的 SPL 脚本在处理此类数据时就相对简单很多:A1-D1:导入“building.txt”数据表,创建保存数据结果的building.btx集文件A2:创建临时二维表。A3:按照起、止时间段创建新的完整的年份统计表。A4-B4:将 building 表按照 TYPE 分组,并循环处理每组数据。在单元格 B4 中使用insert()实现 A3 与 A4 的数据补齐,其中参数“0:A3”表示在 A2 二维表末尾的位置追加 A3 长度的多条记录数据,并将补齐 / 补全数据插入到单元格 A2 的二维表中。A5:将 A2 数据结果导出到 building.btx 集文件中。查看集文件补齐数据结果如下:2、 补齐 / 补全固定分组并转置 员工的出差记录存储在“OnBusiness”数据表中,包含:Date 和 ID_user 字段。而用户信息数据存储在“User”表中,包含:ID 和 Name 字段。需要实现在指定的时间段,按顺序列出每周每个员工是否出差状态信息。这个场景的特殊之处是需要每个 User 员工对应占一列。OnBusiness 和 User 的部分数据,如下: 如果当起止日期是 2015-05-31、2015-06-28,则期望数据的结果,如下:SPL脚本如下所示:A1:简单关联过滤查询区间范围内的数据。C1:创建保存生成结果数据的 NewOnBusiness.btx 集文件。A2:对单元格 A1 中关联过滤后的数据按 ID_User 分组。A3:按照区间构造二维表的。每周 Week 占 1 行(间断时自动补齐数据),User1-User5 每个员工各占一列,默认初值都是“No”标识状态。A4:通过多次调用 run() 函数循环 A2 数据并确定行记录后,再使用 A.field() 函数实现确定需要修改的列位置,最终将单元格 A3 构造的二维表对应的位置数据修改为员工出差状态为“Yes”状态值。查看集文件补齐并转置的数据结果,如下:上述运算的结果与预期数据结果一致,实现了对数据的补齐和转置。 ...

January 14, 2019 · 3 min · jiezi

Netty中的Channel之数据冲刷与线程安全(writeAndFlush)

本文首发个人博客:猫叔的博客 | MySelfGitHub项目地址InChat一个轻量级、高效率的支持多端(应用与硬件Iot)的异步网络应用通讯框架前言本文预设读者已经了解了一定的Netty基础知识,并能够自己构建一个Netty的通信服务(包括客户端与服务端)。那么你一定使用到了Channel,这是Netty对传统JavaIO、NIO的链接封装实例。那么接下来让我们来了解一下关于Channel的数据冲刷与线程安全吧。数据冲刷的步骤1、获取一个链接实例@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { //获取链接实例 Channel channel = ctx.channel();}我将案例放在初学者最熟悉的channelRead方法中,这是一个数据接收的方法,我们自实现Netty的消息处理接口时需要重写的方法。即客户端发送消息后,这个方法会被触发调用,所以我们在这个方法中进行本次内容的讲解。由上一段代码,其实目前还是很简单,我们借助ChannelHandlerContext(这是一个ChannelHandler与ChannelPipeline相交互并对接的一个对象。如下是源码的解释)来获取目前的链接实例Channel。/* Enables a {@link ChannelHandler} to interact with its {@link ChannelPipeline} * and other handlers. Among other things a handler can notify the next {@link ChannelHandler} in the * {@link ChannelPipeline} as well as modify the {@link ChannelPipeline} it belongs to dynamically. / public interface ChannelHandlerContext extends AttributeMap, ChannelInboundInvoker, ChannelOutboundInvoker { //…… }2、创建一个持有数据的ByteBuf@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { //获取链接实例 Channel channel = ctx.channel(); //创建一个持有数据的ByteBuf ByteBuf buf = Unpooled.copiedBuffer(“data”, CharsetUtil.UTF_8);}ByteBuf又是什么呢?它是Netty框架自己封装的一个字符底层对象,是一个对 byte[] 和 ByteBuffer NIO 的抽象类,更官网的说就是“零个或多个字节的随机和顺序可访问的序列。”,如下是源码的解释/* * A random and sequential accessible sequence of zero or more bytes (octets). * This interface provides an abstract view for one or more primitive byte * arrays ({@code byte[]}) and {@linkplain ByteBuffer NIO buffers}. / public abstract class ByteBuf implements ReferenceCounted, Comparable<ByteBuf> { //…… }由上一段源码可以看出,ByteBuf是一个抽象类,所以我们不能通过 new 的形式来创建一个新的ByteBuf对象。那么我们可以通过Netty提供的一个 final 的工具类 Unpooled(你将其看作是一个创建ByteBuf的工具类就好了)。/* * Creates a new {@link ByteBuf} by allocating new space or by wrapping * or copying existing byte arrays, byte buffers and a string. / public final class Unpooled { //…… }这真是一个有趣的过程,那么接下来我们仅需要再看看 copiedBuffer 这个方法了。这个方法相对简单,就是我们将创建一个新的缓冲区,其内容是我们指定的 UTF-8字符集 编码指定的 “data” ,同时这个新的缓冲区的读索引和写索引分别是0和字符串的长度。3、冲刷数据@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { //获取链接实例 Channel channel = ctx.channel(); //创建一个持有数据的ByteBuf ByteBuf buf = Unpooled.copiedBuffer(“data”, CharsetUtil.UTF_8); //数据冲刷 channel.writeAndFlush(buf);}我相信大部分人都是直接这么写的,因为我们经常理所当然的启动测试,并在客户端接受到了这个 “data” 消息。那么我们是否应该注意一下,这个数据冲刷会返回一个什么值,我们要如何才能在服务端知道,这次数据冲刷是成功还是失败呢?那么其实Netty框架已经考虑到了这个点,本次数据冲刷我们将得到一个 ChannelFuture 。@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { //获取链接实例 Channel channel = ctx.channel(); //创建一个持有数据的ByteBuf ByteBuf buf = Unpooled.copiedBuffer(“data”, CharsetUtil.UTF_8); //数据冲刷 ChannelFuture cf = channel.writeAndFlush(buf);}是的,他就是 Channel 异步IO操作的结果,它是一个接口,并继承了Future<V>。(如下为源码的解释)/* * The result of an asynchronous {@link Channel} I/O operation. / public interface ChannelFuture extends Future<Void> { //…… }既然如此,那么我们可以明显的知道我们可以对其添加对应的监听。4、异步回调结果监听@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { //获取链接实例 Channel channel = ctx.channel(); //创建一个持有数据的ByteBuf ByteBuf buf = Unpooled.copiedBuffer(“data”, CharsetUtil.UTF_8); //数据冲刷 ChannelFuture cf = channel.writeAndFlush(buf); //添加ChannelFutureListener以便在写操作完成后接收通知 cf.addListener(new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture future) throws Exception { //写操作完成,并没有错误发生 if (future.isSuccess()){ System.out.println(“successful”); }else{ //记录错误 System.out.println(“error”); future.cause().printStackTrace(); } } });}好的,我们可以简单的从代码理解到,我们将通过对异步IO的结果监听,得到本次运行的结果。我想这才是一个相对完整的 数据冲刷(writeAndFlush)。测试线程安全的流程对于线程安全的测试,我们将模拟多个线程去执行数据冲刷操作,我们可以用到 Executor 。我们可以这样理解 Executor ,是一种省略了线程启用与调度的方式,你只需要传递一个 Runnable 给它即可,你不再需要去 start 一个线程。(如下是源码的解释)/* * An object that executes submitted {@link Runnable} tasks. This * interface provides a way of decoupling task submission from the * mechanics of how each task will be run, including details of thread * use, scheduling, etc. An {@code Executor} is normally used * instead of explicitly creating threads. For example, rather than * invoking {@code new Thread(new(RunnableTask())).start()} for each * of a set of tasks, you might use:… / public interface Executor { //…… }那么我们的测试代码,大致是这样的。final Channel channel = ctx.channel();//创建要写数据的ByteBuffinal ByteBuf buf = Unpooled.copiedBuffer(“data”,CharsetUtil.UTF_8).retain();//创建将数据写到Channel的RunnableRunnable writer = new Runnable() { @Override public void run() { ChannelFuture cf = channel.writeAndFlush(buf.duplicate()); cf.addListener(new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture future) throws Exception { //写操作完成,并没有错误发生 if (future.isSuccess()){ System.out.println(“successful”); }else{ //记录错误 System.out.println(“error”); future.cause().printStackTrace(); } } }); }};//获取到线程池的Executor的引用Executor executor = Executors.newCachedThreadPool();//提交到某个线程中执行executor.execute(writer);//提交到另一个线程中执行executor.execute(writer);这里,我们需要注意的是:创建 ByteBuf 的时候,我们使用了 retain 这个方法,他是将我们生成的这个 ByteBuf 进行保留操作。在 ByteBuf 中有这样的一种区域: 非保留和保留派生缓冲区。这里有点复杂,我们可以简单的理解,如果调用了 retain 那么数据就存在派生缓冲区中,如果没有调用,则会在调用后,移除这一个字符数据。(如下是 ByteBuf 源码的解释)/<h4>Non-retained and retained derived buffers</h4> * * Note that the {@link #duplicate()}, {@link #slice()}, {@link #slice(int, int)} and {@link #readSlice(int)} does NOT * call {@link #retain()} on the returned derived buffer, and thus its reference count will NOT be increased. If you * need to create a derived buffer with increased reference count, consider using {@link #retainedDuplicate()}, * {@link #retainedSlice()}, {@link #retainedSlice(int, int)} and {@link #readRetainedSlice(int)} which may return * a buffer implementation that produces less garbage. */好的,我想你可以自己动手去测试一下,最好再看看源码,加深一下实现的原理印象。这里的线程池并不是现实线程安全,而是用来做测试多线程的,Netty的Channel实现是线程安全的,所以我们可以存储一个到Channel的引用,并且每当我们需要向远程节点写数据时,都可以使用它,即使当时许多线程都在使用它,消息也会被保证按顺序发送的。结语最后,介绍一下,个人的一个基于Netty的开源项目:InChat一个轻量级、高效率的支持多端(应用与硬件Iot)的异步网络应用通讯框架参考资料: 《Netty实战》 ...

December 24, 2018 · 3 min · jiezi

Alibaba Cluster Data 开放下载:270GB 数据揭秘你不知道的阿里巴巴数据中心

打开一篇篇 IT 技术文章,你总能够看到“大规模”、“海量请求”这些字眼。如今,这些功能强大的互联网应用,都运行在大规模数据中心上,然而,对于大规模数据中心,你又了解多少呢?实际上,除了阅读一些科技文章之外,你很难得到更多关于数据中心的信息。数据中心每个机器的运行情况如何?这些机器上运行着什么样的应用?这些应用有有什么特点?对于这些问题,除了少数资深从业者之外,普通学生和企业的研究者很难了解其中细节。1 什么是Alibaba Cluster Data?2015 年,我们尝试在阿里巴巴的数据中心,将延迟不敏感的批量离线计算任务和延迟敏感的在线服务部署到同一批机器上运行,让在线服务用不完的资源充分被离线使用以提高机器的整体利用率。经过 3 年多的试验论证、架构调整和资源隔离优化,目前这个方案已经走向大规模生产。</span></span>我们通过混部技术将集群平均资源利用率从 10% 大幅度提高到 45%。另外,通过各种优化手段,可以让更多任务运行在数据中心,将“双11”平均每万笔交易成本下降了 17%,等等。那么,实施了一系列优化手段之后的计算机集群究竟是什么样子?混部的情况究竟如何?除了文字性的介绍,直接发布数据能够更加拉近我们与学术研究、业界同行之间的距离。为了让有兴趣的学生以及相关研究人员,可以从数据上更加深入地理解大规模数据中心,我们特别发布了这份数据集。数据集中记录了某个生产集群中服务器以及运行任务的详细情况。在数据集中,你可以详细了解到我们是如何通过混部把资源利用率提高到 45%;我们每天到底运行了多少任务;以及业务的资源需求有什么特点,等等。如何使用这份数据集,完全取决于你的需要。2 你用这个数据可以做什么?刚刚发布的 Alibaba Cluster Data V2018 包含 6 个文件,压缩后大小近 50GB(压缩前 270+GB),里面包含了 4000 台服务器、相应的在线应用容器和离线计算任务长达 8 天的运行情况,具体信息你可以在 GitHub 中找到。通过这份数据,你可以:了解当代先进数据中心的服务器以及任务运行特点;试验你的调度、运筹等各种任务管理和集群优化方面的各种算法并撰写论文;利用这份数据学习如何进行数据分析,揭示更多我们自己都未曾发现的规律。只看上面这几点,没有接触过类似数据的朋友,可能对于这份数据的用处还是没有概念,下面我举几个简单的例子:电商业务在白天和晚上面临的压力不同,我们如何在业务存在波峰波谷的情况下提高整体资源利用率?你知道我们最长的 DAG 有多少依赖吗?一个典型的容器存在时间是多久?一个计算型任务的典型存在时间是多少?一个 Task 的多个 Instance 理论上彼此很相似,但是它们运行的时间都一样吗?实际上,学者们甚至可以用这些数据作出更加精彩地分析。2017年,我们曾开放的第一波数据(Alibaba Cluster Data V2017),已经产生了多篇优秀的学术成果。以下是学者们在论文中引用数据(Alibaba Cluster Data V2017)的例子,其中不乏被 OSDI 这样顶级学术会议收录的优秀文章。我们期待,未来你也能与我们共同分享你用这份数据产生的成果!LegoOS: A Disseminated, Distributed OS for Hardware Resource Disaggregation, Yizhou Shan, Yutong Huang, Yilun Chen, and Yiying Zhang, Purdue University. Imbalance in the Cloud: an Analysis on Alibaba Cluster Trace, Chengzhi Lu et al. BIGDATA 2017</span>“CharacterizingCo-located Datacenter Workloads: An Alibaba Case Study, Yue Cheng, Zheng Chai,Ali Anwar. APSys2018</span>”"<span data-type=“color” style=“color:rgb(36, 41, 46)">The Elasticity and Plasticity in Semi-Containerized Co-locating Cloud Workload: aView from Alibaba Trace, Qixiao Liu and Zhibin Yu. SoCC2018</span>“3 Cluster Data V2018的不同新版本 V2018 与 V2017 存在两个最大的区别:DAG 信息加入我们加入了离线任务的 DAG 任务信息,据了解,这是目前来自实际生产环境最大的 DAG 数据。什么是 DAG?离线计算任务,例如 Map Reduce、Hadoop、Spark、Flink 中常用的任务,都是以有向无环图(Directed Acyclic Graph,DAG)的形式进行编排的,其中涉及到任务之间的并行、依赖等方面。下面是一个 DAG 的例子。规模更大上一版数据包含了约 1300 台机器在约 24 小时的内容数据,而新版 Cluster Data V2018 中包括了 4000 台机器 8 天的数据。完成问卷即可获取数据格式描述和数据的下载链接:http://alibabadeveloper.mikecrm.com/BdJtacN ...

December 21, 2018 · 1 min · jiezi

主数据管理项目建设经验分享

一、主数据建设的术法道随着企业信息化系统建设逐渐增多,领导、业务部门对信息系统支撑决策、管控、业务运行难度也随之提高,导致解决业务系统间的交互困难和数据多头管理不一致等问题成为信息化建设的难点和重点。借鉴业界成熟的信息化建设思路,建设步骤分为三步:立标准通过数据标准化建设,达到关键主数据的管理制度化,数据标准化,使各信息系统遵循一套统一的数据标准。此步骤典型的建设是主数据管理系统。通数据依托统一的数据标准,基于统一的服务对接规范,实现各系统间互联互通,通达高效,系统范围涵盖横向纵向两个维度,纵向包括集团和下属单位的系统,横向包括同一组织的不同业务系统。此步骤典型的建设是业务财务一体化,业务审批流程推送。挖价值由于前面两个工作,现有系统中将存在大量标准化的、互联互通的业务数据,本阶段的建设将基于这些数据进行不同方向的深入应用建设,例如精细化深入管控体系、全面综合的战略分析能力。此步骤典型的建设是支撑领导、公司战略的独特性要求的考核、分析系统。图一:建设思路从信息化建设角度,需要按照1、2、3的顺序层层建设推进,从业务价值体现角度,需要按照3、2、1的顺序层层支撑。二、主数据建设的顶层设计根据上述建设思路,对建设方法按照业务、技术、数据三个层面进行顶层设计如下:业务架构业务架构围绕业务价值的123三个层次展开。图二:业务架构第一层技术基础价值:主数据管理实现的数据标准化、管理标准化,主数据体现的是技术层面的基础价值,支撑了第二三层价值。第二层业务直接价值:依托统一的数据标准,基于统一的服务对接规范,实现各系统间互联互通,例如业务财务一体化,第二层价值体现的是业务层面的直接价值,支撑了第三层价值。第三层战略战术价值:基于上述工作产生的标准化的数据,进行各类分析、核算、控制、管控、优化工作,对公司战略落地、战术执行的有力支撑。技术架构技术架构对123三个层次工作内容的技术落地进行了描述。图三:技术架构通过主数据管理平台建设达到各异构系统数据标准化,主数据管理平台提供数据统一建模、多源头数据清洗合并、版本管理、血缘分析、数据分发推送、数据质量核查等能力。对于多源头数据进行清洗合并,对于单来源数据进行分发同步,对于无来源数据通过可视化建模方式提供数据录入审批功能。通过企业服务总线建设达到系统标准化服务对接,企业服务总线提供服务标准化集成、数据集成转换采集、消息异步队列、统一监控运维等能力。系统间通过服务总线进行对接,达到了可插拔,低耦合的目标。通过数据仓库建设,集成元数据、主数据、业务数据、系统数据,再进行抽取装载转换分析,为各类分析、核算、控制、管控、优化工作,对公司战略落地、战术执行提供有力支撑。总之,以管理制度、技术规范为基础,通过建设主数据管理系统标准化基本档案数据,从而达到业务单据数据更加准确一致,之后通过单据的上传并进行跨组织的数据报表分析达到实时、准确的集团管控,提供战术执行底层支撑、战略落地具体体现。三、主数据建设的思路按照上述方法对企业信息现状分析,会发现有大量主数据需要建设,此时需要进行分批建设,划分原则是按照业务领域结合目前信息化建设重点进行匹配建设,达到主数据建设支撑了现在正在(规划)建设的业务系统的建设,同时业务系统建设体现出主数据建设的价值。图四:建设思路主数据建设按照管理制度制定、技术方案制定、系统开发对接、历史数据清洗、项目运营依次展开。业务、管理越复杂的主数据前期管理制度制定的工作越重要越耗时,反之业务场景简单的主数据主要工作在于技术方案和系统对接。四、主数据建设的落地方案基础数据管理系统功能涵盖基础数据的全生命周期,包括基础数据建模、基础数据建立、基础数据管理、基础数据共享。基础数据涵盖人员、用户、组织、客户、供应商、物料、项目等主数据,第一阶段可以关注某一特定领域,例如集中在与业财一体化相关的主数据。技术标准涵盖统一分类、基础数据模型、编码原则、编码规则、数据分发、数据服务、服务注册、数据推送、数据查询等。管理规范涵盖管理组织、岗位角色、管理流程、管理规范与制度、权限管理等。辅助工具该层利用应用支撑层的服务总线ESB进行系统间的接口对接和流程编排,目前使用的多个信息系统根据实际的业务需求进行对接。实现业务管理系统的可视化搭建和配置,制定相关接口与标准,实现基础数据功能的统一管理,对业务流程灵活调整和优化整合,实现用户权限设置的统一管理和认证。图五:落地方案

December 19, 2018 · 1 min · jiezi

美团DB数据同步到数据仓库的架构与实践

背景在数据仓库建模中,未经任何加工处理的原始业务层数据,我们称之为ODS(Operational Data Store)数据。在互联网企业中,常见的ODS数据有业务日志数据(Log)和业务DB数据(DB)两类。对于业务DB数据来说,从MySQL等关系型数据库的业务数据进行采集,然后导入到Hive中,是进行数据仓库生产的重要环节。如何准确、高效地把MySQL数据同步到Hive中?一般常用的解决方案是批量取数并Load:直连MySQL去Select表中的数据,然后存到本地文件作为中间存储,最后把文件Load到Hive表中。这种方案的优点是实现简单,但是随着业务的发展,缺点也逐渐暴露出来:性能瓶颈:随着业务规模的增长,Select From MySQL -> Save to Localfile -> Load to Hive这种数据流花费的时间越来越长,无法满足下游数仓生产的时间要求。直接从MySQL中Select大量数据,对MySQL的影响非常大,容易造成慢查询,影响业务线上的正常服务。由于Hive本身的语法不支持更新、删除等SQL原语,对于MySQL中发生Update/Delete的数据无法很好地进行支持。为了彻底解决这些问题,我们逐步转向CDC (Change Data Capture) + Merge的技术方案,即实时Binlog采集 + 离线处理Binlog还原业务数据这样一套解决方案。Binlog是MySQL的二进制日志,记录了MySQL中发生的所有数据变更,MySQL集群自身的主从同步就是基于Binlog做的。本文主要从Binlog实时采集和离线处理Binlog还原业务数据两个方面,来介绍如何实现DB数据准确、高效地进入数仓。整体架构整体的架构如上图所示。在Binlog实时采集方面,我们采用了阿里巴巴的开源项目Canal,负责从MySQL实时拉取Binlog并完成适当解析。Binlog采集后会暂存到Kafka上供下游消费。整体实时采集部分如图中红色箭头所示。离线处理Binlog的部分,如图中黑色箭头所示,通过下面的步骤在Hive上还原一张MySQL表:采用Linkedin的开源项目Camus,负责每小时把Kafka上的Binlog数据拉取到Hive上。对每张ODS表,首先需要一次性制作快照(Snapshot),把MySQL里的存量数据读取到Hive上,这一过程底层采用直连MySQL去Select数据的方式。对每张ODS表,每天基于存量数据和当天增量产生的Binlog做Merge,从而还原出业务数据。我们回过头来看看,背景中介绍的批量取数并Load方案遇到的各种问题,为什么用这种方案能解决上面的问题呢?首先,Binlog是流式产生的,通过对Binlog的实时采集,把部分数据处理需求由每天一次的批处理分摊到实时流上。无论从性能上还是对MySQL的访问压力上,都会有明显地改善。第二,Binlog本身记录了数据变更的类型(Insert/Update/Delete),通过一些语义方面的处理,完全能够做到精准的数据还原。Binlog实时采集对Binlog的实时采集包含两个主要模块:一是CanalManager,主要负责采集任务的分配、监控报警、元数据管理以及和外部依赖系统的对接;二是真正执行采集任务的Canal和CanalClient。当用户提交某个DB的Binlog采集请求时,CanalManager首先会调用DBA平台的相关接口,获取这一DB所在MySQL实例的相关信息,目的是从中选出最适合Binlog采集的机器。然后把采集实例(Canal Instance)分发到合适的Canal服务器上,即CanalServer上。在选择具体的CanalServer时,CanalManager会考虑负载均衡、跨机房传输等因素,优先选择负载较低且同地域传输的机器。CanalServer收到采集请求后,会在ZooKeeper上对收集信息进行注册。注册的内容包括:以Instance名称命名的永久节点。在该永久节点下注册以自身ip:port命名的临时节点。这样做的目的有两个:高可用:CanalManager对Instance进行分发时,会选择两台CanalServer,一台是Running节点,另一台作为Standby节点。Standby节点会对该Instance进行监听,当Running节点出现故障后,临时节点消失,然后Standby节点进行抢占。这样就达到了容灾的目的。与CanalClient交互:CanalClient检测到自己负责的Instance所在的Running CanalServer后,便会进行连接,从而接收到CanalServer发来的Binlog数据。对Binlog的订阅以MySQL的DB为粒度,一个DB的Binlog对应了一个Kafka Topic。底层实现时,一个MySQL实例下所有订阅的DB,都由同一个Canal Instance进行处理。这是因为Binlog的产生是以MySQL实例为粒度的。CanalServer会抛弃掉未订阅的Binlog数据,然后CanalClient将接收到的Binlog按DB粒度分发到Kafka上。离线还原MySQL数据完成Binlog采集后,下一步就是利用Binlog来还原业务数据。首先要解决的第一个问题是把Binlog从Kafka同步到Hive上。Kafka2Hive整个Kafka2Hive任务的管理,在美团数据平台的ETL框架下进行,包括任务原语的表达和调度机制等,都同其他ETL类似。而底层采用LinkedIn的开源项目Camus,并进行了有针对性的二次开发,来完成真正的Kafka2Hive数据传输工作。对Camus的二次开发Kafka上存储的Binlog未带Schema,而Hive表必须有Schema,并且其分区、字段等的设计,都要便于下游的高效消费。对Camus做的第一个改造,便是将Kafka上的Binlog解析成符合目标Schema的格式。对Camus做的第二个改造,由美团的ETL框架所决定。在我们的任务调度系统中,目前只对同调度队列的任务做上下游依赖关系的解析,跨调度队列是不能建立依赖关系的。而在MySQL2Hive的整个流程中,Kafka2Hive的任务需要每小时执行一次(小时队列),Merge任务每天执行一次(天队列)。而Merge任务的启动必须要严格依赖小时Kafka2Hive任务的完成。为了解决这一问题,我们引入了Checkdone任务。Checkdone任务是天任务,主要负责检测前一天的Kafka2Hive是否成功完成。如果成功完成了,则Checkdone任务执行成功,这样下游的Merge任务就可以正确启动了。Checkdone的检测逻辑Checkdone是怎样检测的呢?每个Kafka2Hive任务成功完成数据传输后,由Camus负责在相应的HDFS目录下记录该任务的启动时间。Checkdone会扫描前一天的所有时间戳,如果最大的时间戳已经超过了0点,就说明前一天的Kafka2Hive任务都成功完成了,这样Checkdone就完成了检测。此外,由于Camus本身只是完成了读Kafka然后写HDFS文件的过程,还必须完成对Hive分区的加载才能使下游查询到。因此,整个Kafka2Hive任务的最后一步是加载Hive分区。这样,整个任务才算成功执行。每个Kafka2Hive任务负责读取一个特定的Topic,把Binlog数据写入original_binlog库下的一张表中,即前面图中的original_binlog.db,其中存储的是对应到一个MySQL DB的全部Binlog。上图说明了一个Kafka2Hive完成后,文件在HDFS上的目录结构。假如一个MySQL DB叫做user,对应的Binlog存储在original_binlog.user表中。ready目录中,按天存储了当天所有成功执行的Kafka2Hive任务的启动时间,供Checkdone使用。每张表的Binlog,被组织到一个分区中,例如userinfo表的Binlog,存储在table_name=userinfo这一分区中。每个table_name一级分区下,按dt组织二级分区。图中的xxx.lzo和xxx.lzo.index文件,存储的是经过lzo压缩的Binlog数据。MergeBinlog成功入仓后,下一步要做的就是基于Binlog对MySQL数据进行还原。Merge流程做了两件事,首先把当天生成的Binlog数据存放到Delta表中,然后和已有的存量数据做一个基于主键的Merge。Delta表中的数据是当天的最新数据,当一条数据在一天内发生多次变更时,Delta表中只存储最后一次变更后的数据。把Delta数据和存量数据进行Merge的过程中,需要有唯一键来判定是否是同一条数据。如果同一条数据既出现在存量表中,又出现在Delta表中,说明这一条数据发生了更新,则选取Delta表的数据作为最终结果;否则说明没有发生任何变动,保留原来存量表中的数据作为最终结果。Merge的结果数据会Insert Overwrite到原表中,即图中的origindb.table。Merge流程举例下面用一个例子来具体说明Merge的流程。数据表共id、value两列,其中id是主键。在提取Delta数据时,对同一条数据的多次更新,只选择最后更新的一条。所以对id=1的数据,Delta表中记录最后一条更新后的值value=120。Delta数据和存量数据做Merge后,最终结果中,新插入一条数据(id=4),两条数据发生了更新(id=1和id=2),一条数据未变(id=3)。默认情况下,我们采用MySQL表的主键作为这一判重的唯一键,业务也可以根据实际情况配置不同于MySQL的唯一键。上面介绍了基于Binlog的数据采集和ODS数据还原的整体架构。下面主要从两个方面介绍我们解决的实际业务问题。实践一:分库分表的支持随着业务规模的扩大,MySQL的分库分表情况越来越多,很多业务的分表数目都在几千个这样的量级。而一般数据开发同学需要把这些数据聚合到一起进行分析。如果对每个分表都进行手动同步,再在Hive上进行聚合,这个成本很难被我们接受。因此,我们需要在ODS层就完成分表的聚合。首先,在Binlog实时采集时,我们支持把不同DB的Binlog写入到同一个Kafka Topic。用户可以在申请Binlog采集时,同时勾选同一个业务逻辑下的多个物理DB。通过在Binlog采集层的汇集,所有分库的Binlog会写入到同一张Hive表中,这样下游在进行Merge时,依然只需要读取一张Hive表。第二,Merge任务的配置支持正则匹配。通过配置符合业务分表命名规则的正则表达式,Merge任务就能了解自己需要聚合哪些MySQL表的Binlog,从而选取相应分区的数据来执行。这样通过两个层面的工作,就完成了分库分表在ODS层的合并。这里面有一个技术上的优化,在进行Kafka2Hive时,我们按业务分表规则对表名进行了处理,把物理表名转换成了逻辑表名。例如userinfo123这张表名会被转换为userinfo,其Binlog数据存储在original_binlog.user表的table_name=userinfo分区中。这样做的目的是防止过多的HDFS小文件和Hive分区造成的底层压力。实践二:删除事件的支持Delete操作在MySQL中非常常见,由于Hive不支持Delete,如果想把MySQL中删除的数据在Hive中删掉,需要采用“迂回”的方式进行。对需要处理Delete事件的Merge流程,采用如下两个步骤:首先,提取出发生了Delete事件的数据,由于Binlog本身记录了事件类型,这一步很容易做到。将存量数据(表A)与被删掉的数据(表B)在主键上做左外连接(Left outer join),如果能够全部join到双方的数据,说明该条数据被删掉了。因此,选择结果中表B对应的记录为NULL的数据,即是应当被保留的数据。然后,对上面得到的被保留下来的数据,按照前面描述的流程做常规的Merge。总结与展望作为数据仓库生产的基础,美团数据平台提供的基于Binlog的MySQL2Hive服务,基本覆盖了美团内部的各个业务线,目前已经能够满足绝大部分业务的数据同步需求,实现DB数据准确、高效地入仓。在后面的发展中,我们会集中解决CanalManager的单点问题,并构建跨机房容灾的架构,从而更加稳定地支撑业务的发展。本文主要从Binlog流式采集和基于Binlog的ODS数据还原两方面,介绍了这一服务的架构,并介绍了我们在实践中遇到的一些典型问题和解决方案。希望能够给其他开发者一些参考价值,同时也欢迎大家和我们一起交流。招聘如果你对我们的工作内容比较感兴趣,欢迎发送简历给 wangmengmeng05@meituan.com,和我们一起致力于解决海量数据采集和传输的问题中来吧!

December 7, 2018 · 1 min · jiezi