当前位置: 首页 > news >正文

【源码预备】Calcite基础知识与概念:关系代数概念、查询优化、sql关键字执行顺序以及calcite基础概念

文章目录

    • 一. 关系代数的基本知识
    • 二. 查询优化
    • 三. SQL语句的解析顺序
      • 1. FROM
      • 2. WHERE
      • 3. GROUP BY
      • 4. HAVING
      • 5. SELECT
    • 四. Apache Calcite中的基本概念
      • 1. Adapter
      • 2. Calcite中的关系表达式
        • 2.1. 关系表达式例子
        • 2.2. 源码底层结构
      • 3. Calcite的优化规则
      • 4. Calcite的Trait--算子物理属性
      • 5. Calcite的Calling Convention(调用约定)
      • 6. Calcite内建算子

本文主要描述:Calcite 相关的基础性内容。

  1. 关系代数基础概念
  2. 查询优化简单介绍
  3. sql关键字解析顺序
  4. calcite基础概念

 
上篇了解了【源码分析】 Calcite 处理流程详解:calcite架构、处理流程以及就一个运行示例进行源码分析之后,我们对calcite有了一定的认知,但有些细节还未说明,所以本篇讨论对 Calcite 相关的基础性内容进行说明。希望通过本篇能够对Calcite的原理细节有一个更加清晰的了解。

一. 关系代数的基本知识

在学习Apache Calcite的一些基本概念之前,首先要弄懂关系表达式,并且要知道SQL与关系表达式的关系,因为Calcite的最核心的概念就是关系表达式。

关系代数是关系型数据库操作的理论基础,关系代数支持并、差、笛卡尔积、投影和选择等基本运算。关系代数也是 Calcite 的核心,任何一个查询都可以表示成由关系运算符组成的树

在 Calcite 中,它会先将 SQL 转换成关系表达式(relational expression),然后通过规则匹配(rules match)进行相应的优化,优化会有一个成本(cost)模型为参考。

 

关系代数相关内容,简单总结如下:
在这里插入图片描述

 

二. 查询优化

查询优化主要是围绕着 等价交换 的原则做相应的转换,相关文章

数据库查询优化入门: 代数与物理优化基础;

 

三. SQL语句的解析顺序

一个sql语句是按照如下的顺序解析的:

在这里插入图片描述

1. FROM

FROM后面的表标识了这条语句要查询的数据源。和一些子句如,(1-J1)笛卡尔积,(1-J2)ON过滤,(1-J3)添加外部列,所要应用的对象。FROM过程之后会生成一个虚拟表VT1。

  • (1-J1)笛卡尔积 这个步骤会计算两个相关联表的笛卡尔积(CROSS JOIN) ,生成虚拟表VT1-J1。
  • (1-J2)ON过滤 这个步骤基于虚拟表VT1-J1这一个虚拟表进行过滤,过滤出所有满足ON 谓词条件的列,生成虚拟表VT1-J2。
  • (1-J3)添加外部行 如果使用了外连接,保留表中的不符合ON条件的列也会被加入到VT1-J2中,作为外部行,生成虚拟表VT1-J3。

2. WHERE

对VT1过程中生成的临时表进行过滤,满足where子句的列被插入到VT2表中。

3. GROUP BY

这个子句会把VT2中生成的表按照GROUP BY中的列进行分组。生成VT3表。

4. HAVING

这个子句对VT3表中的不同的组进行过滤,满足HAVING条件的子句被加入到VT4表中。

5. SELECT

这个子句对SELECT子句中的元素进行处理,生成VT5表。

  • (5-1)计算表达式 计算SELECT 子句中的表达式,生成VT5-1
  • (5-2) DISTINCT 寻找VT5-1中的重复列,并删掉,生成VT5-2
  • (5-3) TOP 从ORDER BY子句定义的结果中,筛选出符合条件的列。生成VT5-3表
  • ORDER BY 从VT5-3中的表中,根据ORDER BY 子句的条件对结果进行排序,生成VC6表。

 

四. Apache Calcite中的基本概念

1. Adapter

在Calcite的架构中,Adapter的概念使Calcite知道如何去访问不同的数据源。一个数据源的Adapter对应有一个model,一个schema,一个schema Factory。

model定义了数据源的物理属性,比如下面的JDBC Adapter的model:

{"defaultSchema": "db1","schemas": [{"factory": "org.apache.calcite.adapter.jdbc.JdbcSchema$Factory","name": "db1","operand": {"jdbcDriver": "com.mysql.cj.jdbc.Driver","jdbcPassword": "changeme","jdbcUrl": "jdbc:mysql://localhost:3306/test","jdbcUser": "root"},"type": "custom"}],"version": "1.0"
}

schema定义了数据的格式和层次。schema factory可以解析model来创建schema。

在这里插入图片描述

 

2. Calcite中的关系表达式

在 Calcite 中,关系表达式通常以树形结构的形式表示。树的根节点是查询的最外层操作符,例如 SELECT、FROM、WHERE 等,每个操作符都有其对应的子节点,子节点可以是另一个关系表达式或者具体的数据源(where: 由adapter实现?)。

2.1. 关系表达式例子

如下 SQL 查询及其关系表达式

SELECT *
FROM orders o
JOIN customers c ON o.customer_id = c.customer_id
WHERE c.state = 'CA';LogicalProject(order_id=[$0], order_date=[$1], customer_id=[$2], order_total=[$3])LogicalFilter(condition=[=($5, 'CA')])LogicalJoin(condition=[=($2, $6)], joinType=[inner])EnumerableTableScan(table=[[MY_DB, ORDERS]])EnumerableTableScan(table=[[MY_DB, CUSTOMERS]])

说明

  • 每个节点代表一个操作符,例如 LogicalProject 代表 SELECT 操作,LogicalFilter 代表 WHERE 操作,LogicalJoin 代表 JOIN 操作。
  • 节点的顺序和嵌套结构代表了查询的**执行顺序(从下往上看)**和逻辑关系。
  • 节点参数:包括操作符参数子节点引用。例如 LogicalProject 的参数是输出的列,子节点是它所操作的关系表达式。

理解关系表达式对于理解 Calcite 的查询优化和执行过程非常重要。

 

2.2. 源码底层结构

转换为关系表达式的基本逻辑

在calcite中,当一个sql字符串被解析为SqlNode结构的AST树(抽象语法树)后,并不能直接被Calcite的优化器优化。还需要通过SqlToRelConverter将SqlNode结构转换成为RelNode结构组成的树。

 

关系表达式算子接口与实现
在这里插入图片描述

如上图所示,Calcite所有的关系表达式算子都需要实现RelNode接口。其中Calcite的核心算子有:TableScan, TableModify, Values, Project, Filter, Aggregate, Join, Sort, Union, Intersect, Minus, Window 与Match。

通过这些类的名字比较容易理解它们与SQL的对应关系,比如TableModify对应SQL中的INSERT、UPDATE、CREATE操作,Minus对应SQL中的EXCEPT操作,Window对应流处理的window概念等。

Calcite中的这些核心算子都有对应的纯逻辑子类LogicalXXX,SqlToRelConverter将SqlNode转换出来的RelNode树中,每个节点都是这些LogicalXXX子类组成的。它们并不能生成可执行的执行计划,只是用于表示SQL对应的关系表达式结构。

 

Adapter 对接实现

与Calcite对接的后端执行引擎的Adapter都会实现这些算子的可执行的实现。比如Cassandra adpter会有CassandraProject 在Calcite中逻辑算子转换成后端引擎实现的对应算子是在Calcite Planner(优化器)对RelNode树执行优化时候根据优化Rule将逻辑算子替换成对应的实际算子。

这里的adapter与flink的connector设计上是什么关系?

 

3. Calcite的优化规则

Calcite的优化器规则可以将一个关系表达式转换成等价的关系表达式,而这些优化器规则的基类都是RelOptRule。如下图的EnumerableSortRule可以将LogicalSort逻辑算子转换成Calcite内建的可执行的算子EnumerableSort。

在这里插入图片描述

package org.apache.calcite.adapter.enumerable;class EnumerableSortRule extends ConverterRule {EnumerableSortRule() {super(Sort.class, Convention.NONE, EnumerableConvention.INSTANCE,"EnumerableSortRule");}public RelNode convert(RelNode rel) {final Sort sort = (Sort) rel;if (sort.offset != null || sort.fetch != null) {return null;}final RelNode input = sort.getInput();return EnumerableSort.create(convert(input,input.getTraitSet().replace(EnumerableConvention.INSTANCE)),sort.getCollation(),null,null);}
}

Sort.class在优化器运行时匹配这条规则,然后优化器调用convert将原来的Sort算子转换为EnumerableSort算子。比如,LogicalSort在优化器优化时会匹配到这条规则,EnumerableSort就会替代LogicalSort。

 

除了上面的转换规则以外,Calcite已经实现了许多规则可以注册到优化器中,在优化时调用,比如filter、project等算子下推的优化规则等。目前Calcite已经实现了两种优化器引擎:基于代价优化的class VolcanoPlanner和基于经验的优化class HepPlanner。

 

4. Calcite的Trait–算子物理属性

在Calcite中没有使用不同的对象代表逻辑和物理算子,而是使用trait来表示一个算子的物理属性。

Calcite中使用接口RelTrait来代表一个关系表达式节点的物理属性,使用RelTraitDef来表示Reltrait的class。

RelTrait与RelTraitDef的关系就像java中对象与Class的关系一样,每个对象都有Class。

对于物理的关系表达式算子会有一些物理属性,这些物理属性都会用RelTrait来表示。

比如每个算子都有Calling Convention这一Reltrait。比如上图中Sort算子还会有一个物理属性RelCollation,因为Sort算子会对表的一些字段进行排序,RelCollation这一物理属性就会记录这个Sort算子要排序的字段索引、排序方向,null值怎么排序等信息

在这里插入图片描述

 

5. Calcite的Calling Convention(调用约定)

Calling Convention在Calcite中使用接口Convention表示,Convention接口是RelTrait的直接口,所以是一个算子的属性

Calling Convention可以理解为一个特定数据引擎协议,拥有相同Convention的算子可以认为都是同一个数据引擎的算子可以相互连接起来。比如JDBC的算子JDBCXXX都有JdbcConvention,Calcite的内建Enumerable算子EnumerableXXX都有EnumerableConvention。
在这里插入图片描述
上图中,Jdbc算子可以通过JdbcConvention获得对应数据库的SqlDialect和JdbcSchema等数据,这样可以生成对应数据库的sql,获得数据库的连接池与数据库交互实现算子的逻辑。

join场景

如果数据要从一个Calling Convention的算子到另一个Calling Convention算子的时候,比如使用Calcite进行跨库join的场景。需要接口Converter的子类作为两种算子之间的桥梁将两种算子连接起来。
在这里插入图片描述
比如上面的执行计划,要将Enumerable的算子与Jdbc的算子连接起来,中间就要使用JdbcToEnumerableConverter作为桥梁。

 

6. Calcite内建算子

如果一个Adapter没有实现所有的核心关系表达式算子,Calcite也能生成完整的执行计划,完成整个数据处理过程。这是因为Calcite内建了EnumerableConvention作为Calling Convention的Enumerable算子,实现了所有核心的关系表达式算子,比如EnumerableFilter,EnumerableSrt,EnumerableHashJoin等。

Enumerable算子效率不高

使用Enumerable算子效率不高,而且都是在内存中处理的。比如EnumerableHashJoin算子join两个表都是在内存中处理表的所有数据,数据量一大就会造成内存溢出。如果实现一个数据引擎的Adapter,能提供对应算子的处理能力就应该实现这个算子,将工作推到后端的数据引擎中处理,避免回退到使用Enumerable算子。

 

参考:
https://blog.csdn.net/feeling890712/article/details/106333425

相关文章:

【源码预备】Calcite基础知识与概念:关系代数概念、查询优化、sql关键字执行顺序以及calcite基础概念

文章目录 一. 关系代数的基本知识二. 查询优化三. SQL语句的解析顺序1. FROM2. WHERE3. GROUP BY4. HAVING5. SELECT 四. Apache Calcite中的基本概念1. Adapter2. Calcite中的关系表达式2.1. 关系表达式例子2.2. 源码底层结构 3. Calcite的优化规则4. Calcite的Trait--算子物理…...

【Java 设计模式】23 种设计模式

文章目录 设计模式是什么计算机行业里的设计模式创建型模式(共 5 种)结构型模式(共 7 种)行为型模式(共 11 种) 总结 设计模式是什么 “每一个模式描述了一个在我们周围不断重复发生的问题,以及…...

ElasticSearch深度分页解决方案

一、前言 ElasticSearch是一个基于Lucene的搜索引擎,它支持复杂的全文搜索和实时数据分析。在实际应用中,我们经常需要对大量数据进行分页查询,但是传统的分页方式在处理大量数据时会遇到性能瓶颈。本文将介绍ElasticSearch分页工作原理、深…...

nginx下upstream模块详解

目录 一:介绍 二:特性介绍 一:介绍 Nginx的upstream模块用于定义后端服务器组,以及与这些服务器进行通信的方式。它是Nginx负载均衡功能的核心部分,允许将请求转发到多个后端服务器,并平衡负载。 在upst…...

基于ssm的双减后初小教育课外学习生活活动平台的设计与实现论文

双减后初小教育课外学习生活活动平台的设计与实现 摘 要 当下,正处于信息化的时代,许多行业顺应时代的变化,结合使用计算机技术向数字化、信息化建设迈进。以前学校对于课外学习活动信息的管理和控制,采用人工登记的方式保存相关…...

wblogic中间件配置数据源

配置数据源 1.服务-数据源-配置-新建 2.单机选一般数据源 3.选择源名称、jndi名称、数据库类型 4.选择驱动 5.下一步 6.输入连接串信息 参考&#xff1a; 格式二&#xff1a;jdbc:oracle:thin:<host>:<port>:<SID> 数据库名称配置的sid 7.测试配置&#xff…...

Java数据结构之装箱拆箱

装箱和拆箱 也叫装包拆包&#xff0c;装包是把那八种基本数据类型转换为它的包装类&#xff0c;拆包则相反 上面这俩种方式都是装包&#xff0c;下面是它的字节码文件 用到了Integer的ValueOf方法&#xff1a; 就是返回了一个Integer类的对象&#xff0c;把它的value属性设置成…...

各版本 操作系统 对 .NET Framework 与 .NET Core 支持

有两种类型的受支持版本&#xff1a;长期支持 (LTS) 版本和标准期限支持 (STS) 版本。 所有版本的质量都是一样的。 唯一的区别是支持的时间长短。 LTS 版本可获得为期三年的免费支持和补丁。 STS 版本可获得 18 个月的免费支持和修补程序。 有关详细信息&#xff0c;请参阅 .N…...

Golang 线程安全与 sync.Map

前言 线程安全通常是指在并发环境下&#xff0c;共享资源的访问被适当地管理&#xff0c;以防止竞争条件&#xff08;race conditions&#xff09;导致的数据不一致 Go语言中的线程安全可以通过多种方式实现 实现方式 互斥锁&#xff08;Mutexes&#xff09; Go的sync包提供…...

1.2 Hadoop概述

小肥柴的Hadoop之旅 1.2 Hadoop概述 目录1.2 Hadoop概述1.2.1 回归问题1.2.2 Google的三篇论文1.2.3 Hadoop的诞生过程1.2.4 Hadoop特点简介 参考文献和资料 ) 目录 1.2 Hadoop概述 1.2.1 回归问题 通过前一篇帖子的介绍&#xff0c;特别是问题思考部分的说明&#xff0c;我…...

Adams许可管理安全控制策略

随着全球信息化的快速发展&#xff0c;信息安全和许可管理问题日益凸显。在这场无形的挑战中&#xff0c;Adams许可管理安全控制策略以其卓越的性能和可靠性&#xff0c;引领着解决这类问题的新潮流。 Adams许可管理安全控制策略是一种全方位、多层次的安全控制方案&#xff0…...

无人地磅系统|内蒙古中兴首创无人地磅和远程高效管理的突破

走进标杆企业&#xff0c;感受名企力量&#xff0c;探寻学习优秀企业领先之道。 本期要跟砼行们推介的标杆企业是内蒙古赤峰市砼行业的龙头企业&#xff1a;赤峰中兴首创混凝土搅拌有限责任公司&#xff08;以下简称为中兴首创&#xff09;。 中兴首创成立于2011年初&#xff…...

【SpringCloud】7、Spring Cloud Gateway限流配置

1、限流介绍 Spring Cloud Gateway 的限流配置主要涉及到令牌桶算法的实现。令牌桶算法可以对某一时间窗口内的请求数进行限制,保持系统的可用性和稳定性,防止因流量暴增而导致的系统运行缓慢或宕机。 在 Spring Cloud Gateway 中,官方提供了 RequestRateLimiterGatewayFi…...

【gRPC学习】使用go学习gRPC

个人博客:Sekyoro的博客小屋 个人网站:Proanimer的个人网站 RPC是远程调用,而google实现了grpc比较方便地实现了远程调用,gRPC是一个现代的开源远程过程调用(RPC)框架 概念介绍 在gRPC中&#xff0c;客户端应用程序可以直接调用另一台计算机上的服务器应用程序上的方法&#…...

C语言中常用的字符串函数(strlen、sizeof、sscanf、sprintf、strcpy)

C语言中常用的字符串函数 文章目录 C语言中常用的字符串函数1 strlen函数2 sizeof函数2.1 sizeof介绍2.2 sizeof用法 3 sscanf函数3.1 sscanf介绍3.2 sscanf用法3.3 sscanf高级用法 4 sprintf函数4.1 背景4.2 sprintf用法 5 strcpy函数5.1 strcpy介绍5.1 strcpy用法 1 strlen函…...

域名解析服务器:连接你与互联网的桥梁

域名解析服务器&#xff1a;连接你与互联网的桥梁 大家好&#xff0c;我是免费搭建查券返利机器人赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01;今天&#xff0c;我们将探讨一个网络世界中至关重要却鲜为人知的角…...

理论物理在天线设计和射频电路设计中的应用

理论物理的基本原理可以应用于电路中的电磁场分析和电磁波传播问题&#xff0c;例如天线设计和射频电路设计。通过应用麦克斯韦方程组和电磁波传播理论&#xff0c;可以优化电路的性能&#xff0c;提高天线的辐射效率和射频电路的传输效率。麦克斯韦方程组是描述电磁场行为的基…...

MySql01:初识

1.mysql数据库2.配置环境变量3. 列的类型和属性&#xff0c;索引&#xff0c;注释3.1 类型3.2 属性3.3 主键(主键索引)3.4 注释 4.结构化查询语句分类&#xff1a;5.列类型--表列类型设置 1.mysql数据库 数据库&#xff1a; ​ 数据仓库&#xff0c;存储数据&#xff0c;以前我…...

Python——运算符

num 1 num 1 print("num1:", num) num - 1 print("num-1:", num) num * 4 print("num*4:", num) num / 4 print("num/4:", num) num 3 num % 2 print("num%2:", num) num ** 2 print("num**2:", num) 运行结果…...

赋能软件开发:生成式AI在优化编程工作流中的应用与前景

随着人工智能&#xff08;AI&#xff09;技术的快速发展&#xff0c;特别是生成式AI模型如GPT-3/4的出现&#xff0c;软件开发行业正经历一场变革&#xff0c;这些模型通过提供代码生成、自动化测试和错误检测等功能&#xff0c;极大地提高了开发效率和软件质量。 本文旨在深入…...

通过盲对抗性扰动实时击败基于DNN的流量分析系统

文章信息 论文题目&#xff1a;Defeating DNN-Based Traffic Analysis Systems in Real-Time With Blind Adversarial Perturbations 期刊&#xff08;会议&#xff09;&#xff1a;30th USENIX Security Symposium 时间&#xff1a;2021 级别&#xff1a;CCF A 文章链接&…...

【Project】TPC-Online Module (manuscript_2024-01-07)

PRD正文 一、概述 本模块实现隧道点云数据的线上汇总和可视化。用户可以通过注册和登录功能进行身份验证&#xff0c;然后上传原始隧道点云数据和经过处理的数据到后台服务器。该模块提供数据查询、筛选和可视化等操作&#xff0c;同时支持对指定里程的分段显示和点云颜色更改…...

通过cpolar在公网访问本地网站

通过cpolar可以轻松将本地网址映射到公网进行访问&#xff0c;下面简要介绍一下实现步骤。 目录 一、cpolar下载 二、安装 三、使用 3.1 登录 3.2 创建隧道 一、cpolar下载 cpolar官网地址&#xff1a;cpolar - secure introspectable tunnels to localhost 通过QQ邮箱…...

Prokka: ubuntu安装的时候出现错误

[14:10:57] Running: cat /app/prokka_result/ref_file/ref_file.HAMAP.hmm.tmp.77.faa | parallel --gnu --plain -j 2 --block 108208 --recstart ‘>’ --pipe hmmscan --noali --notextw --acc -E 1e-09 --cpu 1 /opt/prokka/db/hmm/HAMAP.hmm /dev/stdin > /app/pro…...

安全防御之密码技术

密码学是信息安全的基础技术之一&#xff0c;是达到信息系统安全等级保护要求的核心技术支持&#xff0c;在身份验证、访问控制、文件加密、数据加密和安全传输中都得到广泛应用。其核心目标是保证信息的机密性、完整性和可用性。 密码学包括加密和解密两个部分。一般过程是&am…...

一文读懂「多模态大模型」

​ 学习资源 5-多模态大模型一统NLP和CV 1.多模态大模型的基本原理 2.常见的多模态大模型 https://www.bilibili.com/video/BV1NN41177Zp?p5&vd_sourcef27f081fc77389ca006fcebf41bede2d 3.多模态大模型如_哔哩哔哩_bilibili 强强联手&#xff01;科大讯飞和中科院终于把【…...

深入PostgreSQL:高级函数用法探索

写在开头 在 PostgreSQL 中,函数是数据库开发和管理中强大而灵活的工具。通过深入了解高级函数用法,我们可以更有效地利用 PostgreSQL 的功能。在本文中,我们将探讨一些看起来比较高级的 PostgreSQL 函数用法,包括窗口函数、自定义聚合函数、JSONB 类型函数、全文搜索、PL…...

huggingface实战bert-base-chinese模型(训练+预测)

文章目录 前言一、bert模型词汇映射说明二、bert模型输入解读1、input_ids说明2、attention_mask说明3、token_type_ids说明4、模型输入与vocab映射内容二、huggingface模型数据加载1、数据格式查看2、数据dataset处理3、tokenizer处理dataset数据三、huggingface训练bert分类模…...

CCS安装和导入项目及编译教程

1. CCS安装# 在 TI官网 下载离线版&#xff08;offline&#xff09;。 Code Composer Studio Downloads 页面上有license 信息&#xff1a;这么看来是免费的&#xff0c;爱了爱了 Licensing: CCSv7 and later are Technology Software Publicly Available (TSPA) compliant.…...

在React里面使用mobx状态管理详细步骤

1、安装MobX和MobX React&#xff1a; 在你的项目目录下运行以下命令安装MobX和MobX React&#xff1a; npm install mobx mobx-react2、创建MobX Store&#xff1a; 创建一个用于管理状态的MobX Store。这个Store应该包含你希望全局管理的状态和相关的操作。以下是一个简单…...

哪个网站做加盟的比较靠谱/南京seo优化公司

报错信息&#xff1a;指明了是Attribute name cannot be null or empty&#xff0c;但是就是不告诉你具体是哪行代码出错了。我真的是吐了。 org.thymeleaf.exceptions.TemplateInputException: An error happened during template parsing (template: "class path resou…...

湖北工程建设信息网站/青岛seo网站排名

view属性释义 所有点的坐标均从视图左下角&#xff08;0,0&#xff09;起算 图纸比例为1:20,打印出的图纸测试相应点坐标时需根据图纸比例计算 1. Origin&#xff08;149.1,46.125,0&#xff09; api:The view origin coordinates in the sheet. 2. ExtremaCenter&#xff…...

广东网站建设多少钱/今天国内最新消息

前些日子&#xff0c;非常荣幸的收到了小米公测提供的米家智能多模网关和小米米家光照传感器。熟悉米家/Aqara的值友应该知道&#xff0c;Aqara作为米家生态链中唯一一家使用Zigbee作为产品核心技术的企业&#xff0c;在几年间已经发布了很多网关类产品&#xff1a;米家多功能网…...

芜湖今日头条新闻/长沙网站seo收费

工具介绍: SharePoint 2010 文档库自带了”Send To” 功能, 但是这个功能只能移动文件, 但是这个功能的限制很多, 比如只能复制文件, 只能在本站点内被复制, 而且只能复制Major 版本, 如果你要移动文件, 或者文件夹而且包含所有的版本&#xff08;主要版本和次要版本&#xff0…...

中文网站建设教程/站长网站大全

前面两篇文章&#xff0c;我们讲了自定义viewpagerphotoView实现本地图片的加载和收缩缩放。实现本地相册功能。 如果没有看的话可以先阅读以下&#xff0c;因为今天网络加载图片的功能&#xff0c;实在这个基础上做的修改&#xff0c;会基于之前的基础上讲解。 1. http://bl…...

网站链接优化怎么做/口碑营销的案例

快过年了&#xff0c;各种互联网产品都出来撒红包。某宝一年一度的集五福&#xff08;shua hou&#xff09;活动更是成为每年的必备活动。虽然到最后每人大概也就分个两块钱&#xff0c;但作为一个全民话题&#xff0c;大多数人还是愿意凑凑热闹。毕竟对于如今生活在大城市的人…...