最近在项目中使用了开源OLAP引擎——Mondrian实现一个多维分析系统,在项目后期系统优化阶段使用了Mondrian中的聚合表机制。这里结合Mondrian官方资料和个人使用经验,对Mondrian中聚合表的概念、应用场景、如何使用、注意事项等内容做一个总结。
1. OLAP相关概念
Mondrian是一个基于Java语言的开源OLAP引擎,它通过MDX语句执行查询,从关系型数据库RDBMS中读取数据,以多维度的形式展示查询结果。
Mondrian通过Schema来定义一个多维数据库,它是一个逻辑概念上的模型,其中包含Cube(立方体)、Dimension(维度)、Hierarchy(层次)、Level(级别)、Measure(度量),这些被映射到数据库物理模型。Mondrian中Schema是以XML文件的形式定义的。
Cube(立方体)是一系列Dimension和Measure的集合区域,它们共用一个事实表。
Dimension(维度)是一个Hierarchy的集合,维度一般有其相对应的维度表,它由Hierarchy(层次)组成,而Hierarchy(层次)又是由组成Level(级别)的。
Hierarchy(层次)是指定维度的层级关系的,如果没有指定,默认Hierarchy里面装的是来自立方体中的真实表。
Level(级别)是Hierarchy的组成部分,使用它可以构成一个结构树,Level的先后顺序决定了Level在结构树上的位置,最顶层的 Level 位于树的第一级,依次类推。
Measure(度量)是我们要进行度量计算的数值,支持的操作有sum、count、avg、distinct-count、max、min等。
概括总结一下:在多维分析中,关注的内容通常被称为度量 (Measure) ,而把限制条件称为维度 (Dimension) 。多维分析就是对同时满足多种限制条件的所有度量值做汇总统计。包含度量值的表被称为事实表 (Fact Table) ,描述维度具体信息的表被称为维表 (Dimension Table) ,同时有一点需要注意:并不是所有的维度都要有维表,对于取值简单的维度,可以直接使用事实表中的一列作为维度展示。
下面是Mondrian中一个简单的Schema文件:
View Code
< Schema > < Cube name ="Sales" > < Table name ="sales_fact_1997" /> < Dimension name ="Gender" foreignKey ="customer_id" > < Hierarchy hasAll ="true" allMemberName ="All Genders" primaryKey ="customer_id" > < Table name ="customer" /> < Level name ="Gender" column ="gender" uniqueMembers ="true" /> Hierarchy > Dimension > < Dimension name ="Time" foreignKey ="time_id" > < Hierarchy hasAll ="false" primaryKey ="time_id" > < Table name ="time_by_day" /> < Level name ="Year" column ="the_year" type ="Numeric" uniqueMembers ="true" /> < Level name ="Quarter" column ="quarter" uniqueMembers ="false" /> < Level name ="Month" column ="month_of_year" type ="Numeric" uniqueMembers ="false" /> Hierarchy > Dimension > < Measure name ="Unit Sales" column ="unit_sales" aggregator ="sum" formatString ="#,###" /> < Measure name ="Store Sales" column ="store_sales" aggregator ="sum" formatString ="#,###.##" /> < Measure name ="Store Cost" column ="store_cost" aggregator ="sum" formatString ="#,###.00" /> < CalculatedMember name ="Profit" dimension ="Measures" formula ="[Measures].[Store Sales] - [Measures].[Store Cost]" > < CalculatedMemberProperty name ="FORMAT_STRING" value ="$#,##0.00" /> CalculatedMember > Cube > Schema >
其中包含一个名为“Sales”的Cube,立方体中有两个维度:“Gender”和“Time”,两个度量值:“Unit Sales”和“Store Sales”。有关Mondrian的Schema文件的具体编写规则,可以参考官方文档:如何编写Schema。
2. 什么是聚合表
下图描述了一个数据库的结构。该数据库中共有五张表,分别是Sales表,Customer表,Time表,Product表和Mfr表。这个数据库的作用是存储每一笔交易:包括这笔交易发生在什么时间,交易的产品类型,进行交易的客户信息,交易方式,交易了多少件产品以及成交金额是多少。
星型模型中有一张事实表(Sales),两个度量列(units和dollars),四个维度表(Product, Mfr, Customer, Time)。在这个星型模型的最顶层,我们创建了以下多维模型:
[Sales]立方体包含[Unit sales]和[Dollar sales]两个度量值;
[Product]维度包含[All Products],[Manufacturer],[Brand],[Prodid]四个级别;
[Time]维度包含[All Time],[Year],[Quarter],[Month],[Day]五个级别;
[Customer]维度包含[All Customers],[State],[City],[Custid]四个级别;
[Payment Method]维度包含[All Payment Methods],[Payment Method]两个级别。
其中,大部分维度都有一个对应的维度表,除了两个地方:[Product]
维度是一个雪花维度,它会把
Product
和
Mfr
两张表展开;
[Payment Method]
维度是一个退化的维度,直接使用事实表中的
payment
列作为维度属性,因此不需要一个单独的维表。
假设现在我们要对交易做一些统计,例如,某一件特定产品在某一个时间段内以某种特定方式总共卖出多少件或多少钱,这时成交产品数和成交金额是我们最终关注的内容,其他的因素例如时间、产品、方式等都只是对我们最终关注内容进行统计的限制条件。
在上面的例子中,限制条件有时间、产品类型、用户类型和交易方式,有时我们并不需要同时使用所有的限制条件,例如,当我们只想知道指定产品的成交总金额时,那么除了产品类型之外其他三个限制条件都是多余的,而在查询时,需要在整个事实表中执行查询,找出产品类型为指定类型的所有产品然后再做统计,为了提高查询效率,我们可以新建一张表,这张表按照产品类型把事实表中的行合并到一起,合并的方式是抛弃其他维,把度量值按特定的方式(max,min,sum,count或avg)整合到一起。这种表被叫做聚合表 (Aggregate Table) 。
3. 聚合表的应用场景
事实表中的行构成了一个集合,每一维(或若干维)按照其取值的不同可以将事实表这个全集划分成若干个不相交的子集。聚合表所做的工作实际上就是把划分出的子集归为数据库表中的一行,这样做一方面可以减少数据库表的行数,另一方面也省去了查询时所需要做的一些统计工作,从而提高查询时的效率。
4. 如何在Mondrian中使用聚合表
在Mondrian应用中加入聚合表需要进行以下工作:
4.1. 定义聚合表
在Mondrian中,一张事实表可以有多张聚合表,但每个聚合表只对应一个事实表。目前Mondrian中支持两种聚合表:lost dimension和collapsed dimension。
1. lost dimension
lost dimension表示有维度完全消失的聚合表,举个例子,例如一个包含有时间、地域、产品三个维度,以及度量值sales的立方体,那么如果有一个聚合表不包含维度,那么就被称为lost dimension,这里度量sales会被聚合为所有地域下的值。一个聚合表可以把所有维度都消失掉,这个聚合表将只包含一行记录,代表所有时间、地域、产品维度下的sales总和。
fact table time_id product_id location_id measure lost (location_id) dimension table time_id product_id measure (aggregated over location) fact_count fully lost dimension table measure (aggregated over everything) fact_count
其中,聚合表中的fact_count列是一个附加列,表示事实表中有多少行记录被聚合到了聚合表中的这一行。
2. collapsed dimension
collapsed dimension表示有维度被退化的聚合表,所谓退化是指某个维度在聚合表中只包含了这个维度的若干级别(Level)。举个例子,时间维度下包含了day,month,quarter,year级别,而在聚合表中退化成了只包含month这个级别,那么聚合表中不会包含time_id列,而是包含month,quarter和year列。当MDX查询语句可以用到这个聚合表时,就不再查询时间维度的维表,而是直接通过聚合表查询所有有关时间的信息(month,quarter和year)。
time dimension table time_idday month quarteryear fact table time_id measure collapsed dimension table month quarteryear measure (aggregated to month level ) fact_count
4.2. 数据库中创建聚合表
在创建聚合表时,只对聚合表的表名称和列名称有所要求。聚合表的名称以它所对应的事实表的名称为后缀。聚合表的名称由三部分组成:
其中,第二部分原则上的要求是至少包含一个字符,可以以字母、数字或下划线,但通常会用第二部分说明聚合表的类型并且对聚合表进行编号。例如,事实表的名称是customer,那么下面这些都是合法的、对应于该事实表的聚合表名:
agg_01_sales
agg_02_sales
agg_l_01_sales
agg_l_02_sales
agg_c_01_sales
agg_lc_01_sales
通常,我们会使用类似后面四个这样的聚合表名,在聚合表名的第二部分,首先是l或c或lc(分别表示包含lost dimension,collapsed dimension或者同时包含两者的聚合表),然后是一个下划线,接着后面是聚合表的数字编号。
在给聚合表的列命名时,只要使聚合表中的列名称和类型与事实表或维表中对应列的名称一致即可。除此之外,在聚合表中必须新加一列,这一列的名称会由Schema中的标签所指定(下面会有详细说明),这一列的作用是统计聚合表中一行聚合了事实表中的行的数目。
另外,聚合表还可以增加一些度量值,增加的度量值所在列的名字由度量方法(sum, max, min, avg)加下滑线再加对应的事实表中的列名字组成。例如,在上图中的事实表有一个名为units的度量值,在聚合表中如果我们想对这个值求和,那么聚合表中保存对units求和结果的列的名字就可以被命名为sum_units。更具体的内容可以参考:聚合表与事实表的表名和列名匹配规则。
聚集表必须被构建,一般来说,聚合表示非实时的,它们需要被重新构建,例如每天凌晨重新构建一次,供第二天分析。
下面是个简单的例子,这里有一张sales_fact_1997事实表:
sales_fact_1997 product_id time_id customer_id promotion_id store_id store_sales store_cost unit_sales
首先我们构建一个时间维度消失了的lost dimension聚合表:
View Code
CREATE TABLE agg_l_05_sales_fact_1997 ( product_id INTEGER NOT NULL , customer_id INTEGER NOT NULL , promotion_id INTEGER NOT NULL , store_id INTEGER NOT NULL , store_sales DECIMAL (10 ,4 ) NOT NULL , store_cost DECIMAL (10 ,4 ) NOT NULL , unit_sales DECIMAL (10 ,4 ) NOT NULL , fact_count INTEGER NOT NULL );CREATE INDEX i_sls_97_cust_id ON agg_l_05_sales_fact_1997 (customer_id);CREATE INDEX i_sls_97_prod_id ON agg_l_05_sales_fact_1997 (product_id);CREATE INDEX i_sls_97_promo_id ON agg_l_05_sales_fact_1997 (promotion_id);CREATE INDEX i_sls_97_store_id ON agg_l_05_sales_fact_1997 (store_id);INSERT INTO agg_l_05_sales_fact_1997 ( product_id, customer_id, promotion_id, store_id, store_sales, store_cost, unit_sales, fact_count)SELECT product_id, customer_id, promotion_id, store_id,SUM (store_sales) AS store_sales,SUM (store_cost) AS store_cost,SUM (unit_sales) AS unit_sales,COUNT (* ) AS fact_countFROM sales_fact_1997 GROUP BY product_id, customer_id, promotion_id, store_id;
接下来构建一个collapsed dimension聚合表,其中时间维度退化为月级别:
View Code
CREATE TABLE agg_c_14_sales_fact_1997 ( product_id INTEGER NOT NULL , customer_id INTEGER NOT NULL , promotion_id INTEGER NOT NULL , store_id INTEGER NOT NULL , month_of_year SMALLINT (6 ) NOT NULL , quarter VARCHAR (30 ) NOT NULL , the_year SMALLINT (6 ) NOT NULL , store_sales DECIMAL (10 ,4 ) NOT NULL , store_cost DECIMAL (10 ,4 ) NOT NULL , unit_sales DECIMAL (10 ,4 ) NOT NULL , fact_count INTEGER NOT NULL );CREATE INDEX i_sls_97_cust_id ON agg_c_14_sales_fact_1997 (customer_id);CREATE INDEX i_sls_97_prod_id ON agg_c_14_sales_fact_1997 (product_id);CREATE INDEX i_sls_97_promo_id ON agg_c_14_sales_fact_1997 (promotion_id);CREATE INDEX i_sls_97_store_id ON agg_c_14_sales_fact_1997 (store_id);INSERT INTO agg_c_14_sales_fact_1997 ( product_id, customer_id, promotion_id, store_id, month_of_year, quarter, the_year, store_sales, store_cost, unit_sales, fact_count)SELECT BASE.product_id, BASE.customer_id, BASE.promotion_id, BASE.store_id, DIM.month_of_year, DIM.quarter, DIM.the_year,SUM (BASE.store_sales) AS store_sales,SUM (BASE.store_cost) AS store_cost,SUM (BASE.unit_sales) AS unit_sales,COUNT (* ) AS fact_countFROM sales_fact_1997 AS BASE, time_by_day AS DIMWHERE BASE.time_id = DIM.time_idGROUP BY BASE.product_id, BASE.customer_id, BASE.promotion_id, BASE.store_id, DIM.month_of_year, DIM.quarter, DIM.the_year;
4.3. 在Schema中声明聚合表
在Schema中声明聚合表时,需要把声明内容放到
标签中。声明聚合表时常用的标签及其含义如下:
和一个聚合表的声明相关的内容都放在这个标签内,并且通过这个标签的name属性,可以把这部分声明与数据库中的一个聚合表对应起来。例如,数据库中有一个聚合表的名字为:agg_l_01_sales,那么在Schema中可以这样声明这个聚合表:
< AggName name ="agg_l_01_sales" > ... AggName >
其中...表示声明的其他部分,这部分由下面的一个或若干个标签组成,下面的标签都在中使用,并且它们是平级的,不会相互出现在其他标签内。
通过这个标签的column属性可以指定一个聚合表中用来统计每一行聚合了事实表中多少行的列的名字,例如:
< AggFactCount name ="fact_count" />
表示在这个聚合表中用一个名为fact_count的列来统计聚合表的一行聚合了事实表的多少行。
这个标签用来把事实表中的一个外键同聚合表中含义相同的标签匹配起来,例如:
< AggForeignKey factColumn ="product_id" aggColumn ="product_id" />
表示在事实表中有一个外键product_id,而在该事实表所对应的聚合表中与它功能相同(是同一张维表的主键)的外键名字是 product_id。其中factColumn指定事实表中外键的名字,aggColumn指定聚合表中相匹配的外键的名字。
如果聚合表中的维不是一个外键,那么需要用这个标签来声明聚合表中的这一维。这里举两个例子来说明它的用法:
当聚合表中的这一维也是事实表中的一维时(例如上图中payment那一列),可以这样写:
< AggLevel name ="[Payment Method].[Payment Method]" column ="payment" />
其中name属性由两部分组成,首先是事实表的这一维在Schema中声明时的维的名称(由标签的name属性所指定),然后加上一个.最后再加上这一维的层次结构(Hierarchy)的名字(由标签内的标签的name属性所指定)即可。而column属性则是聚合表中这一列的名字,此处标签只指定聚合表中列的名字而 没有指定事实表中相对应列的名字是因为Mondrian会根据列名字匹配规则自动在事实表中查找相匹配的列。
当聚合表中的这一维是维表中的一维时(例如上图中month那一列),与上一种情况写法完全相同即可,并不因为聚合表中这一列对应的是维表中的列而有所不同:
< AggLevel name ="[Time].[Month]" column ="month" />
用来声明聚合表中度量值和事实表中度量值的匹配关系,例如:
< AggMeasure name ="[Measures].[Dollar Sales]" column ="sum_dollars" />
其中的name属性的写法是[Measures].后面跟上度量值在Schema中声明时所使用的名字,它由标签中的name属性所指定。而column的值是聚合表中一列的名字。
5. 在Mondrian中使用聚合表的注意事项
5.1. 在什么情况下Mondrian会使用聚合表
当需要查询的度量值的维是一张聚合表所包含的维的子集时,这张聚合表就可能会被使用。这里说可能被使用是因为其他聚合表可能也满足使用条件,这时 Mondrian会首先选择满足条件且维数与行数之乘积最少的聚合表,如果有多张满足条件的聚合表维数相同,Mondrian会选择一个行数最少的聚合 表。如果没有聚合表满足条件,Mondrian会从事实表中进行查询。详细内容参考Mondrian配置属性:mondrian.rolap.aggregates.ChooseByVolume
5.2. Mondrian的聚合表与事实表数据同步的问题
一般来说,事实表中的数据是静态不变的,目前,Mondrian并不提供聚合表和事实表同步的机制,聚合表的数据需要自己批量导入后计算生成。
也就是说,当事实表被修改时,Mondrian不会对聚合表做相应的更改,Mondrian不提供根据事实表向聚合表中导入数据和同步数据的功能。因此,如果自己的应用场景中事实表中数据是动态变化的,就需要自己考虑如何做到事实表和聚合表的同步更新。
6. Mondrian中聚合表的例子
6.1. 第一个例子
建立一个聚合表Agg_1,结构如下图所示:
其中,
Time维度被退化,只提取year、quarter列,忽略month和day列;
Product相关的两个维度也在聚合表中被退化;
Customer维度消失掉了;
对于事实表中的每个度量列(units
,dollars
),
聚合表中可以有一个或多个聚合列(sum units
,min units
,max units
,sum dollars
);
同时聚合表中还有个度量列row count,表示出现的次数。
聚合表Agg_1对应的Schema声明如下:
View Code
< Cube name ="Sales" > < Table name ="sales" > < AggName name ="agg_1" > < AggFactCount column ="row count" /> < AggMeasure name ="[Measures].[Unit Sales]" column ="sum units" /> < AggMeasure name ="[Measures].[Min Units]" column ="min units" /> < AggMeasure name ="[Measures].[Max Units]" column ="max units" /> < AggMeasure name ="[Measures].[Dollar Sales]" column ="sum dollars" /> < AggLevel name ="[Time].[Year]" column ="year" /> < AggLevel name ="[Time].[Quarter]" column ="quarter" /> < AggLevel name ="[Product].[Mfrid]" column ="mfrid" /> < AggLevel name ="[Product].[Brand]" column ="brand" /> < AggLevel name ="[Product].[Prodid]" column ="prodid" /> AggName > Table >
6.2. 第二个例子
建立一个聚合表Agg_2,结构如下图所示:
其中,
Time维度被退化为year、quarter和month级别;
Customer维度被退化为state级别;
Payment Method被退化为Payment Method级别;
Product维度保持了原始的雪花模型关系。
聚合表Agg_2对应的Schema声明如下:
View Code
< Cube name ="Sales" > < Table name ="sales" > < AggName name ="agg_2_sales" > < AggFactCount column ="row count" /> < AggForeignKey factColumn ="prodid" aggColumn ="prodid" /> < AggMeasure name ="[Measures].[Unit Sales]" column ="sum units" /> < AggMeasure name ="[Measures].[Min Units]" column ="min units" /> < AggMeasure name ="[Measures].[Max Units]" column ="max units" /> < AggMeasure name ="[Measures].[Dollar Sales]" column ="sum dollars" /> < AggLevel name ="[Time].[Year]" column ="year" /> < AggLevel name ="[Time].[Quarter]" column ="quarter" /> < AggLevel name ="[Time].[Month]" column ="month" /> < AggLevel name ="[Payment Method].[Payment Method]" column ="payment" /> < AggLevel name ="[Customer].[State]" column ="state" /> AggName > Table > < Dimension name ="Product" > < Hierarchy hasAll ="true" primaryKey ="prodid" primaryKeyTable ="Product" > < Join leftKey ="mfrid" rightKey ="mfrid" > < Table name ="Product" /> < Table name ="Mfr" /> Join > < Level name ="Manufacturer" table ="Mfr" column ="mfrid" /> < Level name ="Brand" table ="Product" column ="brand" /> < Level name ="Name" table ="Product" column ="prodid" /> Hierarchy > Dimension > < Dimension name ="Day" foreignKey ="day" > < Hierarchy hasAll ="true" primaryKey ="day" > < Table name ="Time" /> < Level name ="Year" column ="year" type ="Numeric" uniqueMembers ="true" /> < Level name ="Quarter" column ="quarter" uniqueMembers ="false" /> < Level name ="Month" column ="month" type ="Numeric" uniqueMembers ="false" /> Hierarchy > Dimension > < Dimension name ="Customer" foreignKey ="custid" > < Hierarchy hasAll ="true" primaryKey ="custid" > < Table name ="Customer" /> < Level name ="City" column ="city" uniqueMembers ="ture" /> < Level name ="State" column ="state" uniqueMembers ="true" /> Hierarchy > Dimension > < Dimension name ="Payment method" > < Hierarchy hasAll ="true" > < Level name ="Payment method" column ="payment" uniqueMembers ="ture" /> Hierarchy > Dimension > < AggMeasure name ="Unit Sales" aggregator ="sum" /> < AggMeasure name ="Min Units" aggregator ="min" /> < AggMeasure name ="Max Units" aggregator ="max" /> < AggMeasure name ="Dollar Sales" aggregator ="sum" /> Cube >
其中,标签用于声明prodid列连接到维表的prodid列,其他的所有列仍然从Product和Mfr维表中获取。
7. 总结
1. 使用Mondrian做大数据量(如>100W行)的OLAP分析时,考虑是否可以使用聚合表进行优化。
2. 然而Mondrian的优化方式又不限于聚合表这一种,是否要进行聚合表优化,要根据实际情况来决定。
3. Mondrian目前并不提供对聚合表的数据同步机制,如果要做实时OLAP,需要自己实现聚合表和事实表中的数据同步。
8. 参考资料
1. Mondiran在线文档
2. Mondiran Technical Guide
你可能感兴趣的:(Mondrian中聚合表的应用)
guava loadingCache代码示例
IM 胡鹏飞
Java 工具类介绍
publicclassTest2{publicstaticvoidmain(String[]args)throwsException{LoadingCachecache=CacheBuilder.newBuilder()//设置并发级别为8,并发级别是指可以同时写缓存的线程数.concurrencyLevel(8)//设置缓存容器的初始容量为10.initialCapacity(10)//设置缓存
系统学习Python——并发模型和异步编程:进程、线程和GIL
分类目录:《系统学习Python》总目录在文章《并发模型和异步编程:基础知识》我们简单介绍了Python中的进程、线程和协程。本文就着重介绍Python中的进程、线程和GIL的关系。Python解释器的每个实例都是一个进程。使用multiprocessing或concurrent.futures库可以启动额外的Python进程。Python的subprocess库用于启动运行外部程序(不管使用何种
C++11堆操作深度解析:std::is_heap与std::is_heap_until原理解析与实践
文章目录堆结构基础与函数接口堆的核心性质函数签名与核心接口std::is_heapstd::is_heap_until实现原理深度剖析std::is_heap的验证逻辑std::is_heap_until的定位策略算法优化细节代码实践与案例分析基础用法演示自定义比较器实现最小堆检查边缘情况处理性能分析与实际应用时间复杂度对比典型应用场景与手动实现的对比注意事项与最佳实践迭代器要求比较器设计C++标
为什么会出现“与此站点的连接不安全”警告?
当浏览器弹出“与此站点的连接不安全”的红色警告时,不仅会让访客感到不安,还可能直接导致用户流失、品牌信誉受损,甚至引发数据泄露风险。作为网站运营者,如何快速解决这一问题?一、为什么会出现“与此站点的连接不安全”警告?浏览器提示“不安全连接”,本质上是检测到当前网站与用户之间的数据传输未经过加密保护。以下是触发警告的常见原因:1.未安装SSL证书SSL(SecureSocketsLayer)证书是网
什么是证书吊销列表?CRL 解释
WoTrusSSL
ssl https
数字证书是安全在线互动的支柱,用于验证身份和确保加密通信。但是,当这些证书被盗用或滥用时,必须立即撤销它们以维持信任。这就是证书撤销列表(CRL)的作用所在。CRL由证书颁发机构(CA)维护,对于识别和撤销已撤销的证书,防止其造成危害至关重要。在本指南中,我们将探讨什么是CRL、它们如何运作以及为什么它们对网络安全至关重要。什么是证书吊销列表(CRL)?证书吊销列表(CRL)是证书颁发机构(CA)
有必要获得WHQL测试认证吗,有什么好处?
什么是WHQL认证?WHQL是MicrosoftWindowsHardwareQualityLab的缩写,中文意思是Windows硬件设备质量实验室,主要是对Windows操作系统的兼容性测试,检验硬件产品和驱动程序在windows系统下的兼容性和稳定性。当某一硬件或软件通过WHQL测试时,制造商可以在其产品包装和广告上使用“DesignedforWindows”标志。该标志可以证明硬件或软件已经
Flask框架入门:快速搭建轻量级Python网页应用
「已注销」
python-AI python基础 网站网络 python flask 后端
转载:Flask框架入门:快速搭建轻量级Python网页应用1.Flask基础Flask是一个使用Python编写的轻量级Web应用框架。它的设计目标是让Web开发变得快速简单,同时保持应用的灵活性。Flask依赖于两个外部库:Werkzeug和Jinja2,Werkzeug作为WSGI工具包处理Web服务的底层细节,Jinja2作为模板引擎渲染模板。安装Flask非常简单,可以使用pip安装命令
驱动程序为什么要做 WHQL 认证?
GDCA SSL证书
网络协议 网络
驱动程序进行WHQL(WindowsHardwareQualityLabs)认证的核心价值在于解决兼容性、安全性和市场准入三大关键问题,具体必要性如下:️一、规避系统拦截,保障驱动可用性消除安装警告未认证的驱动在安装时会触发Windows的红色安全警告(如“无法验证发布者”),甚至被系统强制拦截。通过WHQL认证的驱动获得微软数字签名,用户可无阻安装。满足系统强制要求Windows1
求是网:“内卷式”竞争的突出表现和主要危害有哪些?
加百力
财经研究 科技知识 人工智能 大数据
"内卷式"竞争主要表现为:企业层面的低价竞争、同质化竞争和营销"逐底竞争";地方政府层面的违规优惠政策、盲目重复建设和设置市场壁垒。危害体现在三个层面:微观上导致"劣币驱逐良币",损害消费者利益;中观上破坏行业生态,挤压产业链利润空间;宏观上扭曲资源配置,抑制创新活力。什么是“内卷式”竞争?概括其一般特征,是指经济主体为了维持市场地位或争夺有限市场,不断投入大量精力和资源,却没有带来整体收益增长的
WHQL签名怎么申请
GDCA SSL证书
windows
WHQL(WindowsHardwareQualityLabs)签名是微软对硬件和驱动程序进行认证的一种方式,以确保它们与Windows操作系统的兼容性和稳定性。以下是申请WHQL签名的基本步骤,供您参考:1.准备阶段准备硬件设备和驱动程序:确保您的硬件设备已经准备好,并且对应的驱动程序已经经过充分的测试,能够在各种配置和环境下正常工作。获取EV代码签名证书:根据微软的要求,驱动程序进行WHQL认
JSON 与 AJAX
Auscy
json ajax 前端
一、JSON(JavaScriptObjectNotation)1.数据类型与语法细节支持的数据类型:基本类型:字符串(需用双引号)、数字、布尔值(true/false)、null。复杂类型:数组([])、对象({})。严格语法规范:键名必须用双引号包裹(如"name":"张三")。数组元素用逗号分隔,最后一个元素后不能有多余逗号。数字不能以0开头(如012会被解析为12),不支持八进制/十六进制
发票合并工具
小朋的软件园
前端 javascript java html 服务器
"发票合并工具"是一款专为高效整理票据设计的实用工具,支持将来自不同渠道的发票文件(如PDF文档、各类图片格式)快速整合为排版规范的PDF文件,尤其适用于财务报销场景下的批量票据处理需求。核心功能亮点多格式兼容:无缝导入PDF文件及常见图片格式(.png/.jpg/.jpeg/.bmp),适配多来源发票整合需求。智能布局配置:提供灵活的页面布局选项(每页2/3/4张发票),其中"2合1"模式针对报
Python Flask 框架入门:快速搭建 Web 应用的秘诀
Python编程之道
Python人工智能与大数据 Python编程之道 python flask 前端 ai
PythonFlask框架入门:快速搭建Web应用的秘诀关键词Flask、微框架、路由系统、Jinja2模板、请求处理、WSGI、Web开发摘要想快速用Python搭建一个灵活的Web应用?Flask作为“微框架”代表,凭借轻量、可扩展的特性,成为初学者和小型项目的首选。本文将从Flask的核心概念出发,结合生活化比喻、代码示例和实战案例,带你一步步掌握:如何用Flask搭建第一个Web应用?路由
C++ 11 Lambda表达式和min_element()与max_element()的使用_c++ lamda函数 min_element((1)
2401_84976182
程序员 c语言 c++ 学习
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上CC++开发知识点,真正体系化!由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新如果你需要这些资料,可以戳这里获取#include#include#includeusingnamespacestd;boolcmp(int
C++ 11 Lambda表达式和min_element()与max_element()的使用_c++ lamda函数 min_element(
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。需要这份系统化的资料的朋友,可以添加戳这里获取一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!intmain(){vectormyvec{3,
k8s:安装 Helm 私有仓库ChartMuseum、helm-push插件并上传、安装Zookeeper
云游
docker helm helm-push
ChartMuseum是Kubernetes生态中用于存储、管理和发布HelmCharts的开源系统,主要用于扩展Helm包管理器的功能核心功能集中存储:提供中央化仓库存储Charts,支持版本管理和权限控制。跨集群部署:支持多集群环境下共享Charts,简化部署流程。离线部署:适配无网络环境,可将Charts存储在本地或局域网内。HTTP接口:通过HTTP协议提供服务,用户
上位机知识篇---SD卡&U盘镜像
常用的镜像烧录软件balenaEtcherbalenaEtcher是一个开源的、跨平台的工具,用于将操作系统镜像文件(如ISO和IMG文件)烧录到SD卡和USB驱动器中。以下是其使用方法、使用场景和使用注意事项的介绍:使用方法下载安装:根据自己的操作系统,从官方网站下载对应的安装包。Windows系统下载.exe文件后双击安装;Linux系统若下载的是.deb文件,可在终端执行“sudodpkg-
【LeetCode 热题 100】24. 两两交换链表中的节点——(解法一)迭代+哨兵
xumistore
LeetCode leetcode 链表 算法 java
Problem:24.两两交换链表中的节点题目:给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。文章目录整体思路完整代码时空复杂度时间复杂度:O(N)空间复杂度:O(1)整体思路这段代码旨在解决一个经典的链表操作问题:两两交换链表中的节点(SwapNodesinPairs)。问题要求将链表中每两个相邻的节点进行交换
Guava LoadingCache
sqyaa.
java并发编程 Java知识 jvm 缓存 guava
LoadingCache是GoogleGuava库提供的一个高级缓存实现,它通过自动加载机制简化了缓存使用模式。核心特性自动加载机制当缓存未命中时,自动调用指定的CacheLoader加载数据线程安全:并发请求下,相同key只会加载一次灵活的过期策略支持基于写入时间(expireAfterWrite)和访问时间(expireAfterAccess)的过期可设置最大缓存大小,基于LRU策略淘汰丰富的
JavaScript 树形菜单总结
Auscy
microsoft
树形菜单是前端开发中常见的交互组件,用于展示具有层级关系的数据(如文件目录、分类列表、组织架构等)。以下从核心概念、实现方式、常见功能及优化方向等方面进行总结。一、核心概念层级结构:数据以父子嵌套形式存在,如{id:1,children:[{id:2}]}。节点:树形结构的基本单元,包含自身信息及子节点(若有)。展开/折叠:子节点的显示与隐藏切换,是树形菜单的核心交互。递归渲染:因数据层级不固定,
基于定制开发开源AI智能名片S2B2C商城小程序的社群游戏定制策略研究
说私域
人工智能 小程序 游戏
摘要:本文聚焦社群游戏定制领域,深入探讨以社群文化和用户偏好为导向的定制策略。通过分析互动游戏活动、社群文化塑造等关键要素,结合定制开发开源AI智能名片S2B2C商城小程序的技术特性,提出针对性游戏定制方案。研究旨在提升社群用户参与度与游戏体验,为社群游戏发展提供理论支持与实践指导。关键词:社群游戏定制;定制开发开源AI智能名片S2B2C商城小程序;社群文化;用户偏好一、引言在数字化社交蓬勃发展的
冒泡、选择、插入排序:三大基础排序算法深度解析(C语言实现)
xienda
算法 排序算法 数据结构
在算法学习道路上,排序算法是每位程序员必须掌握的基石。本文将深入解析冒泡排序、选择排序和插入排序这三种基础排序算法,通过C语言代码实现和对比分析,帮助读者彻底理解它们的差异与应用场景。算法原理与代码实现1.冒泡排序(BubbleSort)工作原理:通过重复比较相邻元素,将较大元素逐步"冒泡"到数组末尾。voidbubbleSort(intarr[],intn){ for(inti=0;iarr[
Leetcode 148. 排序链表
文章目录前引题目代码(首刷看题解)代码(8.9二刷部分看解析)代码(9.15三刷部分看解析)前引综合性比较强的一道题,要求时间复杂度必须O(logn)才能通过,最适合链表的排序算法就是归并。这里采用自顶向下的方法步骤:找到链表中点(双指针)对两个子链表排序(递归,直到只有一个结点,记得将子链表最后指向nullptr)归并(引入dummy结点)题目Leetcode148.排序链表代码(首刷看题解)c
全面触摸屏输入法设计与实现
长野君
本文还有配套的精品资源,点击获取简介:触摸屏输入法是针对触摸设备优化的文字输入方案,包括虚拟键盘、手写、语音识别和手势等多种输入方式。本方案通过提供主程序文件、用户手册、界面截图、示例图、说明文本和音效文件,旨在为用户提供一个完整的、多样的文字输入体验。开发者通过持续优化算法和用户界面,使用户在无物理键盘环境下也能高效准确地进行文字输入。1.触摸屏输入法概述简介在现代信息技术飞速发展的今天,触摸屏
LeetCode 148. 排序链表:归并排序的细节解析
进击的小白菜
2025 Top100 详解 leetcode 链表 算法
文章目录题目描述一、方法思路:归并排序的核心步骤二、关键实现细节:快慢指针分割链表1.快慢指针的初始化问题2.为什么选择`fast=head.next`?示例1:链表长度为偶数(`1->2->3->4`)三、完整代码实现四、复杂度分析五、总结题目描述LeetCode148题要求对链表进行排序,时间复杂度需为O(nlogn),且空间复杂度为O(logn)。由于链表的特殊结构(无法随机访问),归并排序
前端项目架构设计要领
1.架构设计的核心目标在设计前端项目架构时,核心目标是模块化、可维护、可扩展、可测试,以及开发效率的最大化。这些目标可以通过以下几个方面来实现:组件化:将UI功能封装为可复用的组件。模块化:将业务逻辑分解为独立的模块或服务。自动化构建与部署:实现自动化构建、测试和部署流程,减少人为操作的错误。代码规范化与检查:确保团队协作时,代码风格和质量一致。2.项目目录结构设计一个清晰合理的目录结构对大型项目
精通Canvas:15款时钟特效代码实现指南
烟幕缭绕
本文还有配套的精品资源,点击获取简介:HTML5的Canvas是一个用于绘制矢量图形的API,通过JavaScript实现动态效果。本项目集合了15种不同的时钟特效代码,帮助开发者通过学习绘制圆形、线条、时间更新、旋转、颜色样式设置及动画效果等概念,深化对Canvas的理解和应用。项目中的CSS文件负责时钟的样式设定,而JS文件则包含实现各种特效的逻辑,通过不同的函数或类处理时间更新和动画绘制,提
高效批量单词翻译工具的设计与应用
本文还有配套的精品资源,点击获取简介:在信息技术飞速发展的今天,批量单词翻译工具通过计算机的数据处理能力,大大提高了语言学习和文字处理的效率。用户通过简单输入单词列表到一个文本文件,并运行翻译程序,即可获得翻译结果并保存至指定文件。该工具集成了内置或外部翻译引擎,利用自然语言处理技术实现快速准确的翻译,并可能提供词性识别等附加功能。尽管机器翻译无法完全取代人工校对,但它为用户提供了一种高效的翻译解
嵌入式系统LCD显示模块编程实践
本文还有配套的精品资源,点击获取简介:本文档提供了一个具有800x480分辨率的3.5英寸液晶显示模块LW350AC9001的驱动程序代码,以及嵌入式系统中使用C/C++语言进行硬件编程的实践指南。该模块的2mm厚度使其适用于空间受限的便携式设备。内容包括驱动程序源代码、硬件控制接口使用方法,以及如何在嵌入式系统中进行图形处理、电源管理与性能优化。1.嵌入式系统原理1.1嵌入式系统概念嵌入式系统是
深入剖析OpenJDK 18 GA源码:Java平台最新发展
想法臃肿
本文还有配套的精品资源,点击获取简介:OpenJDK18GA作为Java开发的关键里程碑,提供了诸多新特性和改进。本文章深入探讨了OpenJDK18GA源码,揭示其内部机制,帮助开发者更好地理解和利用这个版本。文章还涵盖了PatternMatching、SealedClasses、Records、JEP395、JEP406和JEP407等特性,以及HotSpot虚拟机、编译器、垃圾收集器、内存模型
怎么样才能成为专业的程序员?
cocos2d-x小菜
编程 PHP
如何要想成为一名专业的程序员?仅仅会写代码是不够的。从团队合作去解决问题到版本控制,你还得具备其他关键技能的工具包。当我们询问相关的专业开发人员,那些必备的关键技能都是什么的时候,下面是我们了解到的情况。
关于如何学习代码,各种声音很多,然后很多人就被误导为成为专业开发人员懂得一门编程语言就够了?!呵呵,就像其他工作一样,光会一个技能那是远远不够的。如果你想要成为
java web开发 高并发处理
BreakingBad
java Web 并发 开发 处理 高
java处理高并发高负载类网站中数据库的设计方法(java教程,java处理大量数据,java高负载数据) 一:高并发高负载类网站关注点之数据库 没错,首先是数据库,这是大多数应用所面临的首个SPOF。尤其是Web2.0的应用,数据库的响应是首先要解决的。 一般来说MySQL是最常用的,可能最初是一个mysql主机,当数据增加到100万以上,那么,MySQL的效能急剧下降。常用的优化措施是M-S(
mysql批量更新
ekian
mysql
mysql更新优化:
一版的更新的话都是采用update set的方式,但是如果需要批量更新的话,只能for循环的执行更新。或者采用executeBatch的方式,执行更新。无论哪种方式,性能都不见得多好。
三千多条的更新,需要3分多钟。
查询了批量更新的优化,有说replace into的方式,即:
replace into tableName(id,status) values
微软BI(3)
18289753290
微软BI SSIS
1)
Q:该列违反了完整性约束错误;已获得 OLE DB 记录。源:“Microsoft SQL Server Native Client 11.0” Hresult: 0x80004005 说明:“不能将值 NULL 插入列 'FZCHID',表 'JRB_EnterpriseCredit.dbo.QYFZCH';列不允许有 Null 值。INSERT 失败。”。
A:一般这类问题的存在是
Java中的List
g21121
java
List是一个有序的 collection(也称为序列)。此接口的用户可以对列表中每个元素的插入位置进行精确地控制。用户可以根据元素的整数索引(在列表中的位置)访问元素,并搜索列表中的元素。
与 set 不同,列表通常允许重复
读书笔记
永夜-极光
读书笔记
1. K是一家加工厂,需要采购原材料,有A,B,C,D 4家供应商,其中A给出的价格最低,性价比最高,那么假如你是这家企业的采购经理,你会如何决策?
传统决策: A:100%订单 B,C,D:0%
&nbs
centos 安装 Codeblocks
随便小屋
codeblocks
1.安装gcc,需要c和c++两部分,默认安装下,CentOS不安装编译器的,在终端输入以下命令即可yum install gccyum install gcc-c++
2.安装gtk2-devel,因为默认已经安装了正式产品需要的支持库,但是没有安装开发所需要的文档.yum install gtk2*
3. 安装wxGTK
yum search w
23种设计模式的形象比喻
aijuans
设计模式
1、ABSTRACT FACTORY—追MM少不了请吃饭了,麦当劳的鸡翅和肯德基的鸡翅都是MM爱吃的东西,虽然口味有所不同,但不管你带MM去麦当劳或肯德基,只管向服务员说“来四个鸡翅”就行了。麦当劳和肯德基就是生产鸡翅的Factory 工厂模式:客户类和工厂类分开。消费者任何时候需要某种产品,只需向工厂请求即可。消费者无须修改就可以接纳新产品。缺点是当产品修改时,工厂类也要做相应的修改。如:
开发管理 CheckLists
aoyouzi
开发管理 CheckLists
开发管理 CheckLists(23) -使项目组度过完整的生命周期
开发管理 CheckLists(22) -组织项目资源
开发管理 CheckLists(21) -控制项目的范围开发管理 CheckLists(20) -项目利益相关者责任开发管理 CheckLists(19) -选择合适的团队成员开发管理 CheckLists(18) -敏捷开发 Scrum Master 工作开发管理 C
js实现切换
百合不是茶
JavaScript 栏目切换
js主要功能之一就是实现页面的特效,窗体的切换可以减少页面的大小,被门户网站大量应用思路:
1,先将要显示的设置为display:bisible 否则设为none
2,设置栏目的id ,js获取栏目的id,如果id为Null就设置为显示
3,判断js获取的id名字;再设置是否显示
代码实现:
html代码:
<di
周鸿祎在360新员工入职培训上的讲话
bijian1013
感悟 项目管理 人生 职场
这篇文章也是最近偶尔看到的,考虑到原博客发布者可能将其删除等原因,也更方便个人查找,特将原文拷贝再发布的。“学东西是为自己的,不要整天以混的姿态来跟公司博弈,就算是混,我觉得你要是能在混的时间里,收获一些别的有利于人生发展的东西,也是不错的,看你怎么把握了”,看了之后,对这句话记忆犹新。 &
前端Web开发的页面效果
Bill_chen
html Web Microsoft
1.IE6下png图片的透明显示:
<img src="图片地址" border="0" style="Filter.Alpha(Opacity)=数值(100),style=数值(3)"/>
或在<head></head>间加一段JS代码让透明png图片正常显示。
2.<li>标
【JVM五】老年代垃圾回收:并发标记清理GC(CMS GC)
bit1129
垃圾回收
CMS概述
并发标记清理垃圾回收(Concurrent Mark and Sweep GC)算法的主要目标是在GC过程中,减少暂停用户线程的次数以及在不得不暂停用户线程的请夸功能,尽可能短的暂停用户线程的时间。这对于交互式应用,比如web应用来说,是非常重要的。
CMS垃圾回收针对新生代和老年代采用不同的策略。相比同吞吐量垃圾回收,它要复杂的多。吞吐量垃圾回收在执
Struts2技术总结
白糖_
struts2
必备jar文件
早在struts2.0.*的时候,struts2的必备jar包需要如下几个:
commons-logging-*.jar Apache旗下commons项目的log日志包
freemarker-*.jar  
Jquery easyui layout应用注意事项
bozch
jquery 浏览器 easyui layout
在jquery easyui中提供了easyui-layout布局,他的布局比较局限,类似java中GUI的border布局。下面对其使用注意事项作简要介绍:
如果在现有的工程中前台界面均应用了jquery easyui,那么在布局的时候最好应用jquery eaysui的layout布局,否则在表单页面(编辑、查看、添加等等)在不同的浏览器会出
java-拷贝特殊链表:有一个特殊的链表,其中每个节点不但有指向下一个节点的指针pNext,还有一个指向链表中任意节点的指针pRand,如何拷贝这个特殊链表?
bylijinnan
java
public class CopySpecialLinkedList {
/**
* 题目:有一个特殊的链表,其中每个节点不但有指向下一个节点的指针pNext,还有一个指向链表中任意节点的指针pRand,如何拷贝这个特殊链表?
拷贝pNext指针非常容易,所以题目的难点是如何拷贝pRand指针。
假设原来链表为A1 -> A2 ->... -> An,新拷贝
color
Chen.H
JavaScript html css
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <HTML> <HEAD>&nbs
[信息与战争]移动通讯与网络
comsci
网络
两个坚持:手机的电池必须可以取下来
光纤不能够入户,只能够到楼宇
建议大家找这本书看看:<&
oracle flashback query(闪回查询)
daizj
oracle flashback query flashback table
在Oracle 10g中,Flash back家族分为以下成员:
Flashback Database
Flashback Drop
Flashback Table
Flashback Query(分Flashback Query,Flashback Version Query,Flashback Transaction Query)
下面介绍一下Flashback Drop 和Flas
zeus持久层DAO单元测试
deng520159
单元测试
zeus代码测试正紧张进行中,但由于工作比较忙,但速度比较慢.现在已经完成读写分离单元测试了,现在把几种情况单元测试的例子发出来,希望有人能进出意见,让它走下去.
本文是zeus的dao单元测试:
1.单元测试直接上代码
package com.dengliang.zeus.webdemo.test;
import org.junit.Test;
import o
C语言学习三printf函数和scanf函数学习
dcj3sjt126com
c printf scanf language
printf函数
/*
2013年3月10日20:42:32
地点:北京潘家园
功能:
目的:
测试%x %X %#x %#X的用法
*/
# include <stdio.h>
int main(void)
{
printf("哈哈!\n"); // \n表示换行
int i = 10;
printf
那你为什么小时候不好好读书?
dcj3sjt126com
life
dady, 我今天捡到了十块钱, 不过我还给那个人了
good girl! 那个人有没有和你讲thank you啊
没有啦....他拉我的耳朵我才把钱还给他的, 他哪里会和我讲thank you
爸爸, 如果地上有一张5块一张10块你拿哪一张呢....
当然是拿十块的咯...
爸爸你很笨的, 你不会两张都拿
爸爸为什么上个月那个人来跟你讨钱, 你告诉他没
iptables开放端口
Fanyucai
linux iptables 端口
1,找到配置文件
vi /etc/sysconfig/iptables
2,添加端口开放,增加一行,开放18081端口
-A INPUT -m state --state NEW -m tcp -p tcp --dport 18081 -j ACCEPT
3,保存
ESC
:wq!
4,重启服务
service iptables
Ehcache(05)——缓存的查询
234390216
排序 ehcache 统计 query
缓存的查询
目录
1. 使Cache可查询
1.1 基于Xml配置
1.2 基于代码的配置
2 指定可搜索的属性
2.1 可查询属性类型
2.2 &
通过hashset找到数组中重复的元素
jackyrong
hashset
如何在hashset中快速找到重复的元素呢?方法很多,下面是其中一个办法:
int[] array = {1,1,2,3,4,5,6,7,8,8};
Set<Integer> set = new HashSet<Integer>();
for(int i = 0
使用ajax和window.history.pushState无刷新改变页面内容和地址栏URL
lanrikey
history
后退时关闭当前页面
<script type="text/javascript">
jQuery(document).ready(function ($) {
if (window.history && window.history.pushState) {
应用程序的通信成本
netkiller.github.com
虚拟机 应用服务器 陈景峰 netkiller neo
应用程序的通信成本
什么是通信
一个程序中两个以上功能相互传递信号或数据叫做通信。
什么是成本
这是是指时间成本与空间成本。 时间就是传递数据所花费的时间。空间是指传递过程耗费容量大小。
都有哪些通信方式
全局变量
线程间通信
共享内存
共享文件
管道
Socket
硬件(串口,USB) 等等
全局变量
全局变量是成本最低通信方法,通过设置
一维数组与二维数组的声明与定义
恋洁e生
二维数组 一维数组 定义 声明 初始化
/** * */ package test20111005; /** * @author FlyingFire * @date:2011-11-18 上午04:33:36 * @author :代码整理 * @introduce :一维数组与二维数组的初始化 *summary: */ public c
Spring Mybatis独立事务配置
toknowme
mybatis
在项目中有很多地方会使用到独立事务,下面以获取主键为例
(1)修改配置文件spring-mybatis.xml <!-- 开启事务支持 --> <tx:annotation-driven transaction-manager="transactionManager" /> &n
更新Anadroid SDK Tooks之后,Eclipse提示No update were found
xp9802
eclipse
使用Android SDK Manager 更新了Anadroid SDK Tooks 之后,
打开eclipse提示 This Android SDK requires Android Developer Toolkit version 23.0.0 or above, 点击Check for Updates
检测一会后提示 No update were found