-
十亿用户数据,上千个用户标签维度,用户分析怎么做?
2021-02-07 14:52:231月14日,Kyligence 产品经理陈思捷开启了我们在 2021 年的首场线上分享,为大家介绍了用户行为分析的应用场景、以及通过一些行业案例展示如何使用 Kyligence 进行用户行为分析,最后用 Demo 演示了具体的行为分析...1月14日,Kyligence 产品经理陈思捷开启了我们在 2021 年的首场线上分享,为大家介绍了用户行为分析的应用场景、以及通过一些行业案例展示如何使用 Kyligence 进行用户行为分析,最后用 Demo 演示了具体的行为分析过程,还有大家在会上的 Q&A 解答,感兴趣的小伙伴别错过啦。
用户行为分析是什么?
用户行为是指用户为使用产品或获取服务而进行的一系列行动。以网站或者手机应用为例,用户点击按钮、跳出网页、注册等都属于用户行为,而用户行为分析是指对用户行为数据进行分析。
为什么大部分企业都需要做用户行为分析呢?- 快速决策。处理和解释用户行为信息的速度越快,就能更快掌握目前业务状况,从而帮助更早做出决策判断,团队可以第一时间采取措施积极应对。
- 更完整的用户画像。基于用户行为数据的这种用户模型中,记录了每个用户的每一次行为,这样可以客观、真实地还原用户与产品的交互过程,从事实的角度帮助构建更加完整、真实的用户画像。
- 精细化运营。用户行为数据是动态变化的,随着用户从认知,熟悉,最后成为高价值用户,用户的每个行为都记录了下来。不同阶段的用户可以分别采取有针对性的运营策略。
用户行为分析的应用场景
用户行为分析的典型场景流程就是这样的:
- 第一步:通过分析埋点数据,还原用户使用产品的全流程路径,可视化显示用户访问路径,从整体的视角查看用户在各个节点上的流量,定位关键路径。
- 第二步:指定关键步骤进行漏斗分析,得到各个步骤的转化率和流失率,定位转化步骤中的问题节点和客群。
- 第三步:再将关键步骤中的客群与标签数据联动,得到这客群的价值分布。
- 最后,有了完善的数据做支持,业务人员不仅能够在指定运营策略的过程中,参考过往的活动数据,做到手中有数,心中有谱。
所谓自助式闭环分析,就是能够在第一时间,对当前的运营策略进行及时的效果评估,并根据具体情况和必要性进行快速调整,将运营活动的效果进一步优化。产品调整或运营活动执行之后进行效果追踪,又可以将结果反馈到路径分析环节中,来得到优化后的直观展示。
接下来看看用户行为分析在各行各业中有哪些实践应用?1)金融领域,提高订单的转化率
在金融领域中,对于理财类产品的运营人员,首要关注理财产品订单转化率。理财 APP 中一个典型的用户行为路径是:用户先浏览详情页之后,加入购物车,提交订单,最后到成功支付。
为了提高订单的转换率,需要分析用户从看到商品,到最后支付成功的各个环节的流程。定位流失率高的步骤,分析此步骤中流失用户有什么特点,用于指导产品优化;如果发现加入购物车步骤流失较高,且发现这部分流失用户的设备类型 75% 都是安卓,这可能说明了安卓系统的 APP 加入购物车页面、按钮有问题。通过修复安卓版本 APP,从而提高了订单成单数量。
利用好用户行为分析,就可以对产品、服务进行优化从而引导用户进行转换,或者引导用户进行复购。2)社交领域,注重用户获取
在社交领取中,分析人员特别注重的是用户从哪个搜索引擎带来的流量、点击哪个入口进入社交网站界面,且注册成功、以及在社交网站中参与社交互动的行为和频次。通过分析新用户从开始使用到参加社交这个过程的转化情况,进行渠道资源评估、投放效果评估,找寻最佳拉新渠道资源。
3)零售领域,关心营销优化
在零售行业的促销活动中,营销人员首先通过分析以往的历史数据,找出一批优质的高价值用户名单,例如近七天之内未访问平台的用户,然后在推送平台中发送短信,用户收到短信后,点击链接领取优惠券,吸引用户进行消费;再通过一定时间的观察以后,针对完成首单的用户通过APP 推送的方式发放优惠券,刺激二次消费。这个过程中,就需要分析用户的转化行为和留存行为。
综上,在接触到的许多客户案例中,特别是精细化运营过程中都需要构建个性化的用户旅程,在用户旅程的不同时机,适时传递用户所需,从而提升用户转化和留存。但随着移动化、数字化、智能化不断加强,各大企业持续加大对线上渠道的建设投入,线上的用户数不断增加,用户行为数据量也在增加。而进行用户行为分析,总是会遇到难点。用户行为分析的现状及挑战
对于许多大型企业来说,日常面对数十亿用户数据,上千个用户标签维度,用户行为分析就面临巨大挑战。
首先是底层的数据结构无法支撑复杂的分析需求,此时需要技术人员投入大量精力和时间,来进行跨表、跨库的查询,处理无法被复用的数据请求。在灵活的维度组合下,分析人员无法快速得到查询结果,甚至计算不出结果。
数据割裂也是用户关心的问题。当数据散落在多个系统中时,就无法支持多维度的下钻分析或精细分析。无法进一步分析查看用户明细和用户特征,行为分析流于表面,只有转化表现而缺乏转化原因的探查入口。
进行用户行为分析时,由于 SQL 难度高,业务人员需要依赖大数据部门或者研发部门排期编写、维护 SQL 逻辑,不仅维护困难,开发周期还很长。当有业务调整需要时,又需要另外的开发周期,无法快速响应业务上的诉求。
如何应对海量数据、多维度、高基数的分析挑战?- 首先需要更强大的计算引擎提供分析,支持海量数据分析和低延迟;并且在数据量增长、业务需求增长的情况下,保证稳定的查询体验。
- 其次,我们需要一个统一的数据模型,帮助企业创建数据资产之间的关联,以获得对数据更全面的视角。还应支持数据导出,与画像系统联动、与营销系统打通。
- 最后,应该提供拖拽式的行为分析。用户根据相关业务,灵活地创建图表,分析自己想要看的行为数据。易学易用,快速上手。不仅如此,用户还可以灵活的多维选择进行组合查询、下钻分析和明细信息查询。
总结一下,强大的计算引擎、统一的数据模型和自助式的分析体验是企业在大数据场景下做好用户行为分析的关键。
Kyligence 如何助力企业用户行为分析
1)技术架构
下图中底层蓝色的部分是 Kyligence 的数据处理计算部分,依托于存储与计算分离的特性以及预计算能力,Kyligence能够很好地满足在海量数据场景下的数据高效计算能力。同时 Kyligence 还提供了完善的企业级平台运维处理能力,支持多种架构满足各类客户的场景需求。
往上,通过 Kyligence 多维数据模型框架,对用户基础数据进行语义分类和转化,提供多种维度分类的数据主题模型。基于这些数据主题模型,就可以直接对接应用分析端进行常用的事件分析,漏斗分析,留存分析了。
总结下 Kyligence 用户行为分析的解决方案主要有以下 4 点强大功能:- 支持从多种数据仓库、数据湖加载数据,进行海量数据的存储,为全时间段、全维度分析提供基础,实现海量数据融合查询与统一管理;模型预计算技术,分析击中预计算不重复计算,不断复用预计算结果,提升查询的速度和性能,同时,查询的性能随业务的增长也不会受到影响。
- 利用 Bitmap 计算 提供了高基数维度的精确去重计算,满足真实场景中的用户行为分析需求。
- 提供了高性能的查询保障和交互式的分析需求;拖拽式开发报表,解耦 IT 人员的依赖,赋能更多业务人员,充分发挥业务人员的聪明才智,大幅度的缩短业务策略的落地实施周期。
- 通过 Kyligence 将用户行为数据、用户标签数据打通,业务人员基于统一的业务数据集进行自助式分析。将精确用户 ID 数据导出到其他系统,支持后续营销活动。
2)典型分析场景应用
> 事件分析
对行为事件进行分析,主要应用于统计和追踪用户行为或业务过程。拿理财 APP 为例,用户先浏览详情页再加入购物车,提交订单,最后点击成功支付。在这个过程中,对应了 APP 中的按钮点击事件、曝光事件、加载事件,可以对这些事件进行统计、分组,或是筛选,可以回答以下问题:
- 每天成功购买的用户数是多少?
- 每天各个时段浏览量、浏览用户数的变化?
- PV、UV数的变化趋势是什么?
还可以根据设备、APP 版本等维度进行对比统计分析,回答关于变化趋势、维度对比的各种细分问题。
在用户统计中,UV 的计算并不是简单粗暴的统计相加,而是需要依据用户唯一的识别符,例如用户ID,或者 IOS 广告标识符 IDFA,或是 IMEI 等,根据这些标识符来做去重计算。而对于多维度下的 UV 查询,则需要根据分析人员的查询条件来实时地做去重计算。
相对于传统技术中大量依赖人力的去重分析,使用 Kyligence 产品提供的精确去重技术就可以实现超高基数的 UV 分析。> 全路径转化效果分析
全路径分析提供了流量的全局分析视角,在图表可以看到不同节点之间的流量走向。由此可以判断各个页面之间的流量配比是否满足预期,并查看整体路径/节点的转化率是否正常。
通过用户全路径分析,还能找出用户实际访问的关键路径,例如可以得到转化率较高的路径中用户是否成功注册,以及产生购买行为;或者转化率较低的路径中用户是否实际到达登录步骤等。
> 漏斗分析
漏斗分析是对产品中、营销活动一系列关键节点的转化分析和流失分析。利用漏斗分析,可以轻松看出各个步骤之间转化情况和流失情况的比较。业务人员通过拆解业务流程,并在 Kyligence 中按照关键流程节点来自定义漏斗分析步骤,就可以很快发现重要的路径上是否有转化异常的情况。
通过增加或者调整步骤的顺序,可以进行更细粒度的转化率分析。使用更改筛选条件,还可以直接比较不同人群的转化效果。> 用户标签分析与漏斗分析联动
用户标签分析,通过标签筛选,帮助业务人员通过页面点选标签的方式,圈选出目标群体用户,进而实现精准营销。
标签可以按照用户的基本属性来分析:例如有年龄分段、性别、地理等信息,来反映用户群体的大致形象;或者根据 CRM 系统中同步的信息:对客户等级信息,保险、贷款等客户标签进行展现;再抽取业务相关的属性,例如对于理财产品:有历史累计交易金额、历史购买过理财产品、当前持有资产等标签。
通过这些标签,再联动漏斗分析,就可以精准定位关键步骤中的流失人群,并了解价值分布,为产品设计、精准营销提供依据,进行客户挽回。案例解读
1)物流运输平台
背景介绍:每天产生近 10 亿的流量数据,需要响应业务方的多维查询、自定义漏斗分析、留存分析、用户画像等流量分析需求。
作为全国最大的车货匹配信息平台,这个平台上连接着上千万的司机和货主用户,这些用户每天都会访问平台各种各样的产品来进行发货、找货,或使用一些加油、ETC充值、借贷的服务。平台每天会产生近十亿的流量数据,近半年的数据累计甚至达到了千亿级。
这些流量数据记录着非常丰富的用户行为。所以无论哪条业务线,无论是管理者、数据分析师、产品经理,还是运营人员,都非常希望深入分析流量数据,以此来洞察用户,为各项业务的展开提供决策支持。
在接入 Kylin 的技术以前,他们的业务人员以人工提数的方式处理流量分析需求。业务人员每周会把需求提交给数据分析师,数据分析师进行排期、写 SQL 提数,最后把数据反馈给需求方。这种方式非常的原始低效,一方面,业务人员要等较长的时间才能拿到结果;另一方面,人工处理需求的成本非常高,需要数据分析师全力投入来支持。因此,他们希望做到快速地响应业务方的多维查询、漏斗分析等流量分析需求。
在使用 Kylin 技术后,IT 人员只需要对数据进行简单的处理和转化,配置模型,然后构建数据。业务人员在前端展现平台进行查询,平台根据查询条件生成相应 SQL 语句下发到查询引擎,就可以得到结果。
整体实现了以下多个分析场景:- 多维查询:系统有十多个维度可以相互交叉分析,并且和任意日期关联。
- 虚拟埋点分析:虚拟埋点就是由几个埋点组合成的埋点。在很多场景下,只查询单个埋点的行为数据是不够的。而虚拟埋点的转化分析涉及到多个埋点先做并集,再做交集的 UV 聚合去重。对于这种复杂分析需求,业务用户只需要把这个虚拟埋点具体包含哪些埋点告诉系统,系统会自动地生成 SQL 去查询。
- 自定义漏斗:在这个方案中,利用 Kylin 提供的交集函数,可以在前端自定义漏斗配置后即刻返回数据的效果。
从时间成本上来看,新的方案实现了 T+0 的流量数据查询,端到端的延迟大概是 15 分钟左右。显然,新的实现方式能够更近一步支持精细化的流量分析,提供丰富的维度、T+0 的数据、即时灵活的自定义数据,让系统的功能得到了非常强大扩展。
2)房地产开发商
背景介绍:后台数据每天按日更新,并且日均数据量都会在百 G 以上,需要对业主特征,房产特征,活动营销进行快速分析响应。
第二个案例是国内知名的房地产开发商,通过一整套垂直行业的用户画像系统,持续给他们的客户营造高品质的房产品和生活服务。这个系统利用了 Kylin 技术加速主要数据服务,有效提升了互联网广告推广、营销服务的效率。
系统中融合各业务系统数据,包括线下房产、4S、商业园区、线上 APP 的服务数据,完成客户全生活链用户画像的建设。线下交易数据,联动线上的埋点行为数据,为数字化营销建立更为准确优化的策略,从而真正做到“数据驱动营销”。
后续,这套系统会融入知识图谱,建立业主与业主、业主与房子之间的连接,从而形成一套更加全面、可视化的用户行为画像系统。
如果你想亲自体验使用 Kyligence 助力企业用户行为分析,欢迎免费试用,全程免费的测试场景,等你来体验!Q&A
Q:请问用户路径分析中步骤需要提前预设值吗?其中的 Null 是指?
A:路径分析图中的步骤都是根据数据自动生成的。例如数据中存在步骤 A -> 步骤 B有 800 人,则路径分析图中就会展示步骤 A -> 步骤 B 中的流量为800,无需手动设定步骤。当数据中存在 Null 时,会把 Null 也认为是一个步骤。
Q:请问分析的结果是否可以推送或者分享到其他的平台(比如报表平台)?A:分析的结果可以通过 csv、xlsx 的方式下载下来,也可以直接将报表链接分享。
Q:如果用户行为类型有多种,这个在数据模型建设的时候是先将这些数据整合在一起,然后加载至 Kylin,接下来再针对不同的分析主题建设不同的 Cube 嘛?A:数据建多少个模型和 Cube 取决于数据采集、数据处理的方式。可以将不同类型的数据创建为不同模型,基于不同模型来创建后面的图表;也可以整合到一个模型当中支撑分析。当然根据具体情况的不同,解决方案也不同。如果需要具体讨论,您可以在 Kyligence 微信后台详细描述您的场景以及遇到的问题,期待和您进一步交流。
Q:这里演示的功能是基于行为明细和画像标签实时聚合计算的吗?和开源 Kylin 预计算的技术架构是不是不太一样?A:在 Demo 演示中,展示了漏斗分析图和用户画像相关的图表之间的联动。图表的查询击中了行为数据的预计算模型和标签数据的预计算模型。这与开源 Kylin 预计算的技术是一样的。
-
日期格式化为yyyymmdd_小白篇(二十):通过Java生成日期维度表
2021-01-12 23:11:43简短介绍大家好,一年一度的双十一又到了。准备好剁手了吗?反正我是看透了套路,什么时候买都差不多(好吧,其实咱穷^_^,求个心理安慰)。今天给大家分享个日期维度表的工具类。01—为什么要日期维度表日期维度在数仓...简短介绍
大家好,一年一度的双十一又到了。准备好剁手了吗?反正我是看透了套路,什么时候买都差不多(好吧,其实咱穷^_^,求个心理安慰)。今天给大家分享个日期维度表的工具类。01
—
为什么要日期维度表
日期维度在数仓中有着很重要的作用。举个栗子:我们展示全年每天商品交易量。如果某天某个商品没有交易量,但是这个日期又得显示出来。那我们要怎么处理呢?此时日期维度表就起到作用了,我们只要用日期维度表做查询主表,就可以很方便的展示每天是否有交易量的数据了。02
—
创建日期维度表
-- dim_dateCREATE TABLE dim_date( id string COMMENT '自增主键id', day_code string COMMENT '日代码', day_long_desc string COMMENT '日完整名称', day_medium_desc string COMMENT '日中等长度名', day_short_desc string COMMENT '日短名', week_code string COMMENT '周代码', week_long_desc string COMMENT '周完整名称', week_medium_desc string COMMENT '周中等长度名', week_short_desc string COMMENT '周短名', week_name string COMMENT '周名称', ten_day_code string COMMENT '旬代码', ten_day_long_desc string COMMENT '旬完整名称', ten_day_medium_desc string COMMENT '旬中等长度名', ten_day_short_desc string COMMENT '旬短名', month_code string COMMENT '月代码', month_long_desc string COMMENT '月完整名称', month_medium_desc string COMMENT '月中等长度名', month_short_desc string COMMENT '月短名', quarter_code string COMMENT '季代码', quarter_long_desc string COMMENT '季完整名称', quarter_medium_desc string COMMENT '季中等长度名', quarter_short_desc string COMMENT '季短名', half_year_code string COMMENT '半年代码', half_long_desc string COMMENT '半年完整名称', half_medium_desc string COMMENT '半年中等长度名', half_short_desc string COMMENT '半年短名', year_code string COMMENT '年代码', year_long_desc string COMMENT '年完整名称', year_medium_desc string COMMENT '年中等长度名', year_short_desc string COMMENT '年短名', all_time_code string COMMENT '全部时间代码', all_time_desc string COMMENT '全部时间名称', day_timespan string COMMENT '日时间跨天', day_end_date string COMMENT '结束日期', week_timespan string COMMENT '周跨天数', week_end_date string COMMENT '周结束日期', ten_day_timespan string COMMENT '旬跨天数', ten_day_end_date string COMMENT '旬结束日期', month_timespan string COMMENT '月跨天数', month_end_date string COMMENT '月结束日期', quarter_timespan string COMMENT '季跨天数', quarter_end_date string COMMENT '季结束日期', half_year_timespan string COMMENT '半年跨天数', half_year_end_date string COMMENT '半年结束日期', year_timespan string COMMENT '年跨天数', year_end_date string COMMENT '年结束日期', week_start_date string COMMENT '周开始日期', month_start_date string COMMENT '月开始时间', quarter_start_date string COMMENT '季度开始时间', workday_flag string COMMENT '是否工作日:1.是 0.否', weekend_flag string COMMENT '是否周末:1.是 0.否', holiday_flag string COMMENT '是否为节假日 1:是,0:否', holiday_name string COMMENT '节假日名称', is_workday string COMMENT '是否上班 1:是,0:否', last_week_day string COMMENT '周的最后一天', last_month_day string COMMENT '月的最后一天', load_time string COMMENT '加载时间')COMMENT '日期维度表'ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t' STORED AS TEXTFILE;
03
—
使用Java生成日期维度数据
import java.io.File;import java.io.FileWriter;import java.io.IOException;import java.io.PrintWriter;import java.text.ParseException;import java.text.SimpleDateFormat;import java.util.Calendar;import java.util.Date;public class DateDimUtil { /** * 当前日期 + 1天 * 返回:yyyymmdd */ public static String getNowDate(String specifiedDay) { Calendar c = Calendar.getInstance(); Date date = null; try { date = new SimpleDateFormat("yyyyMMdd").parse(specifiedDay); } catch (ParseException e) { e.printStackTrace(); } c.setTime(date); int day = c.get(Calendar.DATE); c.set(Calendar.DATE, day + 1); return new SimpleDateFormat("yyyyMMdd").format(c.getTime()); } /** * 当前日期,是星期几 */ public static int getWeekDay(String specifiedDay) { Date date = null; try { date = new SimpleDateFormat("yyyyMMdd").parse(specifiedDay); } catch (ParseException e) { e.printStackTrace(); } Calendar c = Calendar.getInstance(); c.setTime(date); int week_of_year = c.get(Calendar.DAY_OF_WEEK); week_of_year = week_of_year - 1; if (week_of_year == 0) { week_of_year = 7; } return week_of_year; } /** * 当前日期,属于年的第几周 */ public static int getWeekofYear(String specifiedDay) { Calendar c = Calendar.getInstance(); Date date = null; try { date = new SimpleDateFormat("yyyyMMdd").parse(specifiedDay); } catch (ParseException e) { e.printStackTrace(); } c.setTime(date); c.setFirstDayOfWeek(Calendar.MONDAY); int week = c.get(Calendar.WEEK_OF_YEAR); return week; } /** * 当前日期,格式化转换 */ public static String yyyymmdd(String specifiedDay,String patten) throws ParseException{ Date date = new SimpleDateFormat("yyyyMMdd").parse(specifiedDay); return new SimpleDateFormat(patten).format(date); } /** * 当前日期,所属月多少天 */ public static int getMDaycnt(String specifiedDay) { Date date = null; try { date = new SimpleDateFormat("yyyyMMdd").parse(specifiedDay); } catch (ParseException e) { e.printStackTrace(); } Calendar c = Calendar.getInstance(); c.setTime(date); int i = c.get(Calendar.DAY_OF_MONTH); return i; } /** * 当前日期,所属月旬数 * 三旬: 上旬1-10日 中旬11-20日 下旬21-31日 * 返回: 1\2\3 */ public static int getTenDay(String specifiedDay) { Date date = null; try { date = new SimpleDateFormat("yyyyMMdd").parse(specifiedDay); } catch (ParseException e) { e.printStackTrace(); } Calendar c = Calendar.getInstance(); c.setTime(date); int i = c.get(Calendar.DAY_OF_MONTH); if (i < 11) return 1; else if (i < 21) return 2; else return 3; } /** * 当前日期,所属月旬数 * 三旬: 上旬1-10日 中旬11-20日 下旬21-31日 * 返回: 1\2\3 */ public static String getTenDays(String specifiedDay) { Date date = null; try { date = new SimpleDateFormat("yyyyMMdd").parse(specifiedDay); } catch (ParseException e) { e.printStackTrace(); } Calendar c = Calendar.getInstance(); c.setTime(date); int i = c.get(Calendar.DAY_OF_MONTH); if (i < 11) return "上旬"; else if (i < 21) return "中旬"; else return "下旬"; } /** * 当前日期,所属月,三旬: 每旬多少天 */ public static int getTenDayscnt(String specifiedDay) { Date date = null; try { date = new SimpleDateFormat("yyyyMMdd").parse(specifiedDay); } catch (ParseException e) { e.printStackTrace(); } Calendar c = Calendar.getInstance(); c.setTime(date); int i = c.get(Calendar.DAY_OF_MONTH); if (i < 11){ return 10; } else if (i < 21) { return 10; }else{ return Integer.parseInt(getMonthEndTime(specifiedDay).substring(6,8)) - 20; } } /** * 当前日期,所属季度 */ public static int getQuarter(String specifiedDay) { Date date = null; try { date = new SimpleDateFormat("yyyyMMdd").parse(specifiedDay); } catch (ParseException e) { e.printStackTrace(); } Calendar c = Calendar.getInstance(); c.setTime(date); int currentMonth = c.get(Calendar.MONTH) + 1; int dt = 0; try { if (currentMonth <= 3) dt = 1; else if (currentMonth <= 6) dt = 2; else if (currentMonth <= 9) dt = 3; else if (currentMonth <= 12) dt = 4; } catch (Exception e) { e.printStackTrace(); } return dt; } /** * 当前日期,所属季度天数 */ public static int getQuarterCntday(String specifiedDay) { int cnt_d = 0; int q = getQuarter(specifiedDay); if (q == 1) { specifiedDay = specifiedDay.substring(0,4); specifiedDay = getMonthEndTime(specifiedDay + "0201"); cnt_d = getMDaycnt(specifiedDay); cnt_d = 31 + cnt_d + 31; }else if (q == 2) { cnt_d = 30 + 31 + 30; }else if (q == 3) { cnt_d = 31 + 31 + 30; }else if (q == 4) { cnt_d = 31 + 30 + 31; } return cnt_d; } /** * 当前日期,所属年多少天 */ public static int getYearCntday(String specifiedDay) { int cnt_d; specifiedDay = specifiedDay.substring(0,4); specifiedDay = getMonthEndTime(specifiedDay + "0201"); cnt_d = getMDaycnt(specifiedDay); cnt_d = 31 + cnt_d + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31; return cnt_d; } /** * 当前日期,所属前半年 或 后半年 天数据 */ public static int getHyearCntday(String specifiedDay) { int cnt_d = 0; int q = getHalfYear(specifiedDay); if (q == 1) { specifiedDay = specifiedDay.substring(0,4); specifiedDay = getMonthEndTime(specifiedDay + "0201"); cnt_d = getMDaycnt(specifiedDay); cnt_d = 31 + cnt_d + 31 + 30 + 31 + 30; }else if (q == 2) { cnt_d = 31 + 31 + 30 + 31 + 30 + 31; } return cnt_d; } /** * 当前日期,所属前半年 或 后半年 * 返回:1\2 */ public static int getHalfYear(String specifiedDay) { int dt = getQuarter(specifiedDay); if (dt <= 2) { dt = 1; }else { dt = 2; } return dt; } /** * 当前日期,所属前半年 或 后半年 * 返回:上半年\下半年 */ public static String getHalfYears(String specifiedDay) { int dt = getQuarter(specifiedDay); if (dt<=2) { return "上半年"; } return "下半年"; } /** * 当前日期,所属月的开始时间 */ public static String getMonthStartTime(String specifiedDay) { Date date = null; try { date = new SimpleDateFormat("yyyyMMdd").parse(specifiedDay); } catch (ParseException e) { e.printStackTrace(); } Calendar c = Calendar.getInstance(); c.setTime(date); String dt = ""; try { c.set(Calendar.DATE, 1); dt = new SimpleDateFormat("yyyyMMdd").format(c.getTime()); } catch (Exception e) { e.printStackTrace(); } return dt; } /** * 当前日期,所属月的结束时间 */ public static String getMonthEndTime(String specifiedDay) { Date date = null; try { date = new SimpleDateFormat("yyyyMMdd").parse(specifiedDay); } catch (ParseException e) { e.printStackTrace(); } Calendar c = Calendar.getInstance(); c.setTime(date); String dt = ""; try { c.set(Calendar.DATE, 1); c.add(Calendar.MONTH, 1); c.add(Calendar.DATE, -1); dt = new SimpleDateFormat("yyyyMMdd").format(c.getTime()); } catch (Exception e) { e.printStackTrace(); } return dt; } /** * 当前日期,所属周的第一天(周一),的日期 */ public static String getWeekStartTime(String specifiedDay,String pattern) { Date date = null; try { date = new SimpleDateFormat("yyyyMMdd").parse(specifiedDay); } catch (ParseException e) { e.printStackTrace(); } Calendar c = Calendar.getInstance(); c.setTime(date); try { SimpleDateFormat shortSdf = new SimpleDateFormat("yyyy-MM-dd"); SimpleDateFormat longSdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); int weekday = c.get(Calendar.DAY_OF_WEEK) - 2; c.add(Calendar.DATE, -weekday); c.setTime(longSdf.parse(shortSdf.format(c.getTime()) + " 00:00:00.000")); } catch (Exception e) { e.printStackTrace(); } return new SimpleDateFormat(pattern).format(c.getTime()); } /** * 当前日期,所属周的最后一天(周日),的日期 */ public static String getWeekEndTime(String specifiedDay,String pattern) { Date date = null; try { date = new SimpleDateFormat("yyyyMMdd").parse(specifiedDay); } catch (ParseException e) { e.printStackTrace(); } Calendar c = Calendar.getInstance(); c.setTime(date); try { SimpleDateFormat shortSdf = new SimpleDateFormat("yyyy-MM-dd"); SimpleDateFormat longSdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); int weekday = c.get(Calendar.DAY_OF_WEEK); c.add(Calendar.DATE, 8 - weekday); c.setTime(longSdf.parse(shortSdf.format(c.getTime()) + " 23:59:59.999")); } catch (Exception e) { e.printStackTrace(); } return new SimpleDateFormat(pattern).format(c.getTime()); } /** * 当前日期,所属旬结束时间 */ public static String getTenDayEndTime(String specifiedDay) { Date date = null; try { date = new SimpleDateFormat("yyyyMMdd").parse(specifiedDay); } catch (ParseException e) { e.printStackTrace(); } int ten = getTenDay(specifiedDay); if (ten == 1) { SimpleDateFormat df = new SimpleDateFormat("yyyyMM10"); return df.format(date); } else if (ten == 2) { SimpleDateFormat df = new SimpleDateFormat("yyyyMM20"); return df.format(date); } else { return getMonthEndTime(specifiedDay); } } /** * 当前日期,所属季度的开始时间 */ public static String getQuarterStartTime(String specifiedDay) { Date date = null; try { date = new SimpleDateFormat("yyyyMMdd").parse(specifiedDay); } catch (ParseException e) { e.printStackTrace(); } Calendar c = Calendar.getInstance(); c.setTime(date); int currentMonth = c.get(Calendar.MONTH) + 1; String dt = ""; try { if (currentMonth <= 3) c.set(Calendar.MONTH, 0); else if (currentMonth <= 6) c.set(Calendar.MONTH, 3); else if (currentMonth <= 9) c.set(Calendar.MONTH, 6); else if (currentMonth <= 12) c.set(Calendar.MONTH, 9); c.set(Calendar.DATE, 1); dt = new SimpleDateFormat("yyyyMMdd").format(c.getTime()); } catch (Exception e) { e.printStackTrace(); } return dt; } /** * 当前日期,所属季度的结束时间 */ public static String getQuarterEndTime(String specifiedDay) { Date date = null; try { date = new SimpleDateFormat("yyyyMMdd").parse(specifiedDay); } catch (ParseException e) { e.printStackTrace(); } Calendar c = Calendar.getInstance(); c.setTime(date); int currentMonth = c.get(Calendar.MONTH) + 1; String dt = ""; try { if (currentMonth <= 3) { c.set(Calendar.MONTH, 2); c.set(Calendar.DATE, 31); } else if (currentMonth <= 6) { c.set(Calendar.MONTH, 5); c.set(Calendar.DATE, 30); } else if (currentMonth <= 9) { c.set(Calendar.MONTH, 8); c.set(Calendar.DATE, 30); } else if (currentMonth <= 12) { c.set(Calendar.MONTH, 11); c.set(Calendar.DATE, 31); } dt = new SimpleDateFormat("yyyyMMdd").format(c.getTime()); } catch (Exception e) { e.printStackTrace(); } return dt; } /** * 当前日期,是否节假日 * */ public static int getJjr(String specifiedDay,String j) { String[] f = { "0101" , "0405" , "0501" , "1001" }; String sub = specifiedDay.substring(4,8); if (!"2".equals(j)) {//0工作日、1周末、2节日、3调休 for (String s : f) { if (s.equals(sub)) { return 1; } } return 0; }else{ return 1; } } /** * 当前日期,节假日名称 * http://timor.tech/api/holiday?date=20190505 */ public static String getJjrname(String specifiedDay) { String[] f = { "0101" , "0405" , "0501" , "1001" }; String[] f1 = { "元旦节" , "清明节" , "劳动节" , "国庆节" }; String sub = specifiedDay.substring(4,8); for (int k = 0 ; k < f.length ; k++ ) { if(f[k].equals(sub)){ return f1[k]; } } return "-"; } /** * 当前日期,是否上班 */ public static int iswork(String specifiedDay,String j) { String[] f = { "0101" , "0405" , "0501" , "1001" }; String sub = specifiedDay.substring(4,8); //0工作日、1周末、2节日、3调休 if ("0".equals(j) || "3".equals(j)) { for (String s : f) { if (s.equals(sub)) { return 0; } } return 1; } else { return 0; } } /** * 循环计算 */ public static void anyDate(String start_day, String end_day, int i) throws Exception { while (true) { start_day = getNowDate(start_day); if (start_day.equals(end_day)) { break; } else { System.out.println(start_day); StringBuffer rel = new StringBuffer(); String year_s = start_day.substring(0, 4); String month_s = start_day.substring(4, 6); String day_long_desc = yyyymmdd(start_day,"yyyy年MM月dd日");// 日完整名称 yyyy年MM月dd日 String day_medium_desc = yyyymmdd(start_day,"dd日");// 日中等长度名 dd日 String day_short_desc = yyyymmdd(start_day,"yyyy-MM-dd");// 日短名 yyyy-MM-dd int ws = getWeekofYear(start_day); String n_year = year_s; if (ws == 1 && "12".equals(month_s)){ n_year = (Integer.parseInt(year_s) + 1) + ""; } String week_code = n_year + "W" + ws;// 周代码 2019W02 String week_long_desc = n_year + "年第" + ws + "周"; //周完整名称String 2019年第02周 String week_medium_desc = "第" + ws + "周"; //周中等长度名String 第02周 String week_short_desc = n_year + "-W" + ws ; //周短名String String week_name = yyyymmdd(start_day,"EEEE"); //旬代码String String ten_day_code =year_s + month_s + "X" + getTenDay(start_day); //旬完整名称String String ten_day_long_desc = year_s +"年"+ month_s + "月" + getTenDays(start_day); //旬中等长度名String String ten_day_medium_desc = getTenDays(start_day); //旬短名String String ten_day_short_desc = year_s +"-"+ month_s + "-X" + getTenDay(start_day); //月代码String String month_code = year_s + month_s; //月完整名称String String month_long_desc = year_s + "年" + month_s + "月"; //月中等长度名String String month_medium_desc = month_s + "月"; //月短名String String month_short_desc = year_s + "-" + month_s; //季代码String String qu=getQuarter(start_day)+ ""; String quarter_code = year_s + "Q"+ qu; //季完整名称String String quarter_long_desc = year_s + "年第" + qu + "季度"; //季中等长度名String String quarter_medium_desc = "第" + qu + "季度"; //季短名String String quarter_short_desc = year_s + "-Q" + qu; //半年代码String String half_year_code =year_s + "H" + getHalfYear(start_day); //半年完整名称String String half_long_desc = year_s + "年" +getHalfYears(start_day); //半年中等长度名String String half_medium_desc = getHalfYears(start_day); //半年短名String String half_short_desc = year_s + "-H" + getHalfYear(start_day); //年完整名称String String year_long_desc = year_s + "年"; //年中等长度名String String year_medium_desc = year_s + "年"; //年短名String //全部时间代码String String all_time_code = "ALL"; //全部时间名称String String all_time_desc = "ALL_TIME"; //日时间跨天String String day_timespan = "1"; //周跨天数String String week_timespan = "7"; //周结束日期String String week_end_date = getWeekEndTime(start_day,"yyyy-MM-dd");; //旬跨天数String String ten_day_timespan = getTenDayscnt(start_day)+""; //旬结束日期String String ten_day_end_date = getTenDayEndTime(start_day); //月跨天数String String month_timespan = getMonthEndTime(start_day).substring(6,8)+""; //月结束日期String String month_end_date = getMonthEndTime(start_day); //季跨天数String String quarter_timespan = getQuarterCntday(start_day)+""; //季结束日期String String quarter_end_date = getQuarterEndTime(start_day); //半年跨天数String String half_year_timespan = getHyearCntday(start_day)+""; //半年结束日期String String half_year_end_date = year_s + "0630"; //年跨天数String String year_timespan = getYearCntday(start_day)+""; //年结束日期String String year_end_date = year_s + "1231"; //周开始日期String String week_start_date = getWeekStartTime(start_day,"yyyyMMdd"); //月开始时间String String month_start_date = getMonthStartTime(start_day); //季度开始时间String String quarter_start_date = getQuarterStartTime(start_day); //是否工作日:1.是 0.否 String workday_flag = getWeekDay(start_day) <= 5 ? "1" : "0" ; //是否周末:1.是 0.否 String weekend_flag = getWeekDay(start_day) > 5 ? "1" : "0"; //是否为节假日 1:是,0:否 -: 未知 String holiday_flag = "-";//暂时默认未知,或者调用接口处理 //节假日名称String String holiday_name = getJjrname(start_day); //是否上班 1:是,0:否 -: 未知 String is_workday = "-";//暂时默认未知,或者调用接口处理 String last_week_day = getWeekEndTime(start_day,"yyyy-MM-dd"); //周的最后一天String String last_month_day = yyyymmdd(getMonthEndTime(start_day),"yyyy-MM-dd"); //月的最后一天String Date d = new Date(); String load_time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(d);//加载时间 rel.append(i).append("\t"); rel.append(start_day).append("\t"); rel.append(day_long_desc).append("\t"); rel.append(day_medium_desc).append("\t"); rel.append(day_short_desc).append("\t"); rel.append(week_code).append("\t"); rel.append(week_long_desc).append("\t"); rel.append(week_medium_desc).append("\t"); rel.append(week_short_desc).append("\t"); rel.append(week_name).append("\t"); rel.append(ten_day_code).append("\t"); rel.append(ten_day_long_desc).append("\t"); rel.append(ten_day_medium_desc).append("\t"); rel.append(ten_day_short_desc).append("\t"); rel.append(month_code).append("\t"); rel.append(month_long_desc).append("\t"); rel.append(month_medium_desc).append("\t"); rel.append(month_short_desc).append("\t"); rel.append(quarter_code).append("\t"); rel.append(quarter_long_desc).append("\t"); rel.append(quarter_medium_desc).append("\t"); rel.append(quarter_short_desc).append("\t"); rel.append(half_year_code).append("\t"); rel.append(half_long_desc).append("\t"); rel.append(half_medium_desc).append("\t"); rel.append(half_short_desc).append("\t"); rel.append(year_s).append("\t"); rel.append(year_long_desc).append("\t"); rel.append(year_medium_desc).append("\t"); rel.append(year_s).append("\t"); rel.append(all_time_code).append("\t"); rel.append(all_time_desc).append("\t"); rel.append(day_timespan).append("\t"); rel.append(start_day).append("\t"); rel.append(week_timespan).append("\t"); rel.append(week_end_date).append("\t"); rel.append(ten_day_timespan).append("\t"); rel.append(ten_day_end_date).append("\t"); rel.append(month_timespan).append("\t"); rel.append(month_end_date).append("\t"); rel.append(quarter_timespan).append("\t"); rel.append(quarter_end_date).append("\t"); rel.append(half_year_timespan).append("\t"); rel.append(half_year_end_date).append("\t"); rel.append(year_timespan).append("\t"); rel.append(year_end_date).append("\t"); rel.append(week_start_date).append("\t"); rel.append(month_start_date).append("\t"); rel.append(quarter_start_date).append("\t"); rel.append(workday_flag).append("\t"); rel.append(weekend_flag).append("\t"); rel.append(holiday_flag).append("\t"); rel.append(holiday_name).append("\t"); rel.append(is_workday).append("\t"); rel.append(last_week_day).append("\t"); rel.append(last_month_day).append("\t"); rel.append(load_time); writeFile(rel); } i++ ; } } // 写入文件(增量写入,不会覆盖原有内容) public static void writeFile(StringBuffer rel) { // 本地存放路径 String file_path = "d:/date_dim.txt" ; FileWriter fw_s = null; PrintWriter pw_s = null; try { File f_hive = new File(file_path);/* 生成路径 */ fw_s = new FileWriter(f_hive, true); pw_s = new PrintWriter(fw_s); pw_s.println(rel); pw_s.flush(); fw_s.flush(); } catch (IOException e) { e.printStackTrace(); } finally { if (pw_s != null) pw_s.close(); if (fw_s != null) { try { fw_s.close(); } catch (IOException e) { e.printStackTrace(); } } } } // 测试 public static void main(String[] args) throws Exception { String start_day = "20191031";/*开始日期*/ String end_day = "20201231";/*结束日期*/ anyDate(start_day,end_day,1);//开始时间-结束时间-续跑ID(便于后续增量生成) System.out.println("success !"); }}
说明:最后将生成的数据文件导入至创建的hive日期维度表中即可。记得验证下数据哦^_^
04
—
小结
其实生成日期维度表是很简单的。可以通过很多编程语言来实现,sql\python\java...等等都可以。大家可以根据各自的习惯来处理。有好的建议,可以留言告知下哦,相互学习嘛。如果大家喜欢可关注公众号,感谢!
-
阿里P8架构师从应用、运维及与K8S和微服务3个维度
2020-12-11 11:11:58今天小编给大家分享一份由阿里从业十余年的架构师编写的《Nginx应用与运维实战》,本书基于新版Nginx,从运维与开发工作的实际需要出发,首先介绍Nginx源码架构,编译及部署,核心配置指令、HTTP功能模块等基动知识;...Nginx作为一款优秀的开源Web服务器软件,具有性能稳定、高并发能力 、资源耗用低及高性能的负载均衡等特点,被众多互联网公司广泛应用于实际生产项目中。因此,它也成为每个互联网技术人员的必备技术。
今天小编给大家分享一份由阿里从业十余年的架构师编写的《Nginx应用与运维实战》,本书基于新版Nginx,从运维与开发工作的实际需要出发,首先介绍Nginx源码架构,编译及部署,核心配置指令、HTTP功能模块等基动知识;接着,重点讲解Nginx在Web服务、代理服务、缓存服务、负载均衡等方面的应用实战;然后,深入讲解Nginx日志管旺,监控配置及管旺,集辟负薮与配蓝管理等运维管理方法:最后,介绍Nginx在Kubarnetas、微服务架构中的应用。书中详细解析了所涉及的专业术语和技术要点,并通过大量配置样例进行演示。力求让读者真正理解Nginx,用好Nginx。
100%免费领取手册的方式:转发这篇文章+关注,扫描下方二维码
全书学习路线
第一部分 Nginx介绍(第1~4章)
第1章 Nginx概述
第2章 Nginx编译及部署
第3章 Nginx核心配置指令
第4章 Nginx HTTP模块详解
第二部分 应用实战(第5~8章)
第5章 Nginx Web服务应用实战
第6章 Nginx代理服务应用实战
第7章 Nginx缓存服务应用实战
第8章 Nginx负载均衡应用实战
第三部分 运维管理(第9~11章)
第9章 Nginx日志管理
第10章 Nginx监控配置及管理
第11章 Nginx集群负载与配置管理
第四部分 Nginx与Kubernetes、微服务的应用集成(第12~13章)
第12章 Nginx在Kubernetes中的应用
第13章 Nginx在微服务架构中的应用
100%免费领取手册的方式:转发这篇文章+关注,扫描下方二维码
本书特色
-
二进制数组操作的数组维度必须匹配_二进制位运算实战(1)-开发一个进制转换工具...
2020-12-09 13:58:14ArrayBuffer的作用 左位移和右位移运算的使用 按位与运算的使用之前介绍了二进制相关的知识 二进制转十进制心算大法, 本篇将使用JavaScript开发一个相关的可视化工具,实现十进制和二进制之间的自动转换。...从这篇文章你将了解到什么?
ArrayBuffer的作用
左位移和右位移运算的使用
按位与运算的使用之前介绍了二进制相关的知识 二进制转十进制心算大法, 本篇将使用JavaScript开发一个相关的可视化工具,实现十进制和二进制之间的自动转换。
当然,醉翁之意不在酒。在开发的过程中熟悉二进制的位运算才是本篇的关注点。
转换工具介绍下面来看看这个可视化工具。
输入一个十进制的正整数(32位无符号整数), 我们会将该数字的二进制展示到一个表格中。
表格由32个单元格组成, 因为1字节=8字位, 所以单元格按八个一组来划分。
比如, 输入一个数字7, 对应的二进制就是111,那么表格就应该是下面这样:
每个单元格上的二进制数字都可以在0和1之间切换, 对应的也会计算出这组二进制数代表的十进制数。
比如, 我们把下图选中的单元格从0切换为1,那么对应的十进制数也会跟着变为263:
ArrayBuffer介绍
下面我们用数字263作为例子,讲讲如何使用位运算操作字节流的方式实现代码。
首先,初始化的时候,我们会把263这个数字放入一个数组,然后把这个数组转为字节流存放到ArrayBuffer内存当中 。
如图,下方的矩形ArrayBuffer表示一段内存,但是我们不能直接操作它。
这时候我们就要用到JS里的TypedArray来访问这一段内存,MDN把TypedArray称为“Multiple views on the same data”。
我们可以使用Uint32Array,Uint8Array等等这些“View”来对ArrayBuffer内存进读写。
这样一来,我们的“十进制展示区” 和“二进制展示区”都可以从同一块内存中读取数据,不用浪费另外的数组空间去存放一大堆的0和1。
另外,在改变“二进制展示区”单元格数值时,我们可以直接对ArrayBuffer内存中的数据进行写操作,省去了很多麻烦。
下面请看代码,我们使用Uint32Array来表示“十进制展示区” 。let target = new Uint32Array([263])
将数组[263]转为字节流,再读取为一个由32位无符号字节组成的数组,于是变量target赋值的数组就是[263]。target[0]就是图中“十进制展示区”的263。
我们使用Uint8Array来表示“二进制展示区”。let bytes = new Uint8Array(target.buffer)
通过target.buffer可以读取到内存中存放的字节流,将其读取为一个由8位无符号字节组成的数组,得到的bytes数组就是[7,1,0,0], 对应的二进制数组就是[0000111,00000001, 00000000, 00000000]。
接下来我们要将bytes数组显示到“二进制展示区”中。
因为有32个单元格, 我们从第0格遍历到第31格, 每个单元格都是通过getBit方法从bytes数组中获取对应的二进制数值。function writeBits() { for (var i = 0; i < 32; i++) { 单元格[i].textContent = getBit(i); } }
下面是getBit的具体实现代码。function getBit(bit) { return bytes[bit >> 3] & (0x1 << (bit & 0x7)) ? 1 : 0; }
我们一段段来解释下。
“bit>>3”分组
“>>”是右位移运算符,如果n是整数,那么n>>3效果等同n除以8取除数,可以用于分组;
“bit&7”求余
如果n是整数,n&7效果等同n除以8取余数,可以用于确定n在所属分组中的位置;
“&”运算和“<<”运算
我们知道按位与运算的规则是下面这样:
1&1=1
0&1=0
1&0=0
0&0=0
也即是说, 如果我们想要知道二进制数字"0100 0n01"中的n是0还是1,可以这样:0x01000n01 & 0x00000100
如果结果等于0,那么n的值就是0;如果结果大于0,那么n的值就是1。
在按位与运算的规则下,0x00000100就是一个“取值器”。我们可以通过左位移运算符得到一个“取值器”。0x1 << n的位置
把0x0000 0001中的1移动到n的位置,也就是0x0000 0100。例子讲解
关键的位运算技巧都讲完之后,我们用一个例子来感受下。
比如我们要得到第2个单元格(从第0格算起)在bytes数组[0000111,00000001, 00000000, 00000000]中对应的数值,具体的过程就是这样:第一步,通过2>>3=0,可以计算出第2个单元格属于第0组,也就是bytes数组中下标为0的元素。第二步,通过2&7=0,可以计算出第2个单元格属于第一组第2个格(从第0格算起)。
第三步,制作“取值器”,0x1<<2, 得到00000100。最后,通过"bytes[0]&取值器"判断结果是大于0还是等于0, 就可以得到第2个单元格的值了。
let res = 0x00000111 & 0x00000100 ? 1 : 0
res的值为1, 也就是第2个单元格的值为1。是不是很好玩?
未完待续......往期回顾
二进制、八进制、十进制、十六进制数据转换
二进制转十进制心算大法
-
ReportStudio进阶教程(三十八) - descendants实例介绍
2014-12-19 14:46:18上一回,我们介绍了一个函数的使用: Cognos函数(二十四) - descendants 也简单介绍了一些简单的例子,我们这里实现一个简单的需求: 已产品维度为例子,用户可以选择产看某一指定的层级,并且可以产看该层级下的... -
LLVM每日谈之四十八 LLVM后端文档解析1
2019-05-19 12:14:44之前在LLVM每日谈之四十七 LLVM后端文档解析中,介绍了后端文档中提到关于后端的六大模块、七大环节和七个步骤。前文也提到过,它们是从不同的维度去解析LLVM的后端,不同维度之间是存在各种各样的交叉关系的。在... -
Java进阶专题(二十二) 从零开始搭建一个微服务架构系统 (上)
2021-02-01 17:27:031|1Spring Cloud 这就不用多说了,官网有详细的介绍...Sentinel:把流量作为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。 Nacos:一个更易于构建云原生应用的动态服务发现、配置管理和... -
十、快速入门线性代数的向量和矩阵篇
2021-01-29 16:00:04@Author:Runsen 在本节中,将介绍向量知识...向量的概念其实很简单,比如向量[1,2][1 ,2][1,2],就是一个维度是(1,2)(1,2)(1,2) 的二维的行向量,同样的道理向量 [12]\left[ \begin{array}{l}1\\2\end{array} \right] -
二十三、 桥接设计模式
2016-05-10 14:11:261. 桥接设计模式介绍在软件系统中,某些类型由于自身的逻辑,它具有两个或多个维度的变化,可以采用桥接模式来应对这种“多维度变化”。定义将抽象部分与实现部分分离,使它们可以独立地进行变化。2. 桥接设计模式... -
Cognos函数(十) - currentMember & prevMember & nextMember
2014-09-11 17:32:38我们继续介绍几个维度函数 currentMember & nextMember & pre -
SonarQube介绍及部署
2014-05-28 23:07:00SonarQube介绍及部署 ...用于管理源代码的质量,可以从七个维度检测代码质量,通过插件形式,可以支持包括Java,C#,C/C++,PHP,PL/SQL,Cobol,Web,XML,JavaScrip,Groovy等等二十几种编程语言... -
第十二章 桥接模式
2019-11-30 13:31:20快速导航 一、桥接模式介绍 二、代码演示 三、jdk中使用桥接模式的地方 ...一个类存在两个(或多个)独立变化的维度,且这两个(或多个)维度都需要独立进行扩展 不希望使用继承,或因为多层继承导致系统类的个数剧... -
经济学入门十人十书:大师级书单推荐
2018-05-03 14:36:00论坛君:经济学对于理解世界是一个不可或缺的观察维度。本文摘编自《凯恩斯的中国聚会》一书,作者徐瑾认为经济学应该作为一项普遍的常识加以推广,“经济学不仅属于经济学家,也应该属于所有人,尤其是普通民众。”... -
Shark源码分析(十):KNN算法
2017-01-26 11:53:01Shark源码分析(十):KNN算法关于这个算法,我之前已经有博客详细介绍过。虽然说这个算法看上去非常的简单,但是在搜索k个最近邻居数据点时,还是非常具有技巧性的。这里还是有必要再次强调一下。如果输入数据的... -
【阿里妈妈-adhoc之mdrill介绍】
2016-10-25 20:14:14旨在帮助用户在几秒到几十秒的时间内,分析百亿级别的任意维度组合的数据。 mdrill是一个分布式的在线分析查询系统,基于hadoop,lucene,solr,jstorm等开源系统作为实现,基于SQL的查询语法。 mdrill是一个能够对... -
一百六十一
2020-12-27 19:47:30博客中用的笔记软件——Typora(Markdown语法) 博客中用的图床——阿里云对象存储(Object Storage Service,简称OSS) ...网易云 NOS 对象存储从三个维度进行计量收费:存储容量、流量、接口调用次数。存储容量0- -
二百一十七
2021-01-08 08:16:54最近在做Python职位分析的项目,做这件事的背景是因为接触Python这么久,还没有对Python职位有一个全貌的了解。所以想通过本次分析了解Python相关的职位有哪些、在不同城市的需求量有何差异、薪资怎么样以及对工作... -
Sonar介绍(开源质量平台)
2015-06-10 18:10:13Sonar是一个用于代码质量管理的开源平台,用于管理源代码的质量,可以从七个维度检测代码质量 通过插件形式,可以支持包括java,C#,C/C++,PL/SQL,Cobol,JavaScrip,Groovy等等二十几种编程语言的代码质量管理与检测... -
DM 源码阅读系列文章(十)测试框架的实现
2019-07-24 14:02:12本文为 DM 源码阅读系列文章的第十篇,之前的文章已经详细介绍过 DM 数据同步各组件的实现原理和代码解析,相信大家对 DM 的实现细节已经有了深入的了解。本篇文章将从质量保证的角度来介绍 DM 测试框架的设计和实现... -
Hive零基础从入门到实战 进阶篇(十四) HiveQL:高级聚合函数 grouping sets、cube、rollup
2019-09-03 23:20:58目录 前言 1. 指定维度组合进行聚合 grouping sets 2. 所有维度组合进行聚合 cube 3. 最左侧的维度为主进行层级聚合 rollup ...本文介绍Hive中的三种高级聚合函数,分别是...grouping sets用于在一个 group ... -
论文解读 | 数十亿商品中,长尾和新品怎么找到新主人?
2019-02-20 16:25:54小叽导读:在推荐系统的发展历程中,面临两个核心问题:用户的长尾覆盖度以及新商品的冷启动,在这两个维度下的模型扩展能力的瓶颈一直以来对广大推荐算法工程师都是不小的挑战。本文基于Graph Embedding的理论知识... -
baidu进阶训练笔记十五20200802
2020-08-02 18:27:41文章目录百度Apollo感知介绍(一)感知概貌机器开车与人开车在感知上的一个区别多维度分析感知传感器和标定-1配置硬件传感器和标定-2标定的目的传感器标定算法基于标定间的多`Lidar-Camera`标定 百度Apollo感知介绍... -
mysql 数据表格切分_精:主流数据库中间件介绍和对比
2021-01-02 01:48:27目前的数据库中间件有很多,本节将介绍主流的中间件,并从各个维度将其与Mycat进行对比。Mango的中文名是“芒果”,它是一个轻量级的极速数据层访问框架,目前已有十多个大型线上项目在使用它。据称,某一支付系统... -
第一章 介绍
2009-11-15 20:42:00十几年以前,DirectX的诞生,使windows操作系统彻成为游戏的领地。它第一次出现在windows 95里面,从那开始就使...我们经历过2D加速器,那个时候芯片设计者还没有把第三个维度加入进来,到最后我们能够使图形硬件可编 -
Cognos函数(二十四) - descendants
2014-12-19 12:13:33这里,我们介绍下descendants 这个函数,有时候会用到的,按指定层级取数的时候,我们来学习下 1. 函数定义 descendants用来获得一个成员集,根据距离获得指定维度下的成员集 2. 实例 -
论文解读 | 数十亿商品中,长尾和新品怎么找到新主人? ...
2019-02-20 16:25:54小叽导读:在推荐系统的发展历程中,面临两个核心问题:用户的长尾覆盖度以及新商品的冷启动,在这两个维度下的模型扩展能力的瓶颈一直以来对广大推荐算法工程师都是不小的挑战。本文基于Graph Embedding的理论知识... -
Lucene 索引文件的生成(二十五)之kdd&kdi&kdm
2020-12-18 16:02:24在系列文章索引文件的生成(Lucene 7.5.0)中,我们介绍了存储维度(见文章Bkd-Tree)值大于等于2的数值类型对应的索引文件的生成过程。对于维度值等于1的情况,其生成过程有少许的不同。为了后续便于介绍该类型的... -
SpringCloud第十七篇:服务网关Zuul基于Apollo动态路由
2020-05-29 15:23:21Zuul作为一个老牌的开源服务网关组件,动态路由对它来讲是一个十分必要的功能,毕竟我们不能随便重启服务网关,服务网关是一个微服务系统的大门,...Apollo支持4个维度管理Key-Value格式的配置: application (应用) en -
pytorch学习笔记(十九):二维卷积层
2020-08-04 10:29:27它有高和宽两个空间维度,常用来处理图像数据。本节中,我们将介绍简单形式的二维卷积层的工作原理。 1. 二维互相关运算 虽然卷积层得名于卷积(convolution)运算,但我们通常在卷积层中使用更加直观的互相关... -
从头开始学Tableau-第十九章(石油产量分析)
2019-09-18 11:17:18本节要介绍一个油井产量与收入的数据分析案例,但是我们的重点是学习参数的使用。 油井 油井CO2排放量 我们使用的数据是“油井数据.xlsx”我们连接上数据看一下 大致上都是一些价格和收入的数据。 我们将‘油井...