前端技术
HTML
CSS
Javascript
前端框架和UI库
VUE
ReactJS
AngularJS
JQuery
NodeJS
JSON
Element-UI
Bootstrap
Material UI
服务端和客户端
Java
Python
PHP
Golang
Scala
Kotlin
Groovy
Ruby
Lua
.net
c#
c++
后端WEB和工程框架
SpringBoot
SpringCloud
Struts2
MyBatis
Hibernate
Tornado
Beego
Go-Spring
Go Gin
Go Iris
Dubbo
HessianRPC
Maven
Gradle
数据库
MySQL
Oracle
Mongo
中间件与web容器
Redis
MemCache
Etcd
Cassandra
Kafka
RabbitMQ
RocketMQ
ActiveMQ
Nacos
Consul
Tomcat
Nginx
Netty
大数据技术
Hive
Impala
ClickHouse
DorisDB
Greenplum
PostgreSQL
HBase
Kylin
Hadoop
Apache Pig
ZooKeeper
SeaTunnel
Sqoop
Datax
Flink
Spark
Mahout
数据搜索与日志
ElasticSearch
Apache Lucene
Apache Solr
Kibana
Logstash
数据可视化与OLAP
Apache Atlas
Superset
Saiku
Tesseract
系统与容器
Linux
Shell
Docker
Kubernetes
[Groovy默认参数值减少代码冗余]的搜索结果
这里是文章列表。热门标签的颜色随机变换,标签颜色没有特殊含义。
点击某个标签可搜索标签相关的文章。
点击某个标签可搜索标签相关的文章。
转载文章
...上的点光强度的增加或减少。下图显示了一个例子。这些面的邻边依然朝上。顶点法向倾向S1,与顶点法向与表面法向有相同的夹角相比,这使顶点法向与光源间的夹角变小。 可以用高洛德着色在三维场景中显示一些有清晰边缘的物体。要达到这个目的,只要在需要产生清晰边缘的表面交线处,把表面法向复制给交线处顶点的法向,如下图所示。 如果使用DrawPrimitive方法渲染场景,要将有锋利边缘的物体定义为三角形表,而非三角形带。当将物体定义为三角形带时,Direct3D会将它作为由多个三角形组成的单个多边形处理。高洛德着色被同时应用于多边形每个表面的内部和表面之间。结果产生表面之间平滑着色的物体。因为三角形表由一系列不相连的三角形面组成,所以Direct3D对多边形每个面的内部使用高洛德着色。但是,没有在表面之间应用高洛德着色。如果三角形表的两个或更多的三角形是相邻的,那么在它们之间看起来会有一条锋利边缘。 另一种可选的方法是在渲染具有锋利边缘的物体时改变到平面着色模式。这在计算上是最有效的方法,但它可能导致场景中的物体不如用高洛德着色渲染的物体真实。 三角形光栅化法则 顶点指定的点经常不能精确地对应到屏幕上的像素。此时,Microsoft® Direct3D®使用三角形光栅化法则决定对于给定三角形使用哪个像素。 三角形光栅化法则 点、线光栅化法则 点精灵光栅化法则 三角形光栅化法则 Direct3D在填充几何图形时使用左上填充约定(top-left filling convention)。这与Microsoft Windows®的图形设备接口(GUI)和OpenGL中的矩形使用的约定相同。Direct3D中,像素的中心是决定点。如果中心在三角形内,那么该像素就是三角形的一部分。像素中心用整数坐标表示。 这里描述的Direct3D使用的三角形光栅化法则不一定适用于所有可用的硬件。测试可以发现这些法则的实现间的细微变化。 下图显示了一个左上角为(0,0),右下角为(5,5)的矩形。正如大家想象的那样,此矩形填充25个像素。矩形的宽度由right减left定义。高度由bottom减top定义。 在左上填充约定中,上表示水平span在垂直方向上的位置,左表示span中的像素在水平方向上的位置。一条边除非是水平的,否则不可能是顶边——一般来说,大多数三角形只有左边或右边。 左上填充约定确定当一个三角形穿过像素的中心时Direct3D采取的动作。下图显示了两个三角形,一个在(0,0),(5,0)和(5,5),另一个在(0,5),(0,0)和(5,5)。在这种情况下第一个三角形得到15个像素(显示为黑色),而第二个得到10个像素(显示为灰色),因为公用边是第一个三角形的左边。 如果应用程序定义一个左上角为(0.5,0.5),右下角为(2.5,4.5)的矩形,那么这个矩形的中心在(1.5,2.5)。当Direct3D光栅化器tessellate这个矩形时,每个像素的中心都毫无异义地分别位于四个三角形中,此时就不需要左上填充约定。下图显示了这种情况。矩形内的像素根据在Direct3D中被哪个三角形包含做了相应的标注。 如果将上例中的矩形移动,使之左上角为(1.0,1.0),右下角为(3.0,5.0),中心为(2.0,3.0),那么Direct3D使用左上角填充约定。这个矩形中大多数的像素跨越两个或更多的三角形的边界,如下图所示。 这两个矩形会影响到相同的像素。 点、线光栅化法则 点和点精灵一样,都被渲染为与屏幕边缘对齐的四边形,因此它们使用与多边形同样的渲染法则。 非抗锯齿线段的渲染法则与GDI使用的法则完全相同。 更多有关抗锯齿线段的渲染,请参阅ID3DXLine。 点精灵光栅化法则 对点精灵和patch图元的渲染,就好像先把图元tessellate成三角形,然后将得到的三角形进行光栅化。更多信息,请参阅点精灵。 矩形 贯穿Microsoft® Direct3D®和Microsoft Windows®编程,都是用术语包围矩形来讨论屏幕上的物体。由于包围矩形的边总是与屏幕的边平行,因此矩形可以用两个点描述,左上角和右下角。当在屏幕上进行位块传输(Blit = Bit block transfer)或命中检测时,大多数应用程序使用RECT结构保存包围矩形的信息。 C++中,RECT结构有如下定义。 typedef struct tagRECT { LONG left; // 这是左上角的x坐标。 LONG top; // 这是左上角的y坐标。 LONG right; // 这是右下角的x坐标。 LONG bottom; // 这是右下角的y坐标。 } RECT, PRECT, NEAR NPRECT, FAR LPRECT; 在上例中,left和top成员是包围矩形左上角的x-和y-坐标。类似地,right和bottom成员组成右下角的坐标。下图直观地显示了这些值。 为了效率、一致性及易用性, Direct3D所有的presentation函数都使用矩形。 三角形插值对象(interpolants) 在渲染时,流水线会贯穿每个三角形的表面进行顶点数据插值。有五种可能的数据类型可以进行插值。顶点数据可以是各种类型的数据,包括(但不限于):漫反射色、镜面反射色、漫反射阿尔法(三角形透明度)、镜面反射阿尔法、雾因子(固定功能流水线从镜面反射的阿尔法分量中取得,可编程顶点流水线则从雾寄存器中取得)。顶点数据通过顶点声明定义。 对一些顶点数据的插值取决于当前的着色模式,如下表所示。 着色模式 描述 平面 在平面着色模式下只对雾因子进行插值。对所有其它的插值对象,整个面都使用三角形第一个顶点的颜色。 高洛德 在所有三个顶点间进行线性插值。 根据不同的颜色模型,对漫反射色和镜面反射色的处理是不同的。在RGB颜色模型中,系统在插值时使用红、绿和蓝颜色分量。 颜色的阿尔法成员作为单独的插值对象对待,因为设备驱动程序可以以两种不同的方法实现透明:使用纹理混合或使用点画法(stippling)。 可以用D3DCAPS9结构的ShadeCaps成员确定设备驱动程序支持何种插值。 向量、顶点和四元数 贯穿Microsoft® Direct3D®,顶点用于描述位置和方向。图元中的每个顶点由指定其位置的向量、颜色、纹理坐标和指定其方向的法向量描述。 四元数给三元素向量的[ x, y, z]值增加了第四个元素。用于三维旋转的方法,除了典型的矩阵以外,四元数是另一种选择。四元数表示三维空间中的一根轴及围绕该轴的一个旋转。例如,一个四元数可能表示轴(1,1,2)和1度的旋转。四元数包含了有价值的信息,但它们真正的威力源自可对它们执行的两种操作:合成和插值。 对四元数进行插值与合成它们类似。两个四元数的合成如下表示: 将两个四元数的合成应用于几何体意味着“把几何体绕axis2轴旋转rotation2角度,然后绕axis1轴旋转rotation1角度”。在这种情况下,Q表示绕单根轴的旋转,该旋转是先后将q2和q1应用于几何体的结果。 使用四元数,应用程序可以计算出一条从一根轴和一个方向到另一根轴和另一个方向的平滑、合理的路径。因此,在q1和q2间插值提供了一个从一个方向变化到另一个方向的简单方法。 当同时使用合成与插值时,四元数提供了一个看似复杂而实际简单的操作几何体的方法。例如,设想我们希望把一个几何体旋转到某个给定方向。我们已经知道希望将它绕axis2轴旋转r2度,然后绕axis1轴旋转r1度,但是我们不知道最终的四元数。通过使用合成,我们可以在几何体上合成两个旋转并得到最终单个的四元数。然后,我们可以在原始四元数和合成的四元数间进行插值,得到两者之间的平滑转换。 Direct3D扩展(D3DX)工具库包含了帮助用户使用四元数的函数。例如,D3DXQuaternionRotationAxis函数给一个定义旋转轴的向量增加一个旋转值,并在由D3DXQUTERNION结构定义的四元数中返回结果。另外,D3DXQuaternionMultiply函数合成四元数,D3DXQuaternionSlerp函数在两个四元数间进行球面线性插值(spherical linear interpolation)。 Direct3D应用程序可以使用下列函数简化对四元数的使用。 D3DXQuaternionBaryCentric D3DXQuaternionConjugate D3DXQuaternionDot D3DXQuaternionExp D3DXQuaternionIdentity D3DXQuaternionInverse D3DXQuaternionIsIdentity D3DXQuaternionLength D3DXQuaternionLengthSq D3DXQuaternionLn D3DXQuaternionMultiply D3DXQuaternionNormalize D3DXQuaternionRotationAxis D3DXQuaternionRotationMatrix D3DXQuaternionRotationYawPitchRoll D3DXQuaternionSlerp D3DXQuaternionSquad D3DXQuaternionToAxisAngle Direct3D应用程序可以使用下列函数简化对三成员向量的使用。 D3DXVec3Add D3DXVec3BaryCentric D3DXVec3CatmullRom D3DXVec3Cross D3DXVec3Dot D3DXVec3Hermite D3DXVec3Length D3DXVec3LengthSq D3DXVec3Lerp D3DXVec3Maximize D3DXVec3Minimize D3DXVec3Normalize D3DXVec3Project D3DXVec3Scale D3DXVec3Subtract D3DXVec3Transform D3DXVec3TransformCoord D3DXVec3TransformNormal D3DXVec3Unproject D3DX工具库提供的数学函数中包含了许多辅助函数,可以简化对二成员和四成员向量的使用 http://www.gesoftfactory.com/developer/3DCS.htm 本篇文章为转载内容。原文链接:https://blog.csdn.net/okvee/article/details/3438011。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-10-24 12:49:42
271
转载
转载文章
...须准确预估出餐时间以减少骑手等待,但又不能让餐等人,最后饭凉了。饿了么旗下蜂鸟配送“准时达”服务单均配送时长缩短至30分钟以内。 3) 天气特殊影响:天气等环境因素对送餐响应时间影响显著,要想计算骑手的送餐路程时间,ET需要知道每个骑手在不同区域、不同天气下的送餐速度。如果北京雾霾,ET能看见吗?双方研发团队为ET内置了恶劣天气的算法模型。通常情况下,每逢恶劣天气,外卖订单将出现大涨,对应的餐厅出餐速度和骑手骑行速度都将受到影响,这些ET都会考虑在内。如果顾客在下雪天点个火锅呢?ET也知道,将自动识别其为大单,锁定某一个骑手专门完成配送。 4) 餐饮营销顾问:饿了么整体业务涉及C端(消费者)、B端(餐饮商户)、D端(物流配送)、BD端(地推营销),以往区域业务开拓考核新店数量,现在会重点关注餐饮外卖“健康度”,对于营业额忽高忽低、在线排名变化的餐饮店,都需要BD专家根据大数据帮助餐饮店经营者找出原因并给出解决建议,避免新店外卖刚开始就淹没在区域竞争中,销量平平的新店会离开平台,通过机器学习把餐饮运营专家的经验、以及人看不到的隐含规律固化下来,以数据决策来发现餐饮店经营问题、产品差异定位,让餐饮商户尝到甜头,才愿意继续经营。举个例子,饿了么员工都喜欢楼下一家鸡排店的午餐,但大数据发现这家店的外卖营收并不如实体店那么火爆,9元“鸡排+酸梅汁”是所有人都喜欢的爆款产品,可为什么同样菜品遭遇“线下火、线上冷”呢?数据预警后,BD顾问指出线上外卖鸡排产品没有写明“含免费酸梅汁一杯”的关键促销内容,导致大多数外卖消费者订一份鸡排一杯酸梅汁,却收到一份鸡排两杯酸梅汁,体验自然不好。 饿了么是数据驱动、智能算法调度的自动化生活服务平台,通过O2O数据的在线实时分析,与阿里云人工智能团队不断改进算法,以“全局最优”取代“局部最优”,保证平台上所有餐饮商户都能享受到数据智能的科技红利。 “上云用数”的外部价值诸多,从饿了么内部反馈来看,上云不仅没有让运维团队失去价值,反而带来了“云原生应用”(Cloud Native Application)、“云上多活”、“CDN云端压测”、“安全风控一体化”等创新路径与方案,通过敏捷基础设施(IaaS)、微服务架构(PaaS和SaaS)、持续交付管理、DevOps等云最佳实践,摆脱“人肉”支撑的种种困境,进而实现更快的上线速度、细致的故障探测和发现、故障时能自动隔离、故障时能够自动恢复、方便的水平扩容。饿了么CTO张雪峰先生说:“互联网平台型组织,业务量涨数倍,企业人数稳定降低,才是技术驱动的正确商业模式。” 在不久的将来,你每天订餐、出行、娱乐、工作留下的大数据,会“驯养”出无处不在、无所不能的智能机器人管家,家庭助理帮你点菜,无人机为你送餐,聊天机器人接受你的投诉……当然这个无比美妙的“未来世界”背后,皆有阿里云的数据智能母体“ET”。 本篇文章为转载内容。原文链接:https://blog.csdn.net/weixin_34126557/article/details/90592502。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-01-31 14:48:26
343
转载
转载文章
...享等动作类型。 模型参数服务器是内部开发的一套高性能的系统,因为头条数据规模增长太快,类似的开源系统稳定性和性能无法满足,而我们自研的系统底层做了很多针对性的优化,提供了完善运维工具,更适配现有的业务场景。 目前,头条的推荐算法模型在世界范围内也是比较大的,包含几百亿原始特征和数十亿向量特征。 整体的训练过程是线上服务器记录实时特征,导入到Kafka文件队列中,然后进一步导入Storm集群消费Kafka数据,客户端回传推荐的label构造训练样本,随后根据最新样本进行在线训练更新模型参数,最终线上模型得到更新。 这个过程中主要的延迟在用户的动作反馈延时,因为文章推荐后用户不一定马上看,不考虑这部分时间,整个系统是几乎实时的。 但因为头条目前的内容量非常大,加上小视频内容有千万级别,推荐系统不可能所有内容全部由模型预估。 所以需要设计一些召回策略,每次推荐时从海量内容中筛选出千级别的内容库。召回策略最重要的要求是性能要极致,一般超时不能超过50毫秒。 召回策略种类有很多,我们主要用的是倒排的思路。离线维护一个倒排,这个倒排的key可以是分类,topic,实体,来源等。 排序考虑热度、新鲜度、动作等。线上召回可以迅速从倒排中根据用户兴趣标签对内容做截断,高效的从很大的内容库中筛选比较靠谱的一小部分内容。 二、内容分析 内容分析包括文本分析,图片分析和视频分析。头条一开始主要做资讯,今天我们主要讲一下文本分析。文本分析在推荐系统中一个很重要的作用是用户兴趣建模。 没有内容及文本标签,无法得到用户兴趣标签。举个例子,只有知道文章标签是互联网,用户看了互联网标签的文章,才能知道用户有互联网标签,其他关键词也一样。 另一方面,文本内容的标签可以直接帮助推荐特征,比如魅族的内容可以推荐给关注魅族的用户,这是用户标签的匹配。 如果某段时间推荐主频道效果不理想,出现推荐窄化,用户会发现到具体的频道推荐(如科技、体育、娱乐、军事等)中阅读后,再回主feed,推荐效果会更好。 因为整个模型是打通的,子频道探索空间较小,更容易满足用户需求。只通过单一信道反馈提高推荐准确率难度会比较大,子频道做的好很重要。而这也需要好的内容分析。 上图是今日头条的一个实际文本case。可以看到,这篇文章有分类、关键词、topic、实体词等文本特征。 当然不是没有文本特征,推荐系统就不能工作,推荐系统最早期应用在Amazon,甚至沃尔玛时代就有,包括Netfilx做视频推荐也没有文本特征直接协同过滤推荐。 但对资讯类产品而言,大部分是消费当天内容,没有文本特征新内容冷启动非常困难,协同类特征无法解决文章冷启动问题。 今日头条推荐系统主要抽取的文本特征包括以下几类。首先是语义标签类特征,显式为文章打上语义标签。 这部分标签是由人定义的特征,每个标签有明确的意义,标签体系是预定义的。 此外还有隐式语义特征,主要是topic特征和关键词特征,其中topic特征是对于词概率分布的描述,无明确意义;而关键词特征会基于一些统一特征描述,无明确集合。 另外文本相似度特征也非常重要。在头条,曾经用户反馈最大的问题之一就是为什么总推荐重复的内容。这个问题的难点在于,每个人对重复的定义不一样。 举个例子,有人觉得这篇讲皇马和巴萨的文章,昨天已经看过类似内容,今天还说这两个队那就是重复。 但对于一个重度球迷而言,尤其是巴萨的球迷,恨不得所有报道都看一遍。解决这一问题需要根据判断相似文章的主题、行文、主体等内容,根据这些特征做线上策略。 同样,还有时空特征,分析内容的发生地点以及时效性。比如武汉限行的事情推给北京用户可能就没有意义。 最后还要考虑质量相关特征,判断内容是否低俗,色情,是否是软文,鸡汤? 上图是头条语义标签的特征和使用场景。他们之间层级不同,要求不同。 分类的目标是覆盖全面,希望每篇内容每段视频都有分类;而实体体系要求精准,相同名字或内容要能明确区分究竟指代哪一个人或物,但不用覆盖很全。 概念体系则负责解决比较精确又属于抽象概念的语义。这是我们最初的分类,实践中发现分类和概念在技术上能互用,后来统一用了一套技术架构。 目前,隐式语义特征已经可以很好的帮助推荐,而语义标签需要持续标注,新名词新概念不断出现,标注也要不断迭代。其做好的难度和资源投入要远大于隐式语义特征,那为什么还需要语义标签? 有一些产品上的需要,比如频道需要有明确定义的分类内容和容易理解的文本标签体系。语义标签的效果是检查一个公司NLP技术水平的试金石。 今日头条推荐系统的线上分类采用典型的层次化文本分类算法。 最上面Root,下面第一层的分类是像科技、体育、财经、娱乐,体育这样的大类,再下面细分足球、篮球、乒乓球、网球、田径、游泳…,足球再细分国际足球、中国足球,中国足球又细分中甲、中超、国家队…,相比单独的分类器,利用层次化文本分类算法能更好地解决数据倾斜的问题。 有一些例外是,如果要提高召回,可以看到我们连接了一些飞线。这套架构通用,但根据不同的问题难度,每个元分类器可以异构,像有些分类SVM效果很好,有些要结合CNN,有些要结合RNN再处理一下。 上图是一个实体词识别算法的case。基于分词结果和词性标注选取候选,期间可能需要根据知识库做一些拼接,有些实体是几个词的组合,要确定哪几个词结合在一起能映射实体的描述。 如果结果映射多个实体还要通过词向量、topic分布甚至词频本身等去歧,最后计算一个相关性模型。 三、用户标签 内容分析和用户标签是推荐系统的两大基石。内容分析涉及到机器学习的内容多一些,相比而言,用户标签工程挑战更大。 今日头条常用的用户标签包括用户感兴趣的类别和主题、关键词、来源、基于兴趣的用户聚类以及各种垂直兴趣特征(车型,体育球队,股票等)。还有性别、年龄、地点等信息。 性别信息通过用户第三方社交账号登录得到。年龄信息通常由模型预测,通过机型、阅读时间分布等预估。 常驻地点来自用户授权访问位置信息,在位置信息的基础上通过传统聚类的方法拿到常驻点。 常驻点结合其他信息,可以推测用户的工作地点、出差地点、旅游地点。这些用户标签非常有助于推荐。 当然最简单的用户标签是浏览过的内容标签。但这里涉及到一些数据处理策略。 主要包括: 一、过滤噪声。通过停留时间短的点击,过滤标题党。 二、热点惩罚。对用户在一些热门文章(如前段时间PG One的新闻)上的动作做降权处理。理论上,传播范围较大的内容,置信度会下降。 三、时间衰减。用户兴趣会发生偏移,因此策略更偏向新的用户行为。因此,随着用户动作的增加,老的特征权重会随时间衰减,新动作贡献的特征权重会更大。 四、惩罚展现。如果一篇推荐给用户的文章没有被点击,相关特征(类别,关键词,来源)权重会被惩罚。当 然同时,也要考虑全局背景,是不是相关内容推送比较多,以及相关的关闭和dislike信号等。 用户标签挖掘总体比较简单,主要还是刚刚提到的工程挑战。头条用户标签第一版是批量计算框架,流程比较简单,每天抽取昨天的日活用户过去两个月的动作数据,在Hadoop集群上批量计算结果。 但问题在于,随着用户高速增长,兴趣模型种类和其他批量处理任务都在增加,涉及到的计算量太大。 2014年,批量处理任务几百万用户标签更新的Hadoop任务,当天完成已经开始勉强。集群计算资源紧张很容易影响其它工作,集中写入分布式存储系统的压力也开始增大,并且用户兴趣标签更新延迟越来越高。 面对这些挑战。2014年底今日头条上线了用户标签Storm集群流式计算系统。改成流式之后,只要有用户动作更新就更新标签,CPU代价比较小,可以节省80%的CPU时间,大大降低了计算资源开销。 同时,只需几十台机器就可以支撑每天数千万用户的兴趣模型更新,并且特征更新速度非常快,基本可以做到准实时。这套系统从上线一直使用至今。 当然,我们也发现并非所有用户标签都需要流式系统。像用户的性别、年龄、常驻地点这些信息,不需要实时重复计算,就仍然保留daily更新。 四、评估分析 上面介绍了推荐系统的整体架构,那么如何评估推荐效果好不好? 有一句我认为非常有智慧的话,“一个事情没法评估就没法优化”。对推荐系统也是一样。 事实上,很多因素都会影响推荐效果。比如侯选集合变化,召回模块的改进或增加,推荐特征的增加,模型架构的改进在,算法参数的优化等等,不一一举例。 评估的意义就在于,很多优化最终可能是负向效果,并不是优化上线后效果就会改进。 全面的评估推荐系统,需要完备的评估体系、强大的实验平台以及易用的经验分析工具。 所谓完备的体系就是并非单一指标衡量,不能只看点击率或者停留时长等,需要综合评估。 很多公司算法做的不好,并非是工程师能力不够,而是需要一个强大的实验平台,还有便捷的实验分析工具,可以智能分析数据指标的置信度。 一个良好的评估体系建立需要遵循几个原则,首先是兼顾短期指标与长期指标。我在之前公司负责电商方向的时候观察到,很多策略调整短期内用户觉得新鲜,但是长期看其实没有任何助益。 其次,要兼顾用户指标和生态指标。既要为内容创作者提供价值,让他更有尊严的创作,也有义务满足用户,这两者要平衡。 还有广告主利益也要考虑,这是多方博弈和平衡的过程。 另外,要注意协同效应的影响。实验中严格的流量隔离很难做到,要注意外部效应。 强大的实验平台非常直接的优点是,当同时在线的实验比较多时,可以由平台自动分配流量,无需人工沟通,并且实验结束流量立即回收,提高管理效率。 这能帮助公司降低分析成本,加快算法迭代效应,使整个系统的算法优化工作能够快速往前推进。 这是头条A/B Test实验系统的基本原理。首先我们会做在离线状态下做好用户分桶,然后线上分配实验流量,将桶里用户打上标签,分给实验组。 举个例子,开一个10%流量的实验,两个实验组各5%,一个5%是基线,策略和线上大盘一样,另外一个是新的策略。 实验过程中用户动作会被搜集,基本上是准实时,每小时都可以看到。但因为小时数据有波动,通常是以天为时间节点来看。动作搜集后会有日志处理、分布式统计、写入数据库,非常便捷。 在这个系统下工程师只需要设置流量需求、实验时间、定义特殊过滤条件,自定义实验组ID。系统可以自动生成:实验数据对比、实验数据置信度、实验结论总结以及实验优化建议。 当然,只有实验平台是远远不够的。线上实验平台只能通过数据指标变化推测用户体验的变化,但数据指标和用户体验存在差异,很多指标不能完全量化。 很多改进仍然要通过人工分析,重大改进需要人工评估二次确认。 五、内容安全 最后要介绍今日头条在内容安全上的一些举措。头条现在已经是国内最大的内容创作与分发凭条,必须越来越重视社会责任和行业领导者的责任。如果1%的推荐内容出现问题,就会产生较大的影响。 现在,今日头条的内容主要来源于两部分,一是具有成熟内容生产能力的PGC平台 一是UGC用户内容,如问答、用户评论、微头条。这两部分内容需要通过统一的审核机制。如果是数量相对少的PGC内容,会直接进行风险审核,没有问题会大范围推荐。 UGC内容需要经过一个风险模型的过滤,有问题的会进入二次风险审核。审核通过后,内容会被真正进行推荐。这时如果收到一定量以上的评论或者举报负向反馈,还会再回到复审环节,有问题直接下架。 整个机制相对而言比较健全,作为行业领先者,在内容安全上,今日头条一直用最高的标准要求自己。 分享内容识别技术主要鉴黄模型,谩骂模型以及低俗模型。今日头条的低俗模型通过深度学习算法训练,样本库非常大,图片、文本同时分析。 这部分模型更注重召回率,准确率甚至可以牺牲一些。谩骂模型的样本库同样超过百万,召回率高达95%+,准确率80%+。如果用户经常出言不讳或者不当的评论,我们有一些惩罚机制。 泛低质识别涉及的情况非常多,像假新闻、黑稿、题文不符、标题党、内容质量低等等,这部分内容由机器理解是非常难的,需要大量反馈信息,包括其他样本信息比对。 目前低质模型的准确率和召回率都不是特别高,还需要结合人工复审,将阈值提高。目前最终的召回已达到95%,这部分其实还有非常多的工作可以做。别平台。 如果需要机器学习视频,可以在公众号后台聊天框回复【机器学习】,可以免费获取编程视频 。 你可能还喜欢 数学在机器学习中到底有多重要? AI 新手学习路线,附上最详细的资源整理! 提升机器学习数学基础,推荐7本书 酷爆了!围观2020年十大科技趋势 机器学习该如何入门,听听过来人的经验! 长按加入T圈,接触人工智能 觉得内容还不错的话,给我点个“在看”呗 本篇文章为转载内容。原文链接:https://blog.csdn.net/itcodexy/article/details/109574173。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2024-01-13 09:21:23
322
转载
转载文章
...;/ 数据生成代码,Kafka Producer产生数据/public class MockAdClickedStat {/ @param args/public static void main(String[] args) {final Random random = new Random();final String[] provinces = new String[]{"Guangdong", "Zhejiang", "Jiangsu", "Fujian"};final Map<String, String[]> cities = new HashMap<String, String[]>();cities.put("Guangdong", new String[]{"Guangzhou", "Shenzhen", "Dongguan"});cities.put("Zhejiang", new String[]{"Hangzhou", "Wenzhou", "Ningbo"});cities.put("Jiangsu", new String[]{"Nanjing", "Suzhou", "Wuxi"});cities.put("Fujian", new String[]{"Fuzhou", "Xiamen", "Sanming"});final String[] ips = new String[] {"192.168.112.240","192.168.112.239","192.168.112.245","192.168.112.246","192.168.112.247","192.168.112.248","192.168.112.249","192.168.112.250","192.168.112.251","192.168.112.252","192.168.112.253","192.168.112.254",};/ Kafka相关的基本配置信息/Properties kafkaConf = new Properties();kafkaConf.put("serializer.class", "kafka.serializer.StringEncoder");kafkaConf.put("metadeta.broker.list", "Master:9092,Worker1:9092,Worker2:9092");ProducerConfig producerConfig = new ProducerConfig(kafkaConf);final Producer<Integer, String> producer = new Producer<Integer, String>(producerConfig);new Thread(new Runnable() {public void run() {while(true) {//在线处理广告点击流的基本数据格式:timestamp、ip、userID、adID、province、cityLong timestamp = new Date().getTime();String ip = ips[random.nextInt(12)]; //可以采用网络上免费提供的ip库int userID = random.nextInt(10000);int adID = random.nextInt(100);String province = provinces[random.nextInt(4)];String city = cities.get(province)[random.nextInt(3)];String clickedAd = timestamp + "\t" + ip + "\t" + userID + "\t" + adID + "\t" + province + "\t" + city;producer.send(new KeyedMessage<Integer, String>("AdClicked", clickedAd));try {Thread.sleep(50);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();} }} }).start();} } package com.tom.spark.SparkApps.sparkstreaming;import java.sql.Connection;import java.sql.DriverManager;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;import java.util.ArrayList;import java.util.Arrays;import java.util.HashMap;import java.util.HashSet;import java.util.Iterator;import java.util.List;import java.util.Map;import java.util.Set;import java.util.concurrent.LinkedBlockingQueue;import kafka.serializer.StringDecoder;import org.apache.spark.SparkConf;import org.apache.spark.api.java.JavaPairRDD;import org.apache.spark.api.java.JavaRDD;import org.apache.spark.api.java.JavaSparkContext;import org.apache.spark.api.java.function.Function;import org.apache.spark.api.java.function.Function2;import org.apache.spark.api.java.function.PairFunction;import org.apache.spark.api.java.function.VoidFunction;import org.apache.spark.sql.DataFrame;import org.apache.spark.sql.Row;import org.apache.spark.sql.RowFactory;import org.apache.spark.sql.hive.HiveContext;import org.apache.spark.sql.types.DataTypes;import org.apache.spark.sql.types.StructType;import org.apache.spark.streaming.Durations;import org.apache.spark.streaming.api.java.JavaDStream;import org.apache.spark.streaming.api.java.JavaPairDStream;import org.apache.spark.streaming.api.java.JavaPairInputDStream;import org.apache.spark.streaming.api.java.JavaStreamingContext;import org.apache.spark.streaming.api.java.JavaStreamingContextFactory;import org.apache.spark.streaming.kafka.KafkaUtils;import com.google.common.base.Optional;import scala.Tuple2;/ 数据处理,Kafka消费者/public class AdClickedStreamingStats {/ @param args/public static void main(String[] args) {// TODO Auto-generated method stub//好处:1、checkpoint 2、工厂final SparkConf conf = new SparkConf().setAppName("SparkStreamingOnKafkaDirect").setMaster("hdfs://Master:7077/");final String checkpointDirectory = "hdfs://Master:9000/library/SparkStreaming/CheckPoint_Data";JavaStreamingContextFactory factory = new JavaStreamingContextFactory() {public JavaStreamingContext create() {// TODO Auto-generated method stubreturn createContext(checkpointDirectory, conf);} };/ 可以从失败中恢复Driver,不过还需要指定Driver这个进程运行在Cluster,并且在提交应用程序的时候制定--supervise;/JavaStreamingContext javassc = JavaStreamingContext.getOrCreate(checkpointDirectory, factory);/ 第三步:创建Spark Streaming输入数据来源input Stream: 1、数据输入来源可以基于File、HDFS、Flume、Kafka、Socket等 2、在这里我们指定数据来源于网络Socket端口,Spark Streaming连接上该端口并在运行的时候一直监听该端口的数据 (当然该端口服务首先必须存在),并且在后续会根据业务需要不断有数据产生(当然对于Spark Streaming 应用程序的运行而言,有无数据其处理流程都是一样的) 3、如果经常在每间隔5秒钟没有数据的话不断启动空的Job其实会造成调度资源的浪费,因为并没有数据需要发生计算;所以 实际的企业级生成环境的代码在具体提交Job前会判断是否有数据,如果没有的话就不再提交Job;///创建Kafka元数据来让Spark Streaming这个Kafka Consumer利用Map<String, String> kafkaParameters = new HashMap<String, String>();kafkaParameters.put("metadata.broker.list", "Master:9092,Worker1:9092,Worker2:9092");Set<String> topics = new HashSet<String>();topics.add("SparkStreamingDirected");JavaPairInputDStream<String, String> adClickedStreaming = KafkaUtils.createDirectStream(javassc, String.class, String.class, StringDecoder.class, StringDecoder.class,kafkaParameters, topics);/因为要对黑名单进行过滤,而数据是在RDD中的,所以必然使用transform这个函数; 但是在这里我们必须使用transformToPair,原因是读取进来的Kafka的数据是Pair<String,String>类型, 另一个原因是过滤后的数据要进行进一步处理,所以必须是读进的Kafka数据的原始类型 在此再次说明,每个Batch Duration中实际上讲输入的数据就是被一个且仅被一个RDD封装的,你可以有多个 InputDStream,但其实在产生job的时候,这些不同的InputDStream在Batch Duration中就相当于Spark基于HDFS 数据操作的不同文件来源而已罢了。/JavaPairDStream<String, String> filteredadClickedStreaming = adClickedStreaming.transformToPair(new Function<JavaPairRDD<String,String>, JavaPairRDD<String,String>>() {public JavaPairRDD<String, String> call(JavaPairRDD<String, String> rdd) throws Exception {/ 在线黑名单过滤思路步骤: 1、从数据库中获取黑名单转换成RDD,即新的RDD实例封装黑名单数据; 2、然后把代表黑名单的RDD的实例和Batch Duration产生的RDD进行Join操作, 准确的说是进行leftOuterJoin操作,也就是说使用Batch Duration产生的RDD和代表黑名单的RDD实例进行 leftOuterJoin操作,如果两者都有内容的话,就会是true,否则的话就是false 我们要留下的是leftOuterJoin结果为false; /final List<String> blackListNames = new ArrayList<String>();JDBCWrapper jdbcWrapper = JDBCWrapper.getJDBCInstance();jdbcWrapper.doQuery("SELECT FROM blacklisttable", null, new ExecuteCallBack() {public void resultCallBack(ResultSet result) throws Exception {while(result.next()){blackListNames.add(result.getString(1));} }});List<Tuple2<String, Boolean>> blackListTuple = new ArrayList<Tuple2<String,Boolean>>();for(String name : blackListNames) {blackListTuple.add(new Tuple2<String, Boolean>(name, true));}List<Tuple2<String, Boolean>> blacklistFromListDB = blackListTuple; //数据来自于查询的黑名单表并且映射成为<String, Boolean>JavaSparkContext jsc = new JavaSparkContext(rdd.context());/ 黑名单的表中只有userID,但是如果要进行join操作的话就必须是Key-Value,所以在这里我们需要 基于数据表中的数据产生Key-Value类型的数据集合/JavaPairRDD<String, Boolean> blackListRDD = jsc.parallelizePairs(blacklistFromListDB);/ 进行操作的时候肯定是基于userID进行join,所以必须把传入的rdd进行mapToPair操作转化成为符合格式的RDD/JavaPairRDD<String, Tuple2<String, String>> rdd2Pair = rdd.mapToPair(new PairFunction<Tuple2<String,String>, String, Tuple2<String, String>>() {public Tuple2<String, Tuple2<String, String>> call(Tuple2<String, String> t) throws Exception {// TODO Auto-generated method stubString userID = t._2.split("\t")[2];return new Tuple2<String, Tuple2<String,String>>(userID, t);} });JavaPairRDD<String, Tuple2<Tuple2<String, String>, Optional<Boolean>>> joined = rdd2Pair.leftOuterJoin(blackListRDD);JavaPairRDD<String, String> result = joined.filter(new Function<Tuple2<String,Tuple2<Tuple2<String,String>,Optional<Boolean>>>, Boolean>() {public Boolean call(Tuple2<String, Tuple2<Tuple2<String, String>, Optional<Boolean>>> tuple)throws Exception {// TODO Auto-generated method stubOptional<Boolean> optional = tuple._2._2;if(optional.isPresent() && optional.get()){return false;} else {return true;} }}).mapToPair(new PairFunction<Tuple2<String,Tuple2<Tuple2<String,String>,Optional<Boolean>>>, String, String>() {public Tuple2<String, String> call(Tuple2<String, Tuple2<Tuple2<String, String>, Optional<Boolean>>> t)throws Exception {// TODO Auto-generated method stubreturn t._2._1;} });return result;} });//广告点击的基本数据格式:timestamp、ip、userID、adID、province、cityJavaPairDStream<String, Long> pairs = filteredadClickedStreaming.mapToPair(new PairFunction<Tuple2<String,String>, String, Long>() {public Tuple2<String, Long> call(Tuple2<String, String> t) throws Exception {String[] splited=t._2.split("\t");String timestamp = splited[0]; //YYYY-MM-DDString ip = splited[1];String userID = splited[2];String adID = splited[3];String province = splited[4];String city = splited[5]; String clickedRecord = timestamp + "_" +ip + "_"+userID+"_"+adID+"_"+province +"_"+city;return new Tuple2<String, Long>(clickedRecord, 1L);} });/ 第4.3步:在单词实例计数为1基础上,统计每个单词在文件中出现的总次数/JavaPairDStream<String, Long> adClickedUsers= pairs.reduceByKey(new Function2<Long, Long, Long>() {public Long call(Long i1, Long i2) throws Exception{return i1 + i2;} });/判断有效的点击,复杂化的采用机器学习训练模型进行在线过滤 简单的根据ip判断1天不超过100次;也可以通过一个batch duration的点击次数判断是否非法广告点击,通过一个batch来判断是不完整的,还需要一天的数据也可以每一个小时来判断。/JavaPairDStream<String, Long> filterClickedBatch = adClickedUsers.filter(new Function<Tuple2<String,Long>, Boolean>() {public Boolean call(Tuple2<String, Long> v1) throws Exception {if (1 < v1._2){//更新一些黑名单的数据库表return false;} else { return true;} }});//filterClickedBatch.print();//写入数据库filterClickedBatch.foreachRDD(new Function<JavaPairRDD<String,Long>, Void>() {public Void call(JavaPairRDD<String, Long> rdd) throws Exception {rdd.foreachPartition(new VoidFunction<Iterator<Tuple2<String,Long>>>() {public void call(Iterator<Tuple2<String, Long>> partition) throws Exception {//使用数据库连接池的高效读写数据库的方式将数据写入数据库mysql//例如一次插入 1000条 records,使用insertBatch 或 updateBatch//插入的用户数据信息:userID,adID,clickedCount,time//这里面有一个问题,可能出现两条记录的key是一样的,此时需要更新累加操作List<UserAdClicked> userAdClickedList = new ArrayList<UserAdClicked>();while(partition.hasNext()) {Tuple2<String, Long> record = partition.next();String[] splited = record._1.split("\t");UserAdClicked userClicked = new UserAdClicked();userClicked.setTimestamp(splited[0]);userClicked.setIp(splited[1]);userClicked.setUserID(splited[2]);userClicked.setAdID(splited[3]);userClicked.setProvince(splited[4]);userClicked.setCity(splited[5]);userAdClickedList.add(userClicked);}final List<UserAdClicked> inserting = new ArrayList<UserAdClicked>();final List<UserAdClicked> updating = new ArrayList<UserAdClicked>();JDBCWrapper jdbcWrapper = JDBCWrapper.getJDBCInstance();//表的字段timestamp、ip、userID、adID、province、city、clickedCountfor(final UserAdClicked clicked : userAdClickedList) {jdbcWrapper.doQuery("SELECT clickedCount FROM adclicked WHERE"+ " timestamp =? AND userID = ? AND adID = ?",new Object[]{clicked.getTimestamp(), clicked.getUserID(),clicked.getAdID()}, new ExecuteCallBack() {public void resultCallBack(ResultSet result) throws Exception {// TODO Auto-generated method stubif(result.next()) {long count = result.getLong(1);clicked.setClickedCount(count);updating.add(clicked);} else {inserting.add(clicked);clicked.setClickedCount(1L);} }});}//表的字段timestamp、ip、userID、adID、province、city、clickedCountList<Object[]> insertParametersList = new ArrayList<Object[]>();for(UserAdClicked insertRecord : inserting) {insertParametersList.add(new Object[] {insertRecord.getTimestamp(),insertRecord.getIp(),insertRecord.getUserID(),insertRecord.getAdID(),insertRecord.getProvince(),insertRecord.getCity(),insertRecord.getClickedCount()});}jdbcWrapper.doBatch("INSERT INTO adclicked VALUES(?, ?, ?, ?, ?, ?, ?)", insertParametersList);//表的字段timestamp、ip、userID、adID、province、city、clickedCountList<Object[]> updateParametersList = new ArrayList<Object[]>();for(UserAdClicked updateRecord : updating) {updateParametersList.add(new Object[] {updateRecord.getTimestamp(),updateRecord.getIp(),updateRecord.getUserID(),updateRecord.getAdID(),updateRecord.getProvince(),updateRecord.getCity(),updateRecord.getClickedCount() + 1});}jdbcWrapper.doBatch("UPDATE adclicked SET clickedCount = ? WHERE"+ " timestamp =? AND ip = ? AND userID = ? AND adID = ? "+ "AND province = ? AND city = ?", updateParametersList);} });return null;} });//再次过滤,从数据库中读取数据过滤黑名单JavaPairDStream<String, Long> blackListBasedOnHistory = filterClickedBatch.filter(new Function<Tuple2<String,Long>, Boolean>() {public Boolean call(Tuple2<String, Long> v1) throws Exception {//广告点击的基本数据格式:timestamp,ip,userID,adID,province,cityString[] splited = v1._1.split("\t"); //提取key值String date =splited[0];String userID =splited[2];String adID =splited[3];//查询一下数据库同一个用户同一个广告id点击量超过50次列入黑名单//接下来 根据date、userID、adID条件去查询用户点击广告的数据表,获得总的点击次数//这个时候基于点击次数判断是否属于黑名单点击int clickedCountTotalToday = 81 ;if (clickedCountTotalToday > 50) {return true;}else {return false ;} }});//map操作,找出用户的idJavaDStream<String> blackListuserIDBasedInBatchOnhistroy =blackListBasedOnHistory.map(new Function<Tuple2<String,Long>, String>() {public String call(Tuple2<String, Long> v1) throws Exception {// TODO Auto-generated method stubreturn v1._1.split("\t")[2];} });//有一个问题,数据可能重复,在一个partition里面重复,这个好办;//但多个partition不能保证一个用户重复,需要对黑名单的整个rdd进行去重操作。//rdd去重了,partition也就去重了,一石二鸟,一箭双雕// 找出了黑名单,下一步就写入黑名单数据库表中JavaDStream<String> blackListUniqueuserBasedInBatchOnhistroy = blackListuserIDBasedInBatchOnhistroy.transform(new Function<JavaRDD<String>, JavaRDD<String>>() {public JavaRDD<String> call(JavaRDD<String> rdd) throws Exception {// TODO Auto-generated method stubreturn rdd.distinct();} });// 下一步写入到数据表中blackListUniqueuserBasedInBatchOnhistroy.foreachRDD(new Function<JavaRDD<String>, Void>() {public Void call(JavaRDD<String> rdd) throws Exception {rdd.foreachPartition(new VoidFunction<Iterator<String>>() {public void call(Iterator<String> t) throws Exception {// TODO Auto-generated method stub//插入的用户信息可以只包含:useID//此时直接插入黑名单数据表即可。//写入数据库List<Object[]> blackList = new ArrayList<Object[]>();while(t.hasNext()) {blackList.add(new Object[]{t.next()});}JDBCWrapper jdbcWrapper = JDBCWrapper.getJDBCInstance();jdbcWrapper.doBatch("INSERT INTO blacklisttable values (?)", blackList);} });return null;} });/广告点击累计动态更新,每个updateStateByKey都会在Batch Duration的时间间隔的基础上进行广告点击次数的更新, 更新之后我们一般都会持久化到外部存储设备上,在这里我们存储到MySQL数据库中/JavaPairDStream<String, Long> updateStateByKeyDSteam = filteredadClickedStreaming.mapToPair(new PairFunction<Tuple2<String,String>, String, Long>() {public Tuple2<String, Long> call(Tuple2<String, String> t)throws Exception {String[] splited=t._2.split("\t");String timestamp = splited[0]; //YYYY-MM-DDString ip = splited[1];String userID = splited[2];String adID = splited[3];String province = splited[4];String city = splited[5]; String clickedRecord = timestamp + "_" +ip + "_"+userID+"_"+adID+"_"+province +"_"+city;return new Tuple2<String, Long>(clickedRecord, 1L);} }).updateStateByKey(new Function2<List<Long>, Optional<Long>, Optional<Long>>() {public Optional<Long> call(List<Long> v1, Optional<Long> v2)throws Exception {// v1:当前的Key在当前的Batch Duration中出现的次数的集合,例如{1,1,1,。。。,1}// v2:当前的Key在以前的Batch Duration中积累下来的结果;Long clickedTotalHistory = 0L; if(v2.isPresent()){clickedTotalHistory = v2.get();}for(Long one : v1) {clickedTotalHistory += one;}return Optional.of(clickedTotalHistory);} });updateStateByKeyDSteam.foreachRDD(new Function<JavaPairRDD<String,Long>, Void>() {public Void call(JavaPairRDD<String, Long> rdd) throws Exception {rdd.foreachPartition(new VoidFunction<Iterator<Tuple2<String,Long>>>() {public void call(Iterator<Tuple2<String, Long>> partition) throws Exception {//使用数据库连接池的高效读写数据库的方式将数据写入数据库mysql//例如一次插入 1000条 records,使用insertBatch 或 updateBatch//插入的用户数据信息:timestamp、adID、province、city//这里面有一个问题,可能出现两条记录的key是一样的,此时需要更新累加操作List<AdClicked> AdClickedList = new ArrayList<AdClicked>();while(partition.hasNext()) {Tuple2<String, Long> record = partition.next();String[] splited = record._1.split("\t");AdClicked adClicked = new AdClicked();adClicked.setTimestamp(splited[0]);adClicked.setAdID(splited[1]);adClicked.setProvince(splited[2]);adClicked.setCity(splited[3]);adClicked.setClickedCount(record._2);AdClickedList.add(adClicked);}final List<AdClicked> inserting = new ArrayList<AdClicked>();final List<AdClicked> updating = new ArrayList<AdClicked>();JDBCWrapper jdbcWrapper = JDBCWrapper.getJDBCInstance();//表的字段timestamp、ip、userID、adID、province、city、clickedCountfor(final AdClicked clicked : AdClickedList) {jdbcWrapper.doQuery("SELECT clickedCount FROM adclickedcount WHERE"+ " timestamp = ? AND adID = ? AND province = ? AND city = ?",new Object[]{clicked.getTimestamp(), clicked.getAdID(),clicked.getProvince(), clicked.getCity()}, new ExecuteCallBack() {public void resultCallBack(ResultSet result) throws Exception {// TODO Auto-generated method stubif(result.next()) {long count = result.getLong(1);clicked.setClickedCount(count);updating.add(clicked);} else {inserting.add(clicked);clicked.setClickedCount(1L);} }});}//表的字段timestamp、ip、userID、adID、province、city、clickedCountList<Object[]> insertParametersList = new ArrayList<Object[]>();for(AdClicked insertRecord : inserting) {insertParametersList.add(new Object[] {insertRecord.getTimestamp(),insertRecord.getAdID(),insertRecord.getProvince(),insertRecord.getCity(),insertRecord.getClickedCount()});}jdbcWrapper.doBatch("INSERT INTO adclickedcount VALUES(?, ?, ?, ?, ?)", insertParametersList);//表的字段timestamp、ip、userID、adID、province、city、clickedCountList<Object[]> updateParametersList = new ArrayList<Object[]>();for(AdClicked updateRecord : updating) {updateParametersList.add(new Object[] {updateRecord.getClickedCount(),updateRecord.getTimestamp(),updateRecord.getAdID(),updateRecord.getProvince(),updateRecord.getCity()});}jdbcWrapper.doBatch("UPDATE adclickedcount SET clickedCount = ? WHERE"+ " timestamp =? AND adID = ? AND province = ? AND city = ?", updateParametersList);} });return null;} });/ 对广告点击进行TopN计算,计算出每天每个省份Top5排名的广告 因为我们直接对RDD进行操作,所以使用了transfomr算子;/updateStateByKeyDSteam.transform(new Function<JavaPairRDD<String,Long>, JavaRDD<Row>>() {public JavaRDD<Row> call(JavaPairRDD<String, Long> rdd) throws Exception {JavaRDD<Row> rowRDD = rdd.mapToPair(new PairFunction<Tuple2<String,Long>, String, Long>() {public Tuple2<String, Long> call(Tuple2<String, Long> t)throws Exception {// TODO Auto-generated method stubString[] splited=t._1.split("_");String timestamp = splited[0]; //YYYY-MM-DDString adID = splited[3];String province = splited[4];String clickedRecord = timestamp + "_" + adID + "_" + province;return new Tuple2<String, Long>(clickedRecord, t._2);} }).reduceByKey(new Function2<Long, Long, Long>() {public Long call(Long v1, Long v2) throws Exception {// TODO Auto-generated method stubreturn v1 + v2;} }).map(new Function<Tuple2<String,Long>, Row>() {public Row call(Tuple2<String, Long> v1) throws Exception {// TODO Auto-generated method stubString[] splited=v1._1.split("_");String timestamp = splited[0]; //YYYY-MM-DDString adID = splited[3];String province = splited[4];return RowFactory.create(timestamp, adID, province, v1._2);} });StructType structType = DataTypes.createStructType(Arrays.asList(DataTypes.createStructField("timestamp", DataTypes.StringType, true),DataTypes.createStructField("adID", DataTypes.StringType, true),DataTypes.createStructField("province", DataTypes.StringType, true),DataTypes.createStructField("clickedCount", DataTypes.LongType, true)));HiveContext hiveContext = new HiveContext(rdd.context());DataFrame df = hiveContext.createDataFrame(rowRDD, structType);df.registerTempTable("topNTableSource");DataFrame result = hiveContext.sql("SELECT timestamp, adID, province, clickedCount, FROM"+ " (SELECT timestamp, adID, province,clickedCount, "+ "ROW_NUMBER() OVER(PARTITION BY province ORDER BY clickeCount DESC) rank "+ "FROM topNTableSource) subquery "+ "WHERE rank <= 5");return result.toJavaRDD();} }).foreachRDD(new Function<JavaRDD<Row>, Void>() {public Void call(JavaRDD<Row> rdd) throws Exception {// TODO Auto-generated method stubrdd.foreachPartition(new VoidFunction<Iterator<Row>>() {public void call(Iterator<Row> t) throws Exception {// TODO Auto-generated method stubList<AdProvinceTopN> adProvinceTopN = new ArrayList<AdProvinceTopN>();while(t.hasNext()) {Row row = t.next();AdProvinceTopN item = new AdProvinceTopN();item.setTimestamp(row.getString(0));item.setAdID(row.getString(1));item.setProvince(row.getString(2));item.setClickedCount(row.getLong(3));adProvinceTopN.add(item);}// final List<AdProvinceTopN> inserting = new ArrayList<AdProvinceTopN>();// final List<AdProvinceTopN> updating = new ArrayList<AdProvinceTopN>();JDBCWrapper jdbcWrapper = JDBCWrapper.getJDBCInstance();Set<String> set = new HashSet<String>();for(AdProvinceTopN item: adProvinceTopN){set.add(item.getTimestamp() + "_" + item.getProvince());}//表的字段timestamp、adID、province、clickedCountArrayList<Object[]> deleteParametersList = new ArrayList<Object[]>();for(String deleteRecord : set) {String[] splited = deleteRecord.split("_");deleteParametersList.add(new Object[]{splited[0],splited[1]});}jdbcWrapper.doBatch("DELETE FROM adprovincetopn WHERE timestamp = ? AND province = ?", deleteParametersList);//表的字段timestamp、ip、userID、adID、province、city、clickedCountList<Object[]> insertParametersList = new ArrayList<Object[]>();for(AdProvinceTopN insertRecord : adProvinceTopN) {insertParametersList.add(new Object[] {insertRecord.getClickedCount(),insertRecord.getTimestamp(),insertRecord.getAdID(),insertRecord.getProvince()});}jdbcWrapper.doBatch("INSERT INTO adprovincetopn VALUES (?, ?, ?, ?)", insertParametersList);} });return null;} });/ 计算过去半个小时内广告点击的趋势 广告点击的基本数据格式:timestamp、ip、userID、adID、province、city/filteredadClickedStreaming.mapToPair(new PairFunction<Tuple2<String,String>, String, Long>() {public Tuple2<String, Long> call(Tuple2<String, String> t)throws Exception {String splited[] = t._2.split("\t");String adID = splited[3];String time = splited[0]; //Todo:后续需要重构代码实现时间戳和分钟的转换提取。此处需要提取出该广告的点击分钟单位return new Tuple2<String, Long>(time + "_" + adID, 1L);} }).reduceByKeyAndWindow(new Function2<Long, Long, Long>() {public Long call(Long v1, Long v2) throws Exception {// TODO Auto-generated method stubreturn v1 + v2;} }, new Function2<Long, Long, Long>() {public Long call(Long v1, Long v2) throws Exception {// TODO Auto-generated method stubreturn v1 - v2;} }, Durations.minutes(30), Durations.milliseconds(5)).foreachRDD(new Function<JavaPairRDD<String,Long>, Void>() {public Void call(JavaPairRDD<String, Long> rdd) throws Exception {// TODO Auto-generated method stubrdd.foreachPartition(new VoidFunction<Iterator<Tuple2<String,Long>>>() {public void call(Iterator<Tuple2<String, Long>> partition)throws Exception {List<AdTrendStat> adTrend = new ArrayList<AdTrendStat>();// TODO Auto-generated method stubwhile(partition.hasNext()) {Tuple2<String, Long> record = partition.next();String[] splited = record._1.split("_");String time = splited[0];String adID = splited[1];Long clickedCount = record._2;/ 在插入数据到数据库的时候具体需要哪些字段?time、adID、clickedCount; 而我们通过J2EE技术进行趋势绘图的时候肯定是需要年、月、日、时、分这个维度的,所以我们在这里需要 年月日、小时、分钟这些时间维度;/AdTrendStat adTrendStat = new AdTrendStat();adTrendStat.setAdID(adID);adTrendStat.setClickedCount(clickedCount);adTrendStat.set_date(time); //Todo:获取年月日adTrendStat.set_hour(time); //Todo:获取小时adTrendStat.set_minute(time);//Todo:获取分钟adTrend.add(adTrendStat);}final List<AdTrendStat> inserting = new ArrayList<AdTrendStat>();final List<AdTrendStat> updating = new ArrayList<AdTrendStat>();JDBCWrapper jdbcWrapper = JDBCWrapper.getJDBCInstance();//表的字段timestamp、ip、userID、adID、province、city、clickedCountfor(final AdTrendStat trend : adTrend) {final AdTrendCountHistory adTrendhistory = new AdTrendCountHistory();jdbcWrapper.doQuery("SELECT clickedCount FROM adclickedtrend WHERE"+ " date =? AND hour = ? AND minute = ? AND AdID = ?",new Object[]{trend.get_date(), trend.get_hour(), trend.get_minute(),trend.getAdID()}, new ExecuteCallBack() {public void resultCallBack(ResultSet result) throws Exception {// TODO Auto-generated method stubif(result.next()) {long count = result.getLong(1);adTrendhistory.setClickedCountHistoryLong(count);updating.add(trend);} else { inserting.add(trend);} }});}//表的字段date、hour、minute、adID、clickedCountList<Object[]> insertParametersList = new ArrayList<Object[]>();for(AdTrendStat insertRecord : inserting) {insertParametersList.add(new Object[] {insertRecord.get_date(),insertRecord.get_hour(),insertRecord.get_minute(),insertRecord.getAdID(),insertRecord.getClickedCount()});}jdbcWrapper.doBatch("INSERT INTO adclickedtrend VALUES(?, ?, ?, ?, ?)", insertParametersList);//表的字段date、hour、minute、adID、clickedCountList<Object[]> updateParametersList = new ArrayList<Object[]>();for(AdTrendStat updateRecord : updating) {updateParametersList.add(new Object[] {updateRecord.getClickedCount(),updateRecord.get_date(),updateRecord.get_hour(),updateRecord.get_minute(),updateRecord.getAdID()});}jdbcWrapper.doBatch("UPDATE adclickedtrend SET clickedCount = ? WHERE"+ " date =? AND hour = ? AND minute = ? AND AdID = ?", updateParametersList);} });return null;} });;/ Spark Streaming 执行引擎也就是Driver开始运行,Driver启动的时候是位于一条新的线程中的,当然其内部有消息循环体,用于 接收应用程序本身或者Executor中的消息,/javassc.start();javassc.awaitTermination();javassc.close();}private static JavaStreamingContext createContext(String checkpointDirectory, SparkConf conf) {// If you do not see this printed, that means the StreamingContext has been loaded// from the new checkpointSystem.out.println("Creating new context");// Create the context with a 5 second batch sizeJavaStreamingContext ssc = new JavaStreamingContext(conf, Durations.seconds(10));ssc.checkpoint(checkpointDirectory);return ssc;} }class JDBCWrapper {private static JDBCWrapper jdbcInstance = null;private static LinkedBlockingQueue<Connection> dbConnectionPool = new LinkedBlockingQueue<Connection>();static {try {Class.forName("com.mysql.jdbc.Driver");} catch (ClassNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();} }public static JDBCWrapper getJDBCInstance() {if(jdbcInstance == null) {synchronized (JDBCWrapper.class) {if(jdbcInstance == null) {jdbcInstance = new JDBCWrapper();} }}return jdbcInstance; }private JDBCWrapper() {for(int i = 0; i < 10; i++){try {Connection conn = DriverManager.getConnection("jdbc:mysql://Master:3306/sparkstreaming","root", "root");dbConnectionPool.put(conn);} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();} } }public synchronized Connection getConnection() {while(0 == dbConnectionPool.size()){try {Thread.sleep(20);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();} }return dbConnectionPool.poll();}public int[] doBatch(String sqlText, List<Object[]> paramsList){Connection conn = getConnection();PreparedStatement preparedStatement = null;int[] result = null;try {conn.setAutoCommit(false);preparedStatement = conn.prepareStatement(sqlText);for(Object[] parameters: paramsList) {for(int i = 0; i < parameters.length; i++){preparedStatement.setObject(i + 1, parameters[i]);} preparedStatement.addBatch();}result = preparedStatement.executeBatch();conn.commit();} catch (SQLException e) {// TODO Auto-generated catch blocke.printStackTrace();} finally {if(preparedStatement != null) {try {preparedStatement.close();} catch (SQLException e) {// TODO Auto-generated catch blocke.printStackTrace();} }if(conn != null) {try {dbConnectionPool.put(conn);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();} }}return result; }public void doQuery(String sqlText, Object[] paramsList, ExecuteCallBack callback){Connection conn = getConnection();PreparedStatement preparedStatement = null;ResultSet result = null;try {preparedStatement = conn.prepareStatement(sqlText);for(int i = 0; i < paramsList.length; i++){preparedStatement.setObject(i + 1, paramsList[i]);} result = preparedStatement.executeQuery();try {callback.resultCallBack(result);} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();} } catch (SQLException e) {// TODO Auto-generated catch blocke.printStackTrace();} finally {if(preparedStatement != null) {try {preparedStatement.close();} catch (SQLException e) {// TODO Auto-generated catch blocke.printStackTrace();} }if(conn != null) {try {dbConnectionPool.put(conn);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();} }} }}interface ExecuteCallBack {void resultCallBack(ResultSet result) throws Exception;}class UserAdClicked {private String timestamp;private String ip;private String userID;private String adID;private String province;private String city;private Long clickedCount;public String getTimestamp() {return timestamp;}public void setTimestamp(String timestamp) {this.timestamp = timestamp;}public String getIp() {return ip;}public void setIp(String ip) {this.ip = ip;}public String getUserID() {return userID;}public void setUserID(String userID) {this.userID = userID;}public String getAdID() {return adID;}public void setAdID(String adID) {this.adID = adID;}public String getProvince() {return province;}public void setProvince(String province) {this.province = province;}public String getCity() {return city;}public void setCity(String city) {this.city = city;}public Long getClickedCount() {return clickedCount;}public void setClickedCount(Long clickedCount) {this.clickedCount = clickedCount;} }class AdClicked {private String timestamp;private String adID;private String province;private String city;private Long clickedCount;public String getTimestamp() {return timestamp;}public void setTimestamp(String timestamp) {this.timestamp = timestamp;}public String getAdID() {return adID;}public void setAdID(String adID) {this.adID = adID;}public String getProvince() {return province;}public void setProvince(String province) {this.province = province;}public String getCity() {return city;}public void setCity(String city) {this.city = city;}public Long getClickedCount() {return clickedCount;}public void setClickedCount(Long clickedCount) {this.clickedCount = clickedCount;} }class AdProvinceTopN {private String timestamp;private String adID;private String province;private Long clickedCount;public String getTimestamp() {return timestamp;}public void setTimestamp(String timestamp) {this.timestamp = timestamp;}public String getAdID() {return adID;}public void setAdID(String adID) {this.adID = adID;}public String getProvince() {return province;}public void setProvince(String province) {this.province = province;}public Long getClickedCount() {return clickedCount;}public void setClickedCount(Long clickedCount) {this.clickedCount = clickedCount;} }class AdTrendStat {private String _date;private String _hour;private String _minute;private String adID;private Long clickedCount;public String get_date() {return _date;}public void set_date(String _date) {this._date = _date;}public String get_hour() {return _hour;}public void set_hour(String _hour) {this._hour = _hour;}public String get_minute() {return _minute;}public void set_minute(String _minute) {this._minute = _minute;}public String getAdID() {return adID;}public void setAdID(String adID) {this.adID = adID;}public Long getClickedCount() {return clickedCount;}public void setClickedCount(Long clickedCount) {this.clickedCount = clickedCount;} }class AdTrendCountHistory{private Long clickedCountHistoryLong;public Long getClickedCountHistoryLong() {return clickedCountHistoryLong;}public void setClickedCountHistoryLong(Long clickedCountHistoryLong) {this.clickedCountHistoryLong = clickedCountHistoryLong;} } 本篇文章为转载内容。原文链接:https://blog.csdn.net/tom_8899_li/article/details/71194434。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-02-14 19:16:35
297
转载
转载文章
...s库中的verify参数为False来忽略证书验证,从而继续爬取数据。 cookie , Cookie是一种由服务器发送到用户浏览器并存储在用户本地的小型文本文件。它通常包含识别用户会话或持久化用户状态的信息,如登录凭证、用户偏好等。在网络爬虫应用中,模拟用户登录状态常需要利用cookie,通过在HTTP请求头中携带已登录用户的cookie信息,使得爬虫可以像真实用户那样访问受权限保护的内容。 session , Session是指在一次用户会话过程中,服务器为该用户维护的状态信息集合。与cookie不同的是,session数据存储在服务器端,而客户端仅存储一个会话标识符(session ID),通常也以cookie的形式存在。在网络爬虫中使用session对象(如requests库中的requests.session()方法创建的对象),可以帮助爬虫维持与服务器之间的状态信息,实现连续操作间的关联和认证,这对于处理需要保持登录状态或进行多次交互的网页抓取任务尤为关键。
2023-03-01 12:40:55
563
转载
站内搜索
用于搜索本网站内部文章,支持栏目切换。
知识学习
实践的时候请根据实际情况谨慎操作。
随机学习一条linux命令:
echo $BASH_VERSION
- 显示当前bash shell版本。
推荐内容
推荐本栏目内的其它文章,看看还有哪些文章让你感兴趣。
2023-04-28
2023-08-09
2023-06-18
2023-04-14
2023-02-18
2023-04-17
2024-01-11
2023-10-03
2023-09-09
2023-06-13
2023-08-07
2023-03-11
历史内容
快速导航到对应月份的历史文章列表。
随便看看
拉到页底了吧,随便看看还有哪些文章你可能感兴趣。
时光飞逝
"流光容易把人抛,红了樱桃,绿了芭蕉。"