大家好,欢迎来到IT知识分享网。
一 什么是数据仓库
1.1 数据仓库概念
数据仓库,英文名称为Data Warehouse,可简写为DW或DWH。数据仓库,是为企业所有级别的决策制定过程,提供所有类型数据支持的战略集合。它出于分析性报告和决策支持目的而创建。
1.2 数据仓库特点
1.2.1面向主题
普通的操作型数据库主要面向事务性处理,而数据仓库中的所有数据一般按照主题进行划分。主题是对业务数据的一种抽象,是从较高层次上对信息系统中的数据进行归纳和整理。
面向主题的数据可以划分成两部分—-根据原系统业务数据的特点进行主题的抽取和确定每个主题所包含的数据内容。例如客户主题、产品主题、财务主题等;而客户主题包括客户基本信息、客户信用信息、客户资源信息等内容。分析数据仓库主题的时候,一般方法是先确定几个基本的 主题,然后再将范围扩大,最后再逐步求精
1.2.2集成性
面向操作型的数据库通常是异构的、并且相互独立,所以无法对信息进行概括和反映信
息的本质。而数据仓库中的数据是经过数据的抽取、清洗、切换、加载得到的,所以为了保证数据不存在二义性,必须对数据进行编码统一和必要的汇总,以保证数据仓库内数据的一致性。数据仓库在经历数据集成阶段后,使数据仓库中的数据都遵守统一的编码规则,并且消除许多冗余数据。
·
1.2.3稳定性
数据仓库中的数据反映的都是一段历史时期的数据内容,它的主要操作是查询、分析而
不进行一般意义上的更新(数据集成前的操作型数据库主要完成数据的增加、修改、删除、查询),一旦某个数据进入到数据仓库后,一般情况下数据会被长期保留,当超过规定的期限才会被删除。通常数据仓库需要做的工作就是加载、查询和分析,一般不进行任何修改操作,是为了企业高层 人员决策分析之用。
·
1.2.4反映历史变化
数据仓库不断从操作型数据库或其他数据源获取变化的数据,从而分析和预测需
要的历史数据,所以一般数据仓库中数据表的键码(维度)都含有时间键,以表明数据的历史时期信息,然后不断增加新的数据内容。通过这些历史信息可以对企业的发展历程和趋势做出分析和预测。数据仓库的建设需要大量的业务数据作为积累,并将这些宝贵的历史信息经过加工、整理,最后提供给决策分析人员,这是数据仓库建设的根本目的。
1.3 数据仓库发展历程
数据仓库的发展大致经历了这样的三个过程:
- 简单报表阶段:这个阶段,系统的主要目标是解决一些日常的工作中业务人员需要的报表,以及生成一些简单的能够帮助领导进行决策所需要的汇总数据。这个阶段的大部分表现形式为数据库和前端报表工具。
- 数据集市阶段:这个阶段,主要是根据某个业务部门的需要,进行一定的数据的采集,整理,按照业务人员的需要,进行多维报表的展现,能够提供对特定业务指导的数据,并且能够提供特定的领导决策数据。
- 数据仓库阶段:这个阶段,主要是按照一定的数据模型,对整个企业的数据进行采集,整理,并且能够按照各个业务部门的需要,提供跨部门的,完全一致的业务报表数据,能够通过数据仓库生成对对业务具有指导性的数据,同时,为领导决策提供全面的数据支持。
通过数据仓库建设的发展阶段,我们能够看出,数据仓库的建设和数据集市的建设的重要区别就在于数据模型的支持。因此,数据模型的建设,对于我们数据仓库的建设,有着决定性的意义。
1.4 数据仓库意义
- 建立公司统一数据中心
- 为数据BP。运营人员提供数据支持
- 为领导提供决策支持
1.5 数据库和数据仓库的区别
1.5.1数据库
是一种逻辑概念,用来存放数据的仓库,通过数据库软件来实现,数据库由许多表组成,表是二维的,一张表里面可以有很多字段,数据库的表,在与能够用二维表现多维关系。
1.5.2数据仓库
是数据库概念的升级。从逻辑上理解,数据库和数据仓库没有区别,都是通过数据库软件实现的存放数据的地方,只不过从数据量来说,数据仓库要比数据库更庞大得多。数据仓库主要用于数据挖掘和数据分析,辅助领导做决策。
数据库与数据仓库的区别实际讲的是OLTP与OLAP的区别。
1.5.3 对比
操作型处理,叫联机事务处理OLTP(On-Line Transaction Processing,),也可以称面向交易的处理系统,它是针对具体业务在数据库联机的日常操作,通常对少数记录进行查询、修改。用户较为关心操作的响应时间、数据的安全性、完整性和并发支持的用户数等问题。传统的数据库系统作为数据管理的主要手段,主要用于操作型处理。
分析型处理,叫联机分析处理OLAP(On-Line Analytical Processing)一般针对某些主题的历史数据进行分析,支持管理决策。
二 离线数据仓库架构
2.1 数据调研
2.1.1业务调研
数据仓库是要涵盖所有业务领域,还是各个业务领域独自建设,业务领域内的业务线也同样面临着这个问题。所以要构建大数据数据仓库,就需要了解各个业务领域、业务线的业务有什么共同点和不同点,以及各个业务线可以细分为哪几个业务模块,每个业务模块具体的业务流程又是怎样的。业务调研是否充分,将会直接决定数据仓库建设是否成功。
2.1.2需求调研
了解业务系统的业务后不等于说就可以实施数仓建设了,还需要收集数据使用者的需求,及找分析师、运营人员、产品人员等了解他们对数据的诉求。通常需求调研分下面两种途径:
1. 根据与分析师、运营人员、产品人员的沟通获取需求。
2. 对现有报表、数据进行研究分析获取数据建设需求。
2.1.3数据调研
需要了解数据库类型,数据来源,全量数据情况及数据每年增长情况,更新机制;还需要了解数据是否结构化,是否清洗,是接口调用还是直接访问库,有哪些类型的数据,数据结构之怎样的。
2.2 数据采集
2.2.1 日志数据
2.2.1.1埋点日志
- 浏览日志(h5,web,app)
- 点击日志(h5,web,app)
2.2.1.2服务日志
- 应用访问日志
- 接口调用日志
2.2.1.3 NG日志
(h5,web,app)
2.2.1.4采集字段
|
account string, appId string, appVersion string, carrier string, deviceId string, deviceType string, eventId string, ip string, latitude double, longitude double, netType string, osName string, osVersion string, properties map<string,string>, releaseChannel string, resolution string, sessionId string, `timeStamp` bigint …… |
2.2.2 业务数据
- Mysql
- MongoDB
- Oracle
2.2.3 爬虫数据
- 竞品数据
- 维表数据
2.2 ETL
ETL是将业务系统的数据经过抽取、清洗转换之后加载到数据仓库的过程,目的是将企业中的分散、零乱、标准不统一的数据整合到一起,为企业的决策提供分析依据
2.2.1 数据抽取(Extract)
主要是从业务库把数据抽取到数据仓库或者把日志采集到数据仓库
2.2.1.1 业务数据抽取
2.2.1.1.1前言
sqoop和datax作为2款优秀的数据同步工具,备受数据开发人员喜爱,如何选择也是件非常头疼的事,下面就这两种工具来分析分析吧…
2.2.1.1.2 sqoop
sqoop 是 apache 旗下一款“Hadoop中的各种存储系统(HDFS、HIVE、HBASE) 和关系数据库(mysql、oracle、sqlserver等)服务器之间传送数据”的工具。
导入数据:MySQL,Oracle 导入数据到 Hadoop 的 HDFS、HIVE、HBASE 等数据存储系统
导出数据:从 Hadoop 的文件系统中导出数据到关系数据库 mysql 等 Sqoop 的本质还是一个命令行工具。
底层工作机制
将导入或导出命令翻译成 MapReduce 程序来实现
在翻译出的 MapReduce 中主要是对InputFormat 和
OutputFormat 进行定制
|
sqoop import \ –connect jdbc:mysql://hadoop:3306/mysql \ –username root \ –password \ –table order_info \ –target-dir /user/project/t_order_info \ –fields-terminated-by ‘\t’ \ –split-by order_id \ -m 2 |
2.2.1.1.3 datax
DataX 是一个异构数据源离线同步工具,致力于实现包括关系型数据库(MySQL、Oracle等)、HDFS、Hive、ODPS、HBase、FTP等各种异构数据源之间稳定高效的数据同步功能。
核心架构
DataX本身作为离线数据同步框架,采用Framework + plugin架构构建。将数据源读取和写入抽象成为Reader/Writer插件,纳入到整个同步框架中。
- Reader:Reader为数据采集模块,负责采集数据源的数据,将数据发送给Framework。
- Writer:Writer为数据写入模块,负责不断向Framework取数据,并将数据写入到目的端。
- Framework:Framework用于连接reader和writer,作为两者的数据传输通道,并处理缓冲,流控,并发,数据转换等核心技术问题。
DataX完成单个数据同步的作业,我们称之为Job,DataX接受到一个Job之后,将启动一个进程来完成整个作业同步过程。DataX Job模块是单个作业的中枢管理节点,承担了数据清理、子任务切分(将单一作业计算转化为多个子Task)、TaskGroup管理等功能。
DataXJob启动后,会根据不同的源端切分策略,将Job切分成多个小的Task(子任务),以便于并发执行。Task便是DataX作业的最小单元,每一个Task都会负责一部分数据的同步工作。
切分多个Task之后,DataX Job会调用Scheduler模块,根据配置的并发数据量,将拆分成的Task重新组合,组装成TaskGroup(任务组)。每一个TaskGroup负责以一定的并发运行完毕分配好的所有Task,默认单个任务组的并发数量为5。
每一个Task都由TaskGroup负责启动,Task启动后,会固定启动Reader—>Channel—>Writer的线程来完成任务同步工作。
DataX作业运行起来之后, Job监控并等待多个TaskGroup模块任务完成,等待所有TaskGroup任务完成后Job成功退出。否则,异常退出,进程退出值非0
DataX调度流程:
举例来说,用户提交了一个DataX作业,并且配置了20个并发,目的是将一个100张分表的mysql数据同步到odps里面。DataX的调度决策思路是:
DataXJob根据分库分表切分成了100个Task。
根据20个并发,DataX计算共需要分配4个TaskGroup。
4个TaskGroup平分切分好的100个Task,每一个TaskGroup负责以5个并发共计运行25个Task。
下面以datax抽取mysql数据写入hdfs为例:
|
{ “job”: { “setting”: { “speed”: { “channel”: 3 }, “errorLimit”: { “record”: 0, “percentage”: 0.02 } }, “content”: [{ “reader”: { “name”: “mysqlreader”, “parameter”: { “username”: “root”, “password”: “root”, “column”: [‘id’, ‘name’ ], “where”:”gmt_created>=’$bizdate’ and gmt_created<DATE_ADD(‘$bizdate’,INTERVAL 1 DAY)”, “splitPk”: “id”, “connection”: [{ “table”: [ “table” ], “jdbcUrl”: [ “jdbc:mysql://127.0.0.1:3306/database” ] }] } }, “writer”: { “name”: “hdfswriter”, “parameter”: { “defaultFS”: “hdfs://xxx:port”, “fileType”: “orc”, “path”: “/user/hive/warehouse/writerorc.db/orcfull”, “fileName”: “xxx”, “column”: [{ “name”: “id”, “type”: “BIGINT” }, { “name”: “name”, “type”: “STRING” } ], “writeMode”: “append”, “fieldDelimiter”: “\t”, “compress”: “GZIP” } } }] } } |
2.2.1.1.4对比
|
功能 |
datax |
sqoop |
|
运行模式 |
单进程多线程 |
mr |
|
hive读写 |
单机压力大 |
扩展性好 |
|
分布式 |
不支持 |
支持 |
|
运行信息 |
运行时间,数据量,消耗资源,脏数据稽核 |
不支持 |
|
流量控制 |
支持 |
不支持 |
|
社区 |
开源不久,不太活跃 |
活跃 |
2.2.1.1.5总结
对于sqoop和datax,如果只是单纯的数据同步,其实两者都是ok的,但是如果需要集成在大数据平台,还是比较推荐使用datax,原因就是支持流量控制,支持运行信息收集,及时跟踪数据同步情况。
大数据私房菜 提了一个问题
那么你们公司使用的是sqoop还是datax呢?是怎么考虑的?
附:
(有很多朋友私信问datax能操作哪些数据库或者文件,以下把datax各子工程贴出来了,下面有的就是支持的,否则就需要二次开发了)
2.2.1.2 日志采集
2.2.1.2.1 flume
Apache Flume 是一个从可以收集例如日志,事件等数据资源,并将这些数量庞大的数据从各项数据资源中集中起来存储的工具/服务。flume具有高可用,分布式和丰富的配置工具,其结构如下图所示:
Flume:是一个数据采集工具;可以从各种各样的数据源(服务器)上采集数据传输(汇聚)到大数据生态的各种存储系统中(Hdfs、hbase、hive、kafka);
开箱即用!(安装部署、修改配置文件)
Flume可以采集文件,socket数据包(网络端口)、文件夹、kafka、mysql数据库等各种形式源数据,又可以将采集到的数据(下沉sink)输出到HDFS、hbase、hive、kafka等众多外部存储系统中
一般的采集、传输需求,通过对flume的简单配置即可实现;不用开发一行代码!
Flume针对特殊场景也具备良好的自定义扩展能力,因此,flume可以适用于大部分的日常数据采集场景
Flume中最核心的角色是agent,flume采集系统就是由一个个agent连接起来所形成的一个或简单或复杂的数据传输通道。
对于每一个Agent来说,它就是一个独立的守护进程(JVM),它负责从数据源接收数据,并发往下一个目的地,如下图所示:
Source:采集组件,用于跟数据源对接,以获取数据;它有各种各样的内置实现;
Sink:下沉组件,用于往下一级agent传递数据或者向最终存储系统传递数据
Channel:传输通道组件,用于从source将数据传递到sink
根据需求,首先定义以下3大要素
采集源,即source——监控文件内容更新 : exec ‘tail -F file’
下沉目标,即sink——HDFS文件系统 : hdfs sink
Source和sink之间的传递通道——channel,可用file channel 也可以用 内存channel
配置文件编写:
|
agent1.sources = source1 agent1.sinks = sink1 agent1.channels = channel1
# Describe/configure tail -F source1 agent1.sources.source1.type = exec agent1.sources.source1.command = tail -F /home/hadoop/logs/access_log agent1.sources.source1.channels = channel1
#configure host for source agent1.sources.source1.interceptors = i1 agent1.sources.source1.interceptors.i1.type = host agent1.sources.source1.interceptors.i1.hostHeader = hostname
# Describe sink1 agent1.sinks.sink1.type = hdfs #a1.sinks.k1.channel = c1 agent1.sinks.sink1.hdfs.path =hdfs://hadoop1:9000/weblog/flume-collection/%y-%m-%d/%H-%M agent1.sinks.sink1.hdfs.filePrefix = access_log agent1.sinks.sink1.hdfs.maxOpenFiles = 5000 agent1.sinks.sink1.hdfs.batchSize= 100 agent1.sinks.sink1.hdfs.fileType = DataStream agent1.sinks.sink1.hdfs.writeFormat =Text agent1.sinks.sink1.hdfs.rollSize = agent1.sinks.sink1.hdfs.rollCount = agent1.sinks.sink1.hdfs.rollInterval = 60 agent1.sinks.sink1.hdfs.round = true agent1.sinks.sink1.hdfs.roundValue = 10 agent1.sinks.sink1.hdfs.roundUnit = minute agent1.sinks.sink1.hdfs.useLocalTimeStamp = true
# Use a channel which buffers events in memory agent1.channels.channel1.type = memory agent1.channels.channel1.keep-alive = 120 agent1.channels.channel1.capacity = agent1.channels.channel1.transactionCapacity = 600
# Bind the source and sink to the channel agent1.sources.source1.channels = channel1 agent1.sinks.sink1.channel = channel1
|
2.2.1.2.2 logstash
Logstash是一个开源的服务器端数据处理管道,它可以同时从多个源中提取数据,对其进行转换,然后将其发送其他存储。
原始日志文件:
|
[2019-01-14 00:02:11] [INFO] – com.test.pushTest(PushMessageExecutor.java:103) – 消息推送结果:响应状态(200)、状态描述(成功。)、响应反馈()、请求响应耗时(232ms),deviceToken:7b64436eeea34a3ab4e0873b0682ad98e,userId:,auId:null, globalMessageId:2d09f8dc1f9c66b61,appId:p_ios,title:null,subTitle:null,alertBody:请及时查阅。.
|
配置文件demo:
|
input { file { path => “/data/liuzc/test_log/*” type => “aa” start_position => “beginning” sincedb_path => “/dev/null” } }
filter { multiline { pattern => “%{DATESTAMP}” negate => true what => “previous” }
if [type] == “aa” { grok { match => { “message” => “\[%{DATA:time_local}\] \[%{LOGLEVEL:log_level}\] – %{NOTSPACE:pushExecute} – %{NOTSPACE:apns_push_result},deviceToken:%{NOTSPACE:deviceToken},userId:%{NOTSPACE:userId},auId:%{NOTSPACE:auId},globalMessageId:%{NOTSPACE:globalMessageId},appId:%{NOTSPACE:appId},title:%{NOTSPACE:title},subTitle:%{NOTSPACE:subTitle},alertBody:%{NOTSPACE:alertBody}” } } } else { grok { match => { “message” => “%{DATESTAMP:time_local} %{LOGLEVEL:log_level}” } } } #ruby { # code => ‘ # event[“datestr”] = event[“@timestamp”].time.getlocal(“+08:00”).strftime “%Y-%m-%d” # event[“hours”] = event[“@timestamp”].time.getlocal(“+08:00”).strftime(“%H”).to_i # ‘ # }
date { match => [“time_local”, “yy/MM/dd-HH:mm:ss.SSS”] }
}
output { stdout{codec=>”rubydebug”} } |
解析结果:
|
{ “message” => “[2019-01-14 00:02:11] [INFO] – com.test.pushTest(PushMessageExecutor.java:103) – 消息推送结果:响应状态(200)、状态描述(成功。)、响应反馈()、请求响应耗时(232ms),deviceToken:7b64436eeea34a3ab4e0873b0682ad98e,userId:,auId:null,globalMessageId:2d09f8dc1f9c66b61,appId:p_ios,title:null,subTitle:null,alertBody:请及时查阅。.”, “@version” => “1”, “@timestamp” => “2019-01-17T01:16:06.468Z”, “host” => “xy1”, “path” => “/data/liuzc/test_log/test-2019-01-14.log”, “type” => “aa”, “time_local” => “2019-01-14 00:02:11”, “log_level” => “INFO”, “pushExecute” => “com.test.pushExecute(PushMessageExecutor.java:103)”, “apns_push_result” => “消息推送结果:响应状态(200)、状态描述(成功。)、响应反馈()、请求响应耗时(232ms)”, “deviceToken” => “7b64436eeea34a3ab4e0873b0682ad98e”, “userId” => “”, “auId” => “null”, “globalMessageId” => “2d09f8dc1f9c66b61”, “appId” => “p_ios”, “title” => “null”, “subTitle” => “null”, “alertBody” => “请及时查阅。.” } |
Logstash grok在线验证地址:
l 国内:http://grok.qiexun.net/
l 国外:http://grokdebug.herokuapp.com/
2.2.1.2.3 对比
l Logstash和flume都能作为日志采集工具
l Logstash是由ruby开发,flume使用java语言开发
l Logstash每起一个进程,默认占用1G内存,如果进程起的多的话给应用服务器带来很大的压力
2.2.2 数据清洗转换(Cleaning、Transform)
数据清洗的任务是过滤那些不符合要求的数据
数据转换的任务主要进行不一致的数据转换、数据粒度的转换,以及一些业务规则的计算。
2.2.2.1 ID-MAPPING
登录状态下,日志中会采集到用户的登录id(account),可以做到用户身份的精确标识;而在匿名状态下,日志中没有采集到用户的登录id,准确标识用户,成为一件极其棘手的事情
解决方案:关联设备 ID 和登录 ID(动态修正)
一个设备ID被绑定到某个登陆ID(A)之后,如果该设备在后续一段时间(比如一个月内)被一个新的登陆ID(B)更频繁使用,则该设备ID会被调整至绑定登陆ID(B)
2.2.2.2 数据清洗
- 单位统一,比如金额单位统一为元
- 字段类型统一
- 注释补全
- 空值用默认值或者中位数填充
- 时间字段格式统一,如2020-10-16,2020/10/16,统一格式为2020-10-16
- 过滤没有意义的数据
- ……
2.2.2.3 数据转换
下面会介绍模型建设
2.2.3 数据加载(load)
数据同步到其他存储系统,如mysql,hbase
2.3 数据存储
数据存储在hdfs,包含元数据和主数据的存储
2.4 数据应用
- 数据同步到mysql提供接口
- 数据同步到需求方mysql库直接调用
- 数据同步到kylin(olap)做预计算,为需求方提供数据做多维分析
- 数据同步到hbase提供接口服务
- 数据同步到pg提供数据
- 用户画像
- 推荐系统
- 运营系统
- 报表系统
- 业务系统
- BI可视化
2.5 简单架构
三 数据建模
3.1 前言
3.1.1 什么是数据建模
数据建模简单来说就是基于对业务的理解,将各种数据进行整合和关联,并最终使得这些数据可用性,可读性增强,让使用方能快速的获取到自己关心的有价值的信息并且及时的作出响应,为公司带来效益。
3.1.2 为什么要数据建模
数据建模是一套方法论,主要是对数据的整合和存储做一些指导,强调从各个角度合理的存储数据。
· 进行全面的业务梳理,改进业务流程。
在业务模型建设的阶段,能够帮助我们的企业或者是管理机关对本单位的业务进行全面的梳理。通过业务模型的建设,我们应该能够全面了解该单位的业务架构图和整个业务的运行情况,能够将业务按照特定的规律进行分门别类和程序化,同时,帮助我们进一步的改进业务的流程,提高业务效率,指导我们的业务部门的生产。
· 建立全方位的数据视角,消灭信息孤岛和数据差异。
通过数据仓库的模型建设,能够为企业提供一个整体的数据视角,不再是各个部门只是关注自己的数据,而且通过模型的建设,勾勒出了部门之间内在的联系,帮助消灭各个部门之间的信息孤岛的问题,更为重要的是,通过数据模型的建设,能够保证整个企业的数据的一致性,各个部门之间数据的差异将会得到有效解决。
· 解决业务的变动和数据仓库的灵活性。
通过数据模型的建设,能够很好的分离出底层技术的实现和上层业务的展现。当上层业务发生变化时,通过数据模型,底层的技术实现可以非常轻松的完成业务的变动,从而达到整个数据仓库系统的灵活性。
· 帮助数据仓库系统本身的建设。
通过数据仓库的模型建设,开发人员和业务人员能够很容易的达成系统建设范围的界定,以及长期目标的规划,从而能够使整个项目组明确当前的任务,加快整个系统建设的速度。
有了合适的数据模型,是会带来很多好处的:
- 查询使用性能提升
- 用户效率提高,改善用户体验
- 数据质量提升
- 降低企业成本
- ……
所以大数据系统需要数据模型方法来更好的组织和存储,以便在性能,成本,效率和质量之间取的平衡。
3.2 建模工具
PowerDesigner:
Power Designer 是Sybase公司的CASE工具集,使用它可以方便地对管理信息系统进行分析设计,他几乎包括了数据库模型设计的全过程。利用Power Designer可以制作数据流程图、概念数据模型、物理数据模型,还可以为数据仓库制作结构模型,也能对团队设计模型进行控制。他可以与许多流行的软件开发工具,例如PowerBuilder、Delphi、VB等相配合使开发时间缩短和使系统设计更优化。
power designer是能进行数据库设计的强大的软件,是一款开发人员常用的数据库建模工具。使用它可以分别从概念数据模型(Conceptual Data Model)和物理数据模型(Physical Data Model)两个层次对数据库进行设计。在这里,概念数据模型描述的是独立于数据库管理系统(DBMS)的实体定义和实体关系定义;物理数据模型是在概念数据模型的基础上针对目标数据库管理系统的具体化。
3.3 Kimball和Inmon架构
3.3.1 Inmon架构
辐射状企业信息工厂(CIF) 方法由Bill Inmon及业界人士倡导的。在这个环境下,数据从操作性数据源中获取,在ETL系统中处理,将这一过程称为数据获取,从这一过程中获得的原子数据保存在满足第三范式的数据库中,这种规范化的原子数据的仓库被称为CIF架构下的企业级数据仓库(EDW)
与Kimball方法相似,CIF提倡企业数据协调与集成,但CIF认为要利用规范化的EDW承担这一角色,而Kimball架构强调具有一致性维度的企业总线的重要作用
Inmon企业级数据仓库的分析数据库通常以部门为中心(而不是围绕业务过程来组织),而且包含汇总数据,并不是原子级别数据,如果ETL过程中数据所应用的业务规则超越了基本概要,如部门改名了或者其他的类似计算,要将分析数据库与EDW原子数据联系起来将变得很困难
3.3.2 Kimball架构
Kimball架构利用了CIF中处于中心地位的EDW,但是此次的EDW完全与分析与报表用户隔离,仅作为数据来源,其中数据是维度的,原子的,以过程为中心的,与企业级数据仓库总线结构保持一致。
3.3.3 架构对比
3.3.3.1流程
Inmon架构是自顶向下,即从数据抽取–>数据仓库–>数据集市,以数据源为导向,是一种瀑布流开发方法,模型偏向于3NF,
Kimball:架构是自下向上,即从数据集市(主题划分)–>数据仓库–> 数据抽取,是以需求为导向的,一般使用星型模型
3.3.3.2事实表和维表
Inmon架构下,不强调事实表和维表的概念,因为数据源变化可能会比较大,更加强调的是数据清洗的工作
kimball架构强调模型由事实表和维表组成,注重事实表与维表的设计
3.3.3.3数据集市
Inmon架构中,数据集市有自己的物理存储,是真实存在的。
Kimball数据仓库架构中,数据集市是一个逻辑概念,只是多维数据仓库中的主题域划分,并没有自己的物理存储,也可以说是虚拟的数据集市。是数据仓库的一个访问层,是按主题域组织的数据集合,用于支持部门级的决策。
3.3.3.4中心
Inmon架构是以部门为中心,而Kimball架构是以业务过程为中心
3.3.3.5 EDW的访问
Inmon架构中用户可以直接访问企业数据仓库(EDW)
Kimball架构中用户不可以直接访问企业数据仓库(EDW),只能访问展现区数据
企业开发中一般选择Kimball维度建模
3.4 数仓建模阶段划分
3.4.1 业务模型
生成业务模型,主要解决业务层面的分解和程序化
- 划分整个单位的业务,一般按照业务部门的划分,进行各个部分之间业务工作的界定,理清各业务部门之间的关系。
- 深入了解各个业务部门的内具体业务流程并将其程序化。
- 提出修改和改进业务部门工作流程的方法并程序化。
- 数据建模的范围界定,整个数据仓库项目的目标和阶段划分。
3.4.2 领域模型
生成领域模型,主要是对业务模型进行抽象处理,生成领域概念模型。
- 抽取关键业务概念,并将之抽象化。
- 将业务概念分组,按照业务主线聚合类似的分组概念。
- 细化分组概念,理清分组概念内的业务流程并抽象化。
- 理清分组概念之间的关联,形成完整的领域概念模型。
3.4.3 逻辑模型
生成逻辑模型,主要是将领域模型的概念实体以及实体之间的关系进行数据库层次的逻辑化。
- 业务概念实体化,并考虑其具体的属性
- 事件实体化,并考虑其属性内容
- 说明实体化,并考虑其属性内容
3.4.4 物理模型
生成物理模型,主要解决,逻辑模型针对不同关系型数据库的物理化以及性能等一些具体的技术问题。
- 针对特定物理化平台,做出相应的技术调整
- 针对模型的性能考虑,对特定平台作出相应的调整
- 针对管理的需要,结合特定的平台,做出相应的调整
- 生成最后的执行脚本并完善。
3.5 模型建设方法
3.5.1 ER模型
ER模型是属于三范式的,是企业级的主题抽象而不是单独描述某个业务
3.5.1.1 什么是范式
当分类不可再分时,这种关系是规范化的,一个低级范式分解转换为更高级的范式时,就叫做规范化
数据表可以分为1-5NF,第一范式是最低要求,第五范式则是最高要求
最常用的范式有第一范式(1NF)、第二范式(2NF)、第三范式(3NF)
3.5.1.2 第一范式
表中的每一列都是不可拆分的原子项
3.5.1.3 第二范式
第二范式要同时满足下面两个条件:
- 满足第一范式
- 没有部分依赖
上图可以看出,如果一个用户下了很多订单,则用户名,收获地址和手机号有重复出现的情况造成数据冗余,很明显不太符合第二范式,可以改成:
3.5.1.4 第三范式
第三范式要同时满足下面两个条件:
- 满足第二范式
- 没有传递依赖
简单点说,关系重复,能互相推导出来
如上图所示,如果知道了zip邮编,其实是能推出来省市区的,相反,知道了省市区,也是可以推出邮编的,有传递依赖,造成了冗余,不符合第三范式,需要改造:
3.5.1.5 小结
在关系数据模型设计中,一般需要满足第三范式的要求。如果一个表有良好的主外键设计,就应该是满足3NF的表。
规范化带来的好处是通过减少数据冗余提高更新数据的效率,同时保证数据完整性。然而,我们在实际应用中也要防止过度规范化的问题。规范化程度越高,划分的表就越多,在查询数据时越有可能使用表连接操作。
而如果连接的表过多,会影响查询的性能。关键的问题是要依据业务需求,仔细权衡数据查询和数据更新的关系,制定最适合的规范化程度。还有一点需要注意的是,不要为了遵循严格的规范化规则而修改业务需求。
3.5.2 维度建模
维度建模是一种将大量数据结构化的逻辑设计手段,包含维度和指标,它不像ER模型目的是消除冗余数据,维度建模是面向分析,最终目的是提高查询性能,所以会增加数据冗余,并且违反三范式。
维度建模也是重点关注让用户快速完成需求分析且对于复杂查询及时响应,维度建模一般可以分为三种:
- 星型模型
- 雪花模型
- 星座模型
其中最常用的其实是星型模型
3.5.2.1 背景
在多维分析的商业智能解决方案中,根据事实表和维度表的关系,又可将常见的模型分为星型模型,雪花型模型及星座模型。在设计逻辑型数据的模型的时候,就应考虑数据是按照星型模型,雪花型模型还是星座模型进行组织。
3.5.2.2 事实表和维度表
3.5.2.2.1事实表(Fact Table)
指存储有事实记录的表,如系统日志、销售记录等;事实表的记录在不断地动态增长,所以它的体积通常远大于其他表。
事实表作为数据仓库建模的核心,需要根据业务过程来设计,包含了引用的维度和业务过程有关的度量。
作为度量业务过程的事实,一般为整型或浮点型的十进制数值,有可加性,半可加性和不可加性三种类型
3.5.2.2.2可加
最灵活最有用的事实是完全可加,可加性度量可以按照与事实表关联的任意维度汇总。比如订单总金额
3.5.2.2.3半可加
半可加度量可以对某些维度汇总,但不能对所有维度汇总。差额是常见的半可加事实,除了时间维度外,他们可以跨所有维度进行操作。(比如每天的余额加起来毫无意义)
3.5.2.2.4不可加
一些度量是完全不可加的,例如:比率。对非可加事实,一种好的方法是,分解为可加的组件来实现聚集
3.5.2.2.5维度表
维度表(Dimension Table)或维表,有时也称查找表(Lookup Table),是与事实表相对应的一种表;它保存了维度的属性值,可以跟事实表做关联;相当于将事实表上经常重复出现的属性抽取、规范出来用一张表进行管理。常见的维度表有:日期表(存储与日期对应的周、月、季度等的属性)、地点表(包含国家、省/州、城市等属性)等。维度是维度建模的基础和灵魂。
3.5.2.2.6 优点
- 缩小了事实表的大小。
- 便于维度的管理和维护,增加、删除和修改维度的属性,不必对事实表的大量记录进行改动。
- 维度表可以为多个事实表重用,以减少重复工作。
3.5.2.2.7下钻
下钻是商业用户分析数据的最基本的方法。下钻仅需要在查询上增加一个行头指针,新行的头指针是一个维度属性,附加了sql语言的group by表达式,属性可以来自任何与查询使用的事实表关联的维度,下钻不需要预先存在层次的定义,或者是下钻路径。
3.5.2.2.8退化维度
有时,维度除了主键外没有其他内容,例如,当某一发票包含多个数据项时,数据项事实行继承了发票的所有描述性维度外键,发票除了外键无其他项,但发票数量仍然是在此数据项级别的合法维度键。这种退化维度被放入事实表中,清楚的表明没有关联的维度表,退化维度常见于交易和累计快照事实表中。
3.5.2.3事实表和维表的关系
3.5.2.3 星型模型
星形模型中有一张事实表,以及零个或多个维度表,事实表与维度表通过主键外键相关联,维度表之间没有关联,当所有维表都直接连接到“ 事实表”上时,整个图解就像星星一样,故将该模型称为星型模型。星形模型是最简单,也是最常用的模型。由于星形模型只有一张大表,因此它相比于其他模型更适合于大数据处理。其他模型可以通过一定的转换,变为星形模型。
星型架构是一种非正规化的结构,多维数据集的每一个维度都直接与事实表相连接,不存在渐变维度,所以数据有一定的冗余,如在地域维度表中,存在国家 A 省 B 的城市 C 以及国家 A 省 B 的城市 D 两条记录,那么国家 A 和省 B 的信息分别存储了两次,即存在冗余。
3.5.2.4 雪花模型
当有一个或多个维表没有直接连接到事实表上,而是通过其他维表连接到事实表上时,其图解就像多个雪花连接在一起,故称雪花模型。雪花模型是对星型模型的扩展。它对星型模型的维表进一步层次化,原有的各维表可能被扩展为小的维度表,形成一些局部的 ” 层次 ” 区域,这些被分解的表都连接到主维度表而不是事实表。如图,将地域维表又分解为国家,省份,城市等维表。它的优点是 : 通过最大限度地减少数据存储量以及联合较小的维表来改善查询性能。雪花型结构去除了数据冗余。
3.5.2.5 星座模型
星座模型是由星型模型延伸而来,星型模型是基于一张事实表而星座模式是基于多张事实表,并且共享维度表信息,这种模型往往应用于数据关系比星型模型和雪花模型更复杂的场合。星座模型需要多个事实表共享维度表,因而可以视为星形模型的集合,故亦被称为星系模型
3.5.2.6 对比
- 星型模型因为数据的冗余所以很多统计查询不需要做外部的连接,因此一般情况下效率比雪花型模型要高。
- 星型结构不用考虑很多正规化的因素,设计与实现都比较简单。
- 雪花型模型由于去除了冗余,有些统计就需要通过表的联接才能产生,所以效率比较低。
- 正规化也是一种比较复杂的过程,相应的数据库结构设计、数据的 ETL、以及后期的维护都要复杂一些。
3.5.2.7 小结
通过对比,我们可以发现数据仓库大多数时候是比较适合使用星型模型构建底层数据Hive表,通过大量的冗余来减少表查询的次数从而提升查询效率,星型模型对OLAP的分析引擎支持比较友好,这一点在Kylin中比较能体现。而雪花模型在关系型数据库中如MySQL,Oracle中非常常见,尤其像电商的数据库表。在数据仓库中雪花模型和星座模型的应用场景比较少,但也不是没有,所以在具体设计的时候,可以考虑是不是能结合两者的优点参与设计,以此达到设计的最优化目的。
3.5.2.8 建模原则
- 高内聚和低辑合
将业务相近或者相关、粒度相同的数据设计为一个逻辑或者物理模型:将高概率 同 时访问的数据放一起 ,将低概率同时访问的数据分开存储。
- 核心模型与扩展模型分离
建立核心模型与扩展模型体系,核心模型包括的宇段支持常用的核心业务,扩展模 型包括的字段支持个性化或少量应用的需要 ,不能让扩展模型的宇段过度侵人核心模型,以免破坏核心模型的架构简洁性与可维护性。
- 公共处理逻辑下沉及单一
越是底层公用的处理逻辑越应该在数据调度依赖的底层进行封装与实现,不要让公用的处理逻辑暴露给应用层实现,不要让公共逻辑多处同时存在。
- 成本与性能平衡
适当的数据冗余可换取查询和刷新性能,不宜过度冗余与数据复制。
- 数据可回滚
不改变处理逻辑,不修改代码的情况下重跑任务结果不变
- 一致性
字段命名及定义必须一致
- 命名清晰、可理解
表命名需清晰、一致,表名需易于使用方理解
3.5.2.9星型模型设计步骤
- 选择需要进行分析决策的业务过程,比如下单
- 选择粒度。在事件分析中,我们要预判所有分析需要细分的程度,从而决定选择的粒度。比如订单粒度,粒度是维度的一个组合。
- 识别维表。选择好粒度之后,就需要基于此粒度设计维表,包括维度属性,用于分析时进行分组和筛选。
- 选择事实。确定分析需要衡量的指标
3.5.3 Data Vault模型
Data Vault Dan Linstedt 发起创建的一种模型,它是模型的衍生,其设计的出发点也是为了实现数据的整合,但不能直接用于数据分析决策。它强调建立一个可审计的基础数据层,也就是强调数据的历史性、可追溯性和原子性,而不要求对数据进行过度的一致性处理和整合;
同时它基于主题概念将企业数据进行结构化组织,并引入了更进一步的范式处理来优化模型,以应对源系统变更的扩展性。Data Vault 型由以下几部分组成。
- Hub :是企业的核心业务实体,由 实体 key 、数据仓库序列代理键、装载时间、数据来源组成。
- Link :代表 Hub 之间的关系。这里与 模型最大的区别是将关系作为一个独立的单元抽象,可以提升模型的扩展性。它可以直接描述 1:1 1:n n:n 的关系,而不需要做任何变更。它由 Hub 的代理键、装载时间、数据来源组成。
- Satellite :是 Hub 的详细描述内容, 一个 Hub 可以有多个 Satellite它由 Hub 的代理键、装载时间、来源类型、详细的 Hub 描述信息组成。
Data Vault 模型比 ER 模型更容易设计和产出,它的 ETL 加工可实现配置化。
3.5.4 Anchor模型
进一步规范化处理,其核心思想是所有的扩展只添加而不是修改,因此将模型规范到6NF,基本编程了K-V结构化模型。
那么总的来说,分为三个阶段:
- 将数据以源表结构相同的方式同步到Oracle,数据工程师基于ODS数据进行统计。
- 通过一些模型技术改变烟囱式的开发模型,消除一些冗余,提升数据的一致性。(经验)在不太成熟、快速变化的业务面前,构建ER模型的风险非常大,不太适合去构建ER模型。
- 选择了以Kimball的维度建模为核心理念的模型方法论,同时对其进行了一定的升级和扩展,构建了公共层模型数据架构体系。
3.6 开发规范
3.6.1 开发流程
- 需求分析调研(数据调研,需求调研,业务调研):明确口径,评估排期,需求正规流程提交
- 指标管理:完善指标命名规范,指标同名同义,指标与业务强相关,明确指标构成要素
- 模型设计:完善开发流程规范,标准化业务调研,知识库文档集中管理,建立模型评审机制
- ETL开发:ODS->DWD->DW->DWS->ADS
- 数据验证:制定数据测试标准
- 任务调度:规范化调度参数配置
- 上线管理
3.6.2 分层规范
3.6.2.1前言
数据仓库一般分为三层,自上而下分别为数据贴源层(ODS,Operation Data Store)、数据公共层(CDM,Common Data Model)和数据应用层(ADS,Application Data Service)。
3.6.2.2 ODS层
贴源层,与业务库保持一致,不做任何处理
3.6.2.3 CDM层
数据公共层CDM(Common Data Model,又称通用数据模型层),包括DIM维度表、DWD,DW和DWS,由ODS层数据加工而成。主要完成数据加工与整合,建立一致性的维度,构建可复用的面向分析和统计的明细事实表,以及汇总公共粒度的指标
公共维度层(DIM):基于维度建模理念思想,建立企业一致性维度。降低数据计算口径和算法不统一风险。 公共维度层的表通常也被称为逻辑维度表,维度和维度逻辑表通常一一对应。
明细粒度事实层(DWD):对数据进行规范化编码转换,清洗,统一格式,脱敏等,不做横向整合
主题宽表层(DW) 对dwd各种信息进行整合,输出主题宽表(面向业务过 程,不同业务过程的信息不冗余建设,采用外键形式)
公共汇总粒度事实层(DWS):以分析的主题对象作为建模驱动,基于上层的应用和产品的指标需求,构建公共粒度的汇总指标事实表,以宽表化手段物理化模型。构建命名规范、口径一致的统计指标,为上层提供公共指标,建立汇总宽表、明细事实表。
公共汇总粒度事实层的表通常也被称为汇总逻辑表,用于存放派生指标数据。
3.6.2.4 ADS层
数据应用层ADS(Application Data Service):面向业务需求定制开发,存放数据产品个性化的统计指标数据。
3.6.2.5逻辑分层架构
3.6.2.6 分层的好处
- 清晰数据结构:每一个数据分层都有它的作用域,这样我们在使用表的时候能更方便地定位和理解。
- 数据血缘追踪:简单来讲可以这样理解,我们最终给业务呈现的是一张能直接使用的张业务表,但是它的来源有很多,如果有一张来源表出问题了,我们希望能够快速准确地定位到问题,并清楚它的危害范围。
- 减少重复开发:规范数据分层,开发一些通用的中间层数据,能够减少极大的重复计算。
- 把复杂问题简单化:将一个复杂的任务分解成多个步骤来完成,每一层只处理单一的步骤,比较简单和容易理解。而且便于维护数据的准确性,当数据出现问题之后,可以不用修复所有的数据,只需要从有问题的步骤开始修复。
3.6.2.7 数据流向
- 正常流向:ODS->DWD->DW->DWS->ADS,当出现ODS->DWD->DWS->ADS这种关系时,说明主题域未覆盖全。应将DWD数据落到DW中,对于使用频度非常低的表允许DWD->DWS。
- 尽量避免出现DWS宽表中使用DWD又使用(该DWD所归属主题域)DW的表。
- 同一主题域内对于DW生成DW的表,原则上要尽量避免,否则会影响ETL的效率。
- DW、DWS和ADS中禁止直接使用ODS的表, ODS的表只能被DWD引用。
- 禁止出现反向依赖,例如DW的表依赖DWS的表。
3.6.3 表命名规范
- 表名、字段名采用下划线分隔词根(consultorder->consult_order)
- 每部分使用小写英文单词,属于通用字段的必须满足通用字段信息的定义。
- 表名、字段名需以字母为开头。
- 表名、字段名最长不超过64个英文字符。
- 优先使用词根中已有关键字(数仓标准配置中的词根管理),定期Review新增命名的不合理性。
- 在表名自定义部分禁止采用非标准的缩写。
3.6.3.1 ods dwd层
建表表名一律小写
表名命名规则: [层次].[业务]_[表内容]_[周期+处理方式]
3.6.3.2 dw dws层
建表表名一律小写
表名命名规则: [层次].[主题]_[表内容]_[周期+处理方式] 主题在dw层以后,表内容 参考业务系统表名,做适当处理,分表规则可以没有
如:ods.test_order_info_df
ods表示层次,test表示主题,order_info表示表内容,d表示周期(天),f表示处理方式(全量抽取)
3.6.3.3 临时表 tmp
临时表命名规则:[层次].tb_目标表名_程序开始执行时间_序号
3.6.4 字段命名规范
- 有实际意义
- 根据词根组合而成
如: order_amt 订单金额
3.6.5 注释规范
- 能实际说明字段意义
- 字典需要注明 id和desc
如: order_id varchar comment ‘订单id’
order_status tinyint comment ‘1:已支付 2:已发货 3:已签收 ’
3.6.6 数据类型规范
根据实际需求选择字段类型
3.6.6.1 数字类
3.6.6.2 日期时间类
3.6.6.3 字符串类
3.6.6.4 Misc类
3.6.6.5 复合类
3.6.7 分区规范
- 什么情况需要分区
- 分区字段选择
- 分区字段命名规范
目前90%以上的分区表都是以日期分区的,当然,一些日志表还是有二级分区,如三端日志
3.6.8 词根规范
3.6.8.1 词根评审
需要新增一个词根的时候,需要部门评审,看看是否有必要新增,并且如果确定下来需要新增的话如何命名
比如 cnt 这个词代表的意思是count 数量,如果之前词根里面没有的话,理论上来说,新增该词根是没毛病的
3.6.8.2 词根大全
3.6.9 指标规范
3.6.9.1 指标定义
指标的定义(口径)需要与业务方,运营人员或者数据分析师综合确定
现列举一些常用流量指标:
- 日活跃度=当日启动用户/累计用户*100%
- 周活跃度=周活跃用户/累计用户*100%
- 月活跃度=月活跃用户/累计用户*100%
- 页面访问次数: 页面被打开的次数,同一页面的多次访问均会被计数。
- 页面平均停留时长: 每一次页面访问的停留时长的平均值
3.6.9.2 指标命名
3.6.9.2.1基础指标
主要是指不能再拆解的指标,通常表达业务实体原子量化属性的且不可再分的概念集合,如订单数
单个基础指标词根+修饰词
3.6.9.2.2 复合指标
建立在基础指标之上,通过一定运算规则形成的计算指标集合,如人均费用=总费用/人数
3.6.9.2.3派生指标
指的是基础指标或复合指标与维度成员,统计属性,管理属性等相结合产生的指标,如最近7天医生接单量=医生在过去7天一共接到的订单
多个基础指标词根+修饰词
3.5.9.3 指标评审
每定一个指标都是需要业务方(或其他部门)与数据部门一起评审决定的,包括指标是否有必要新增,如何定义等
3.5.9.4 指标存储展示
可以通过自研WEB系统来进行展示
展示内容可以有:
- 指标名称
- 指标编码
- 业务口径
- 指标类型
- 责任人
- 创建时间
- 状态
- ……
3.6.10 数据抽取规范
Mysql数据准备
第一天 9月10号数据
第二天 9月11号数据
对比mysql第一天和第二天的数据发现,第二天新增了订单id为4和5这两条数据,并且订单id为2和3的状态更新为了已支付
3.6.10.1全量表
每天的所有的最新状态的数据。
- 全量表,有无变化,都要报
- 每次上报的数据都是所有的数据(变化的 + 没有变化的)
9月10号全量抽取到ods层

9月11号全量抽取到ods层

全量抽取,每个分区保留历史全量快照。
3.6.10.2增量表
增量表:新增数据,增量数据是上次导出之后的新数据。
- 记录每次增加的量,而不是总量;
- 增量表,只报变化量,无变化不用报
- 业务库表中需有主键及创建时间,修改时间
9月10号全量抽取到ods层(全量初始化)
wedw_dwd.order_info_di表9月10号的分区数据与wedw_ods.order_info_增量抽取的数据合并,有2种方案
a.两个表通过主键关联,dwd表存在并且ods表不存在的数据
union all 一下wedw_ods.order_info_表所有的数据,即全量数据插入到dwd表的9月11号的分区
b.两个表数据union all一下,再根据order_id去重(根据order分组,更新时间降序,取第一条)
3.6.10.3 拉链表
- 维护历史状态,以及最新状态数据
- 数据量比较大
- 表中的部分字段会被更新
- 需要查看某一个时间点或者时间段的历史快照信息
- 查看某一个订单在历史某一个时间点的状态
- 某一个用户在过去某一段时间,下单次数
- 更新的比例和频率不是很大
如果表中信息变化不是很大,每天都保留一份全量,那么每次全量中会保存很多不变的信息,对存储是极大的浪费
优点
- 满足反应数据的历史状态
- 最大程度节省存储
9月10号全量抽取到ods层
建立dwd层拉链表
增加两个字段:start_dt(表示该条记录的生命周期开始时间——周期快照时的状态)end_dt(该条记录的生命周期结束时间)
end_dt= ‘9999-12-31’ 表示该条记录目前处于有效状态
注:第一次加工的时候需要初始化所有数据,start_time设置为数据日期2020-09-10 ,end_time设置为9999-12-31
9月11号抽取更新的数据及当天新增的数据到ods层,即订单id为2,3,4,5的数据
查询当前的所有有效记录:
查询9月10号历史快照:

查询9月11号历史快照:
3.6.10.4 流水表
对于表的每一个修改都会记录,可以用于反映实际记录的变更
3.6.10.5 总结
- 在工作中,其实上述3种表都是很有可能会用到的,那么我们应该怎么选择呢?
- 如果数据量不是很大(不超过20W)且预估后续增长的非常慢,可以考虑全量表抽取,这是最简便的方法
- 如果数据量目前来说不是很大,但是业务发展很快,数据量一段时间后就会上来,建议增量抽取哦
- 目前数据量本身就非常大,肯定是需要增量抽取的,比如现在有10亿数据,如果你每天全量抽取一遍,相信我,你会抽哭的
- 对于历史状态需要保存的,这个时候就需要使用拉链表了,实际工作中,使用拉链表的场景并不会太多,比如订单表,保存订单历史状态,维表(缓慢变化维的处理)
3.6.11 缓慢变化维处理
3.6.11.1背景
众所周知,虽然维度表属性相对稳定,但是并不是一成不变的,尽管相当缓慢,维度值仍会随时间而变化。比如商品类目的改变,医院等级的改变
在一些情况下,保留历史数据没有什么分析价值,而在另一些情况下,保留历史数据是非常重要的
3.6.11.2 解决方案
3.6.11.2.1重写维度值
在维度表中,仅需以当前值重写先前存在的值,不需要触碰事实表
缺点:如果业务需要准确的跟踪历史变化,这种方案是没法实现的,并且在以后想改变是非常困难的
修改之前
修改后:
3.6.11.2.2插入新的维度行
插入新的维度行。采用此种方式,保留历史数据,
维度值变化前的事实和过去的维度值关联,维度值变化后的事实和当前的维度值关联
缺点:虽然此方案能够区分历史情况,但是该方式不能将变化前后记录的事实归一为变化前的维度或者归一为变化后的维度
3.6.11.2.3添加维度列
有些是只保留最新的维度值和最近的维度值,也有的是维度值一有变化就新增一个属性字段。都不是很好的解决方案
变化前:
变化后:
3.6.11.2.4拉链表处理
这是精确跟踪缓慢变化维度属性的主要技术,因为新维度行能够自动划分事实表的历史,所以这是一项非常好的技术
变化前:
变化后:
3.6.12 多值维度及多值属性(交叉维度)
3.6.12.1背景
正常情况下,维表和事实表之间是一对多的关系,维表中的一行记录会连接事实表中的多行记录,事实表中的一行记录在维度表中只能关联上一条记录,不会发生数据发散的现象
想法是美好的,但是事实总是不尽人意。因为现实中不但事实表和维度表之间存在多对多的关系,维度表和维度表之间也存在多对多的关系
这两种情况本质是相同的,但事实表和维度表之间的多对多关系少了唯一描述事实和维度组的中间维度。
对于这两种情况,一种称为桥接表的中间表就需要派上用场了,并且还可以支持更为复杂的多对多的关系
3.6.12.2事实表与维度表多对多(多值维度)
比如下单了一套学习课程,但是这套课程并不是某一个用户买的,而是好几个用户合买的,所以为了处理这种情况,需要创建一个桥接表,将这些合买的用户组成一个组
权重是一个分数值,所有的用户组的权重累加起来为1。将权重和累加事实相乘,以按照每个用户在分组中的比重分配事实。
优点:
- 灵活简化了生成报表的难度
- 借权重避免了多重计算
缺点:
桥接表的维护比较复杂,当出现一个新组合时,得先判断桥接表中是否已存在
3.6.12.3维表与维表多对多(交叉维度)
从分析的角度来看,维度之间的多对多关系是一个很重要的概念,大多数维度都不是完全相互独立的。
在银行系统中,账户和顾客之间有直接关系,但不是一对一的关系。一个账户可以有一个或多个签名确认的用户,一个用户也可有多个账户
有2种方案解决
和多值维度一样,创建账户-用户组桥接表来连接事实表
还有一种方法是利用账户和用户之间的关系,如下图

桥接表可以捕获多对多关系,并且由于源系统中的关系是已知的,因此创建桥接表比多值维度手动构建维度表(桥接表)更容易
3.6.12.4总结
处理多值维度最好的办法是降低事实表的粒度。这种处理方式也是维度建模的一个原则,即事实表应该建立在最细粒度上。这样的处理,需要对事实表的事实进行分摊。
但是有些时候,事实表的粒度是不能降低的,多值维度的出现是无法避免的。如上述交叉维度,事实表与用户维度没有直接的关系,不能将数据粒度进行细分,即使细分的话帐户余额也很难分摊。这时,可以采用桥接表技术进行处理。在帐户维度表和用户维度表之间建立个帐户-用户桥接表。这个桥接表可以解决掉帐户维度和用户维度之间的多对多关系,也解决掉的帐户维度表的多值维度问题。
总之,多值维度是应该尽量避免的,它给数据处理带来了很大的麻烦。如果多值维度不能避免的话,应该建立桥接表来进行处理。
3.6.13 码表规范
码表(编码表):
- 是一种代码说明表格。
- 用来帮助用户明确无解释数据和字符 代码的含义。类似于数据字典
3.6.13.1码表注册
|
disease_code |
disease_name |
|
7863 |
糖尿病 |
|
6575 |
高血压 |
|
…… |
|
3.6.13.2码值统一
一个疾病编码只有一个对应的疾病名称
3.6.14 业务域
3.6.14.1主题域
主题域是对某个主题进行分析后确定的主题的边界。
如用户主题,日志主题
3.6.14.2数据域
数据域是指面向业务分析,将业务过程或者维度进行抽象的集合
如订单域,业务过程可能为:加入购物车->支付->发货->收货,整个业务过程的数据都属于订单域
3.7 名词概念
3.7.1 宽表
宽表从字面意义上讲就是字段比较多的表。通常是指业务主题相关的指标、维度、属性关联在一起的表。
3.7.2 粒度
粒度问题是设计数据仓库的一个最重要方面。粒度是指数据仓库的数据单位中保存数据的细化或综合程度的级别。细化程度越高,粒度级就越小;相反,细化程度越低,粒度级就越大。
笼统的说,粒度就是维度的组合
3.7.3 退化维度
将一些常用的维度属性直接写到事实表中的维度操作称为维度退化
3.7.4 维度层次
维度中的一些描述属性以层次方式或一对多的方式相互关联,可以被理解为包含连续主从关系的属性层次。层次的最底层代表维度中描述最低级别的详细信息,最高层代表最高级别的概要信息。维度常常有多个这样的嵌入式层次结构。
3.7.5 下钻
数据明细,粗粒度到细粒度的过程,会细化某些维度
下钻是商业用户分析数据的最基本的方法。下钻仅需要在查询上增加一个维度属性,附加在SQL的GROUP BY语句中。属性可以来自任何与查询使用的事实表关联的维度。下钻不需要存在层次的定义或是下钻路径。
3.7.6 上卷
数据的汇总聚合,细粒度到粗粒度的过程,会无视某些维度
3.7.8 规范化
按照三范式形成设计是事实和纬度表的方式管理数据称为规范化
规范化常用于OLTP系统的设计
3.7.9反规范化
将维度的属性层次合并到单个维度中的操作称为反规范化
反规范化会产生包含全部信息的宽表,形成数据冗余;实现用维表的空间换取简明性和查询性能的效果,常用于OLAP系统的设计
3.8 总线矩阵
3.8.1 一致性维度
3.8.1.1共享维表
维表公用,所以基于这些 公共维度进行的交叉探查不会存在任何问题
3.8.1.2一致性上卷
其中一个维度的属性是另一个维度的维度属性的子集,且两个维度的公共维度属性结构和内容相同
3.8.1.3 交叉属性
两个维度具有部分相同的维度属性
3.8.2 一致性事实
3.8.3 总线架构
四 数据治理
4.1 为什么要数据治理
- 企业将获得更干净、质量更高的数据,为进一步的数据活动打好基础
- 标准化的数据资产管理方法、流程和策略,将有效提高数据运营效率
- 使数据更容易与业务建立紧密连系,推动数据资产的变现
- 提高数据安全性,保证合规性
总体来说,数据治理能够带来的好处就在于,更高效地帮助企业将数据价值转化成实际的业务价值。
4.2 onedata理论
4.2.1 背景
由于前期缺少规划,随着集团业务发展,暴露的问题越来越多,给数据治理工作带来了很大的挑战,在数据仓库建设过程中,主要发现了以下几个问题:
- 缺乏统一的标准,如:开发规范、指标口径等。
- 缺乏统一数据质量监控,如:字段数据不完整和不准确,数据发散等。
- 业务知识体系混乱,导致数据开发人员开发成本增加。
- 数据架构不合理,层级之间分工不明显,数据流向混乱。
- 缺失统一维度和指标管理。
4.2.2 统一规范
4.2.2.1 特点
4.2.2.2 模型规范
- 模型分层
- 模型数据流向
4.2.2.3 主题划分
- 面向业务:按照业务进行聚焦,降低对业务理解的难度,并能解耦复杂的业务。我们将实体关系模型进行变种处理为实体与业务过程模型。实体定义为业务过程的参与体;业务过程定义是由多个实体作用的结果,实体与业务过程都带有自己特有的属性。根据业务的聚合性,我们把业务进行拆分,形成了几个核心主题。
- 面向分析:按照分析聚焦,提升数据易用性,提高数据的共享与一致性。按照分析主体对象不同及分析特征,形成分析域主题在DWS 进行应用,例如用户分析域、订单分析域。
4.2.2.4 词根
4.2.2.5 命名规范
- 表命名
- 指标命名
4.2.3 统一输出
4.2.3.1 数据资产管理
- 统一指标管理,保证了指标定义、计算口径、数据来源的一致性。
- 统一维度管理,保证了维度定义、维度值的一致性。
- 统一维表管理,保证了维表及维表主键编码的唯一性。
- 统一数据出口,实现了维度和指标元数据信息的唯一出口,维值和指标数据的唯一出口。
4.2.4 成就
4.2.4.1 优化开发流程
4.2.4.2 形成了资产管理体系
基于数据平台形成的资产管理体系,如下图所示:
4.3 元数据管理
4.3.1 概述
元数据通常定义为”关于数据的数据”,元数据贯穿了数据仓库的整个生命周期,使用元数据驱动数据仓库的开发,使数据仓库自动化,可视化。元数据打通了源数据、数据仓库、数据应用,记录数据从产生到消费的全过程。
例如我们看一部电影,电影本身就是数据,那么元数据就是用来描述这部电影的数据。如下图所示:
4.3.2 元数据定义
将元数据按用途的不同分为两类:
- 技术元数据(Technical Metadata)
- 业务元数据(Business Metadata)
4.3.2.1技术元数据
技术元数据是存储关于数据仓库系统技术细节的数据,是用于开发和管理数据仓库使用的数据。常见的技术元数据有:
1.存储元数据:
如表、字段、分区等信息。记录了表的中英文名及表状态。分区信息、责任人信息、对应主题,文件大小、表类型,生命周期,权限信息
记录列的字段中英文名、字段类型、字段备注、是否是分区字段,保密级别及权限信息等信息。
2.运行元数据,
如大数据平台上所有作业运行等信息:类似于 Hive Job 日志,包括作业类型、实例名称、输入输出、 SQL 、运行参数、执行时间,执行引擎等。
3.数据开发平台中数据同步、计算任务、任务调度等信息
包括数据同步的输入输出表和字段,以及同步任务本身的节点信息:计算任务主要有输入输出、任务本身的节点信息 任务调度主要有任务的依赖类型、依赖关系等,以及不同类型调度任务的运行日志等。
4.数据质量和运维相关元数据,如任务监控、运维报警、数据质量、故障等信息,包括任务监控运行日志、告警配置及运行日志、故障信息等。
4.3.2.2 业务元数据
业务元数据从业务角度描述了数据仓库中的数据,它提供了介于使用者和实际系统之间的语义层,使得不懂计算机技术的业务人员也能够读懂”数据仓库中的数据。
常见的业务元数据有维度及属性(包括维度编码,字段类型,创建人,创建时间,状态等)、业务过程、指标(包含指标名称,指标编码,业务口径,指标类型,责任人,创建时间,状态,sql等),安全等级,计算逻辑等的规范化定义,用于更好地管理和使用数据。数据应用元数据,如数据报表、数据产品等的配置和运行元数据。
4.3.3 元数据管理
对于元数据管理,目前来说有三种方式可供选择。
4.3.3.1 Excel手工录入保存
对于规模比较小,并且业务不大的公司,可能会用这种方式,但是这种方式太古老,且容易出错
4.3.3.2自研系统
自研元数据管理系统或者在数据平台开发元数据管理模块
很多公司会自研元数据管理系统或者相关模块,直接读取hive元数据或者数据平台配置的任务及调度元数据进行展示,相比较Excel人工导入,会更智能一点,但是相对于Atlas,成本更高且效果不一定有Atlas好,很多时候也需要批量导入和手工录入
4.3.3.3Atlas元数据管理(常用)
Atlas 是一个可伸缩且功能丰富的元数据管理系统,深度对接了 Hadoop 大数据组件。
简单理解就是一个跟 Hadoop 关系紧密的,可以用来做各类数据的元数据管理的一个软件系统;
atlas本身从技术上来说,就是一个典型的JAVAWEB系统,其整体结构图如下所示:
核心组件
- Core
- Integration
- Metadata source
- Applications
核心特性
- 数据分类管理
- 集中审计
- 搜索与血缘管理
ATLAS的使用,包含两个方面:
注入元数据信息到atlas中(本质是:写入元数据到atlas中)
注入方式1:通过atlas为数据系统开发好的hook来注入
注入方式2:通过atlas自带的WEB-UI来人工填写元数据信息再注入
注入方式3:通过在自己的数据系统中调用atlas对外暴露的api,来灵活注入
使用atlas中的元数据信息来为我们服务(本质是:从atlas中读、改元数据)
方式1:通过atlas自带的WEB-UI前端系统来查看、修改元数据
方式2:通过调用atlas对外暴露的api,来开发自己的管理系统
4.3.4 元数据价值
元数据有重要的应用价值,是数据管理、数据内容、数据应用的基础,在数据管理方面为集团数据提供在计算、存储、成本、质量、安全、模型等治理领域上的数据支持。例如在计算上可以利用元数据查找超长运行节点,对这些节点进行专项治理,保障基线产出时间。在数据内容方面为集团数据进行数据域、数据主题、业务属性等的提取和分析提供数据素材。例如可以利用元数据构建知识图谱,给数据打标签,清楚地知道现在有哪些数据。在数据应用方面打通产品及应用链路,保障产品数据准确、及时产出。例如打通DP和应用数据,明确数据产等级,更有效地保障产品数据。
4.3.5 元数据应用
数据的真正价值在于数据驱动决策,通过数据指导运营。通过数据驱动的方法,我们能够判断趋势 ,从而展开有效行动,帮助自己发现问题,推动创新或解决方案的产生。这就是数据化运营。同样,对于元数据,可以用于指导数据相关人员进行日常工作,实现数据化“运营”。比如对于数据使用者,可以通过元数据让其快速找到所需要的数据;对于ETL 工程师,可以通过元数据指导其进行模型设计、任务优化和任务下线等各种日常ETL 工作;对于运维工程师,可以通过元数据指导其进行整个集群的存储、计算和系统优化等运维工作。
4.4 主数据管理
4.5 数据质量管理
4.5.1数据质量基本概念
数据质量管理(Data Quality Management),是指对数据从计划、获取、存储、共享、维护、应用、消亡生命周期的每个阶段里可能引发的各类数据质量问题,进行识别、度量、监控、预警等一系列管理活动,并通过改善和提高组织的管理水平使得数据质量获得进一步提高
数据质量管理不是一时的数据治理手段,而是循环的管理过程。其终极目标是通过可靠的数据,提升数据在使用中的价值,并最终为企业赢得经济效益
4.5.2 影响因素
数据问题的来源可能产生于从数据源头到数据存储介质的各个环节。在数据采集阶段,数据的真实性、准确性、完整性、时效性都会影响数据质量。除此之外,数据的加工、存储过程都有可能涉及对原始数据的修改,从而引发数据的质量问题。所以,技术、流程、管理等多方面的因素都有可能会影响到数据质量。
在企业中,随着企业业务的增长,数据也是一个增量积累的过程。随着数据类型、数据来源的不断丰富以及数据数量的快速增长,企业在数据管理工作和数据流程中面临越来越多的数据质量问题。而且数据质量的管理并没有被企业重视起来,其根本原因还是ROI并没有那么明显。数据质量管理相对来说成本比较高。因为它涉及到企业数据标准的制定、规范的落地、生命周期的管理等多个环节。从收益上来说,数据质量的效益和结果并不是十分明显,大部分企业不会把数据质量作为KPI。在企业的不同系统中,业务领域的关键指标不一致,数据无法共享导致出现数据孤岛,大量数据无法关联,并且有明显的数据冗余等问题,还有数据的维护需要投入大量的人员、时间、软硬件成本。所以数据的质量管理往往被会边缘化甚至趋向于无。在此附上数据的生命周期图,包括各环节的数据流转和数据处理。
4.5.3评估维度
l 完整性
数据完整性问题包含数据条目不完整,数据属性不完整等
l 一致性
多源数据的数据模型不一致,如命名不一致,数据编码不一致,含义不一致,生命周期不一致等
l 准确性
准确性也叫可靠性,不可靠的数据可能会导致严重的问题,会造成有缺陷的方法和糟糕的决策
l 唯一性
用于识别和度量重复数据,冗余数据,重复数据是导致业务无法协同,流程无法追溯的重要因素,也是数据治理需要解决的最基本的数据问题
l 关联性
数据关联性问题是指存在数据关联的数据关系缺失或错误,例如:函数关系、相关系数、主外键关系、索引关系等。存在数据关联性问题,会直接影响数据分析的结果,进而影响管理决策。
l 真实性
数据必须真实准确的反映客观的实体存在或真实的业务,真 实可靠的 原始统计数据是企业统计工作的灵魂,是一切管理工作的基础,是经 营 者进行正确经营决策必不可少的第一手 资料。
l 及时性
数据的及时性(In-time)是指能否在需要的时候获到数据,数据的及时性与企业的数据处理速度及效率有直接的关系,是影响业务处理和管理效率的关键指标。
l 逻辑检查
不同表字段之间可能会有逻辑关联,需要稽核
l 离群值检查
部分数据可能会偏离其他数据,比如同一个商品金额大家都是100元,而有一条数据是1W
l 自定义规则
由需求方自定义相关规则
l 波动稽核
与上周环比稽核波动情况
l 强弱规则
每个规则的权重应该是不一样的,需要配置优先级,这对后续的告警方式是有帮助的
我们最终的目的是希望做到页面可配置
单表通用配置
|
质控规则 |
规则定义 |
|
唯一性 |
数据不能重复 |
多表自定义规则配置(自定义业务规则)
|
规则名称 |
规则内容 |
责任人 |
订阅人 |
操作 |
4.5.4实施流程
4.5.4.1事前定义质量规则
- 梳理表,字段等信息
- 确定资产等级
- 制定检验规则
4.5.4.2事中监控数据质量
- 在数据抽取过程中,可以对数据进行数据量稽核及唯一性,非空性稽核
- ETL过程对脏数据进行清洗,保证数据质量
- 指标计算过程中,可以对指标进行波动值稽核,保证指标变化在合理范围内
- 抽取结束后进行数据量稽核
以上如果有异常都需要邮件短信报警,对应负责人根据优先级判断是不是需要及时处理
4.5.4.3事后分析和问题跟踪
- 每周定时跑一次程序,对全局数据进行质量稽核控制,如唯一性,非空性等
- 对于程序跑出来的数据:数据质量概览在数据质量管理系统查询
- 数据质量明细数据在数据质量管理系统查询
- 根据异常数据统计出来的各种数据质量报表也可以在数据质量管理系统查询,包括表覆盖率,历史趋势,综合分析,排名分析等(质量报告支持导出为word,pdf,excel)对异常进行评估、严重程度、影响范围、问题分类等
- 可以订阅自己比较关心的主题,表或者规则,邮件只会发送订阅内容
- 对于打分比较低的表或者业务,可以反推业务方进行整改
4.5.4.4重大问题告警及整改
1. 警告邮件短信通知
2. 数据整改问题跟踪处理,故障review,规定时间内处理完成
4.5.5 报表展示(部分)
4.5.6 总结
数据质量管理贯穿数据生命周期的全过程,覆盖质量评估、数据监控、数据探查、数据清洗、数据诊断等方面。数据源在不断增多,数据量在不断加大,新需求推动的新技术也不断诞生,这些都对大数据下的数据质量管理带来了困难和挑战。因此,数据质量管理要形成完善的体系,建立持续改进的流程和良性机制,持续监控各系统数据质量波动情况及数据质量规则分析,适时升级数据质量监控的手段和方法,确保持续掌握系统数据质量状况,最终达到数据质量的平稳状态,为业务系统提供良好的数据保障。
4.6 数据安全
4.6.1背景
江湖传言:数据玩的溜,牢饭吃的久?众看官是不是闻风丧胆?
每个数据开发者都应该非常深刻的明白数据安全意味着什么。简直就是一根红线,丝毫不能越过。
近几年,国家对个人隐私数据保护越来越强,企业在使用数据的时候也非常注重数据安全,那么,我们应该怎么做,才能保护好自己,保护好公司的数据资产呢?
4.6.2 数据脱敏
数据脱敏是保证数据安全的最基本的手段,脱敏方法有很多,最常用的就是使用可逆加密算法,对数仓每一个敏感字段都需要加密。
4.6.3 数据权限控制
需要开发一套完善的数据权限控制体系,最好是能做到字段级别,有些表无关人员是不需要查询的,所以不需要任何权限,有些表部分人需要查询,除数据工程师外,其他人均需要通过OA流程进行权限审批,需要查看哪些表的哪些字段,为什么需要这个权限等信息都需要审批存档。
4.6.4程序检查
有些字段明显是敏感数据,比如身份证号,手机号等信息,但是业务库并没有加密,而且从字段名来看,也很难看出是敏感信息,所以抽取到数据仓库后需要使用程序去统一检测是否有敏感数据,然后根据检测结果让对应负责人去确认是否真的是敏感字段,是否需要加密等。
4.6.5流程化操作
流程化主要是体现在公司内部取数或者外部项目数据同步,取数的时候如果数据量很大或者包含了敏感信息,是需要提OA 审批流程的,让大家知道谁要取这些数据,取这些数据的意义在哪,出了问题可以回溯,快速定位到责任人。开发外部项目的时候,不同公司之间的数据同步,是需要由甲方出具同意书的,否则的话风险太大。
4.6.6敏感SQL实时审查及操作日志分析
及时发现敏感sql的执行并询问责任人,事后分析操作日志,查出有问题的操作。
4.6.7部门重视数据安全
把数据安全当做一项KPI去考核,让大家积极的参与到数据安全管理当中去。
4.6.8对自己负责
不要为了一时的利益,泄露公司数据资产,轻则行业名声败坏,重则要负法律责任,一定要三思而后行!
4.7 数据血缘
目前来说我所了解的基本都是需要手工维护的,有些公司维护在excel中,有些公司维护在web系统中
4.7.1 表血缘
4.7.2 字段血缘
4.7.3 任务血缘
五 指标体系建设
5.1拆解业务模块
5.1.1 拆分准备
- 产品形态
- 业务逻辑
- 业务流程图
5.1.2 拆分方法
- 用户行为法
- 业务拆分法
- 指标推进法
5.2定义核心业务指标
5.2.1 定义核心指标标准
- 反映用户体验和产品核心价值
- 反映用户的活跃程度
- 能够反映公司发展的状态
- 容易被团队理解和交流
- 具有先导性
- 具有可操作性
5.2.2 参考产品的生命周期
- 引入期:核心指标是用户留存
- 成长期:核心是用户转化情况
- 成熟期:核心指标是营收
- 衰退期
5.3梳理常见指标
5.3.1流量类指标
- 独立访客数
- 页面访客数
- 日活
- 周活
- 月活
- 跳出率
5.3.2订单指标
- 订单量
- 成交金额
- 退单率
5.3.3营收指标
- 销售金额
- 客单价
5.3.4考核指标
- 首回时间
- 首回时长
- 回复平均时长
- 好评率
5.3.5整体指标
- 总销售额
- 净利润
5.4 搭建指标体系
六 调度
6.1 责任人
6.2 输出表名
6.3 调度周期
6.4 加工方式
6.5 任务名称
6.6 优先级
6.7 依赖属性
6.8 版型信息
七 值班安排
7.1 排班信息
7.2 值班周期
7.3 任务延迟处理方式
7.4 任务报错处理方式
7.5 告警机制
7.6 责任划分
7.7 起夜率考核
7.8 重要任务最晚产出时间列表
八 技术栈
8.1 总览
8.2 日志采集
- Logstash
- flume
- logagent
8.3业务数据抽取
- Sqoop
- Datax
- Canal
- flink
8.4离线数据处理
- Sparksql
- hivesql
- mapreduce
8.5 实时数据处理
- Sparkstreaming
- flink
8.6调度系统
- Airflow
- azkaban
- oozie
8.7资源管理
- yarn
8.8消息中间件
- Kafka
8.9编程语言
- Java
- python
- scala
8.10数据存储
- Hdfs
- hbase
- elasticsearch
- redis
- mysql
8.11 OLAP
- Druid
- Kylin
8.12报表展示
- Kibana
- PowerBI
- tableau
九 实时数仓
Kafka+flink+clickhouse
敬请期待
word文档目录长图(此版本出的比较匆忙,是初版,之后会完善):
添加好友,备注【交流】
可私聊交流,也可进资源丰富学习群
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/122979.html






































































































