## Algo

&ensp;&ensp;&ensp;&ensp;Algo提供SQL计算功能，支持常用的SQL算法，遵循[SQL-92](https://www.service-architecture.com/articles/database/sql-92.html)标准。  



##   特性

Algo通过宿主机内存计算代替数据库计算，减轻数据库压力，解决数据库性能瓶颈，适用于大数据量且需要进行多次计算的场景。

- 数据库分库后，替代SQL功能
- 替代复杂SQL
- 替代临时表
- 作为报表开发框架




##  快速上手

&ensp;&ensp;&ensp;&ensp;通过ORM组件提供的API对数据库表进行查询，获取DataSet（类似ResultSet）

 ```java
	DataSet ds = ORM.create().queryDataSet("algoKey", "entityName", "selectFields",new QFilter[0]);
	ORMUtil.dumpDataSet(ds.copy());  //打印数据
	ds = ds.sum("amount").finish();//对amount字段求和，amount为字段标识
	ORMUtil.dumpDataSet(ds.copy()); 
 ```

- algoKey
  &ensp;&ensp;无论使用哪种方法来创建DataSet，都必须传递algoKey；algoKey是用来监控追踪DataSet的使用情况，包括日志，性能 (IO,CPU,时间),执行计划等。
- entityName
  &ensp;&ensp;数据库实体名称
- selectField
  &ensp;&ensp;字段标识，可以查询多个字段，使用逗号分隔。



##  Algo API

### Algo对象

| 接口/对象类          | 作用                                                         | 说明/注意                                                    |
| -------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
| kd.bos.algo.Algo     | 创建DataSet getCacheDataSet(String cacheId)                  | 这个类是入口，给平台使用的，业务不要使用                     |
| kd.bos.algo.DataSet  | DataSet操作接口，包括转换，action，close等                   |                                                              |
| Kd.bos.algo.RowMeta  | DataSet的元数据，类似jdbc ResultSetMetaData由字段Field[]组成 |                                                              |
| Kd.bos.algo.Field    | 字段                                                         |                                                              |
| Kd.bos.algo.DataType | 数据类型，包括主要数据类型                                   |                                                              |
| Kd.bos.algo.Input    | 数据源接口                                                   |                                                              |
| Kd.bos.algo.Row      | 行接口，行值访问器                                           | Row是一个虚接口，访问器，不是Object[]，所以业务代码不能把Row缓存起来 |
| CachedDataSet        | DataSet.cache的结果对象                                      | 不是DataSet的子类                                            |
| CacheHint            | Cache hint，指示                                             |                                                              |
| JoinDataSet          | DataSet.join的结果对象，也是Join构造器                       | 不是DataSet的子类                                            |
| HashJoinDataSet      | DataSet.hahJoin的结果对象，也是HashJoin构造器                | 不是DataSet的子类                                            |
| GroupbyDataSet       | DataSet.groupBy的结果对象，也是groupBy构造器                 | 不是DataSet的子类                                            |
| HashTable            | DataSet.toHashTable的结果对象，是hashJoin的参数              |                                                              |
| JoinType             | Join类型枚举                                                 |                                                              |
| JoinHint             | Join hint，指示                                              |                                                              |
| RowMetaFactory       | 创建RowMeta                                                  | 给平台用的                                                   |

### RowMeta，Field，DataType

RowMeta，Field，DataType对应数据库中的行数据，字段，数据类型。

- 获取RowMeta	

  ```java
  RowMeta rowMeta = dataSet.getRowMeta();
  ```

- 获取Field

  ```java
  Field field = rowMeta.getField(index);
  ```

- 获取DataType

  ```java
  DataType type = field.getDataType();
  ```

### 数据类型

数据类型包含以下十种类型

| 类型           | 说明                                    |
| -------------- | --------------------------------------- |
| BooleanType    |                                         |
| StringType     |                                         |
| IntegerType    |                                         |
| LongType       |                                         |
| DoubleType     | 从元数据ORM框架查出来的数据不会有Double |
| BigDecimalType |                                         |
| DateType       |                                         |
| TimestampType  |                                         |
| NullType       | Select中动态创建null Field生成          |
| UnknownType    | 表达式解析后无法确定的列，业务不会用到  |



##  DataSet

###  DataSet简介
- DataSet是指kd.bos.algo.DataSet，无特殊说明情况下，后文中的DataSet都是指kd.bos.algo.DataSet，DataSet是结果集，与JDBC 中的ResultSet类似
- DataSet即是结果集转换器，也是迭代计算

- DataSet不局限于数据库中的数据，文件流，集合类型的数据也可以转换为DataSet

- 获取的DataSet也可以缓存

  ![DataSet](image\01.png)

- kd.bos.algo.DataSet是两类接口，Transform和Action，相关概念与Apache Flink是对等的。

  1. Transform：转换DataSet，生成新的DataSet；包括主要sql操作，如orderby，select，where，filter，group by，range，top，union等等

     ![Transform](image\02.png)

  2. Action：Action是消费DataSet，Action执行结果不是DataSet；Action执行后，DataSet自动关闭；Action接口不多，比如count，cache等
   ![Action](image\03.png)
  


 &nbsp;


###  创建DataSet

- **Algo原生API创建DataSet**

```java
	Algo algo = Algo.create(algoKey);
	public abstract DataSet createDataSet(Collection<Object[]> rowList, RowMeta rowMeta);
```

```java
	Algo algo = Algo.create(algoKey);
	public abstract DataSet createDataSet(Iterator<Object[]> iterator, RowMeta rowMeta);
```

```java
	Algo algo = Algo.create(algoKey);
	public abstract DataSet createDataSet(ResultSet rs);
```

```java
	Algo algo = Algo.create(algoKey);
	public abstract DataSet createDataSet(Input… inputs);
```

 - **业务创建DataSet**

```java
	QueryServiceHelper. queryDataSet(String algoKey, String entityName, String selectFields, QFilter[] filters，String orderBys)
```
```java
	ORM.queryDataSet(String algoKey, String entityName, String selectFields, QFilter[] filters)
```

```java
	DB.queryDataSet();
```
###  DataSet相关API
| 方法                                                         | 功能                                   |
| :----------------------------------------------------------- | :------------------------------------- |
| DataSet join(DataSet rightDataSet)<br/>DataSet join(DataSet rightDataSet, JoinHint hint)<br/>DataSet join(DataSet rightDataSet, JoinType type)<br/>DataSet join(DataSet rightDataSet, JoinType type, JoinHint hint)<br/>DataSet leftJoin(DataSet rightDataSet, JoinHint hint)<br/>DataSet rightJoin(DataSet rightDataSet, JoinHint hint)<br/>DataSet fullJoin(DataSet rightDataSet, JoinHint hint) | join                                   |
| DataSet hashJoin(HashTable hashTable, String leftJoinKeyField, String[] DataSet hashTableSelectFields)<br/>DataSet hashJoin(HashTable hashTable, String leftJoinKeyField, String[] DataSet hashTableSelectFields, boolean includeNotExist) | hashJoin                               |
| union(DataSet dataSet)                                       | Union操作                              |
| top(int length)                                              | 取top n个                              |
| limit(int start, int length)                                 | 取部分行 |
| range(int start, int length)                                 | 取部分行，类似limit                    |
| copy()                                                       | 拷贝自己，后面详细明                   |
| int count(String field, boolean distinct)                    | 对field进行count计数，distinct消除重复 |
| CachedDataSet cache(CacheHint cacheHint                      | 将dataset缓存起来，后续详细介绍        |
| CachedDataSet.Builder cacheBuilder(CacheHint hint)        |                                        |
| print(boolean copy)                                          | 打印输出到console，|
|copy|表示是否copy dataset。调试时，可以调用print(true)打印 |
| Close()                                                      | 关闭    |
| select(String[] exprs)<br/>select(String exprs)              | 选择字段，类似:select a,b,c，a,b,c可以是表达式   |
| addField(String expr, String alias)<br/>addNullField(String alias)<br/>addBalanceField(String expr, String alias)                | 增加字段 |
|addNullField(String alias)                                    |            增加null字段，等价于addField("null",alias) |
| removeFields(String... fields)                               |      删除字段   |
| filter(String expr)<br/>filter(String expr, Map<String, Object> params)<br/> where(String expr)<br/>where(String expr, Map<String, Object> params) |                                                 过滤，类似where，expr中可以写变量，变量值通过params传递，比如”a>b”, params是map，key包含a和b|
| orderBy(String[] fields)                                     |   排序，field可以写成field asc,field desc |
| groupBy(String[] groupFields)<br/>groupBy(String[] groupFields, boolean[] orderByDescs) | groupBy操作 |

###  DataSet使用SQL执行
- **API**

```java
public DataSet executeSql(String sql);
```

- **示例**

```java
DataSet ds= 
dataSet.executeSql("select count(*) c,fname,1 one, null N,'abc' Str, 1+2 as Add,sum(famount) amount, sum(famount*2) amount2,sum(fqty) qty 
where famount>10 
group by fname 
having amount>1000 
order by amount
desc,qty 
limit 0,10");
```



###  DataSet API详解

#### select
- **public DataSet select(String[] exprs);**
&ensp;&ensp;&ensp;&ensp;exprs可以是 字段field、Field as alias、表达式 as alias；Select是对源DataSet的重新选择，类似sql；DataSetA.Select(new String[]{“a”,”b+c as d”})等价于Select a,b+c as d from DataSetA。

示例：
```java
DataSet ds= dataSet.select(new String[]{
	"famount",
	"famount c1",
	"famount + fqty c2", 
	"famount * fqty c3",
	"null c4", "true c5",
	"(famount + fqty) * 3 c6",
    "famount >= fqty c7",
    "famount >= fqty and fqty<100 c8",
    "fname + 'abc' name"});
```

- **public DataSet select(String exprs);**
&ensp;&ensp;&ensp;&ensp;exprs可以是直接写多个字段，比如dataSetA.select(“fname, famount  as amount,1+2 as c”);

**示例：**
```java
DataSet ds= dataSet.select(
	"famount,
	famount c1,
	famount + fqty c2,
	famount * fqty c3,
 	null c4,
  	?true c5,
    (famount + fqty) * 3 c6,
    famount >= fqty c7,
    famount >= fqty and fqty<100 c8,
    fname + 'abc' name});
```



#### addField

- **public DataSet addField(String expr, String alias)**
  &ensp;&ensp;在现有DataSet基础上添加字段，或者删除字段

- **public DataSet addField(String expr, String alias)**
  &ensp;&ensp;添加表达式expr字段，数据类型自动判断

  
#### addNullField
- **public DataSet addNullField(String alias)/public DataSet addNullField(String... alias)**
  &ensp;&ensp;添加值为Null的字段，数据类型为NullType

  

#### addBalanceField
- **public DataSet addBalanceField(String expr, String alias)**
  &ensp;&ensp;添加余额字段，addBalanceField方法将字段的值从上往下累加

**示例：**

```java
addBalanceField(“amount”, “balance”)，
addBalanceField(“amount * 2”, “balance2”)，
```

|Period|	Amount|	balance|	balance2|
|--|--|--|--|
|201701	|100|	100|	200|
|201702|	200|	300|	600|
|201703|	200|	500|	1000|



#### removeField

- **public DataSet removeField(String field)**
  删除字段

  

#### where/filter

| 方法                                                         | 说明                                                         |
| :----------------------------------------------------------- | :----------------------------------------------------------- |
| public DataSet where(String expr);<br/> public DataSet where(String expr, Map<String,  Object> params);<br/> public DataSet filter(String expr);<br/> public DataSet filter(String expr, Map<String, Object> params); | Filter类似于sql的where条件<br/> Expr也是计算表达式，必须为boolean<br/> Params传递参数给expr，如expr为famount + var1 > 10000<br/>Params为：{var1: 100}等价于： famount+100>10000<br/> where和filter是完全等价的 |

**示例：**

```java
DataSet ds= dataSet.where("famount>50 and (fqty-100)<5");
```

```java
DataSet ds = dataSet.filter("famount>50 and (fqty-100)<5");
```



#### orderBy

- **public DataSet orderBy(String[] exprs);**
  Expr可以是:
  1. 字段Fname，默认为asc排序
  2. Fname asc
  3. Fname desc
  4. Expr不可以为表达式

**示例：**


```java
DataSet dataSet2 = dataSet.orderBy(new String[]{"fname", "famount"});
DataSet dataSet2 = dataSet.orderBy(new String[]{"fname desc", "famount asc"});

```


#### groupBy

- **GroupbyDataSet groupBy(String[] groupFields);**

- **GroupbyDataSet groupBy(String[] groupFields, boolean[] orderByDescs);**

  调用过程：
  1. 获取构造器GroupByDataSet
  2. 构造器里设置sum，avg等聚合函数
  3. 构造器finish得到DataSet

**示例：**

```java
GroupbyDataSet groupby = dataSet.groupBy(new String[]{“fname”}); //groupby是构造器
groupby = groupby.sum("(famount + fqty) * 2", "amount").count(“countalias");
groupby = groupby.maxP(“famount”, “fqty”, "amount").count();
DataSet dataSet2 = groupby.finish();//构造完毕，返回DataSet

```
- **groupBy说明**

  1. GroupBy结果集默认根据group fields排序，默认asc排序，可以对每个field的排序方向进行设置，即以下orderByDescs：

     ```
     GroupbyDataSet groupBy(String[] groupFields, boolean[] orderByDescs);
     ```

     所以，对groupby结果进行orderBy，请考虑是否有必要

  2. SQL 92标准，group by结果是不保证排序的，上述API查询结果默认是排序的，是历史原因，目前无法简单去掉;现在没有sql的group by，结果就不保证排序

  3. 当GroupBy字段为空时，如dataset.groupBy(null)，或者dataSet.groupBy(new String[0]);
     dataSet.groupBy(null).sum(a).max(b).finish()等价于没有groupby
     
  4. 有聚合函数的sql：Select sum(a),max(b) from t;如果用sql，可以简写： Select sum(a),max(b)， 不需要group by关键字 



#### union

- **public DataSet union(DataSet rightDataSet);**
  
  1. 两个DataSet叠加起来，不支持消除重复
  2. 两个DataSet字段个数必须相同，且每个字段的类型必须互相兼



- **字段Fields合并规则：**
  
  1. 默认字段名取左边
  2. 数据类型取左边和右边的兼容类型



- **数据类型兼容规则：**
  
  1. Number类型，取最大精度如(Int,Long)取long，(BigDecimal,Long)取BigDecimal
  2. 含Null类型的，取非Null类型
  3. 含Unknown类型的，取非Unknown类型的



- **其他**
  
  1. 如果两个DataSet字段个数不同，又需要Union，可以通过DataSet.addNullField()添加null字段，以满足相同个数
     &nbsp;
#### join

&ensp;&ensp;&ensp;&ensp;适用于两个DataSet的join，跟sql的join类似，支持InnerJoin，LeftJoin，RightJoin，FullJoin，CrossJoin

**join方法**

- JoinDataSet join(DataSet rightDataSet)
- JoinDataSet join(DataSet rightDataSet, JoinHint hint)
- JoinDataSet join(DataSet rightDataSet, JoinType type)
- JoinDataSet join(DataSet rightDataSet, JoinType type, JoinHint hint)

**Join便捷方法**

- JoinDataSet  leftJoin(DataSet rightDataSet)
- JoinDataSet  leftJoin(DataSet rightDataSet, JoinHint hint)
&nbsp;
- JoinDataSet  rightJoin(DataSet rightDataSet)
- JoinDataSet  rightJoin(DataSet rightDataSet, JoinHint hint)
&nbsp;
- JoinDataSet  fullJoin(DataSet rightDataSet)
- JoinDataSet  fullJoin(DataSet rightDataSet, JoinHint hint)

**JoinHint是什么**
&ensp;&ensp;&ensp;&ensp;JoinHint是一些特性指示器，目前只有一个；Join时，null值是否当做0,为true时，0=null;为false时，0!=null;默认值为false。

```java
setNullAsZero(boolean nullAsZero)
```
**JoinDataSet构造器接口**

- JoinDataSet on(String leftField, String rightField); //类似于sql中的on left.leftField=right. rightField
- JoinDataSet select(String[] leftFields, String[] rightFields);//类似于sql中的select，分别选择左右表字段
- JoinDataSet hint(JoinHint hint);//设置hint
- DataSet finish();//返回DataSet



**示例**

```java
JoinDataSet join = dataSet.join(productDataSet, JoinType.Left);
DataSet result = join.on("fproductid", "fid").select(new String[]{"fproductid", "famount amount", "fqty qty"}, new String[]{"fname productName"}).finish();

JoinDataSet join = dataSet.leftJoin(productDataSet);
DataSet result = join.on("fproductid", "fid").select(new String[]{"fproductid", "famount amount", "fqty qty"}, new String[]{"fname productName"}).finish();

```
#### hashJoin

1. 适用于一个大表关联1至N个小表，如业务单据join基础资料
2. hashJoin比普通Join性能更好，特别是同时关联多个小表时
3. HashJoin性能比较好，消耗资源少，推荐使用，但也谨慎推荐，因为小表是否真的很小，需要判断，一般认为小表数据量小于10000即可

​		![HashJoin](image\04.png)

**HashJoin使用步骤**

1. 小表DataSet转换为HashTable，其中keyField必须是唯一单字段，否则就不能是HashTable

   ```
   public HashTable toHashTable(String keyField);
   ```

2. 大表DataSet.hashJoin小表，得到HashJoinDataSet构造器，其中leftJoinKeyField为大表关联字段，hashTableSelectFields右边选择字段

   ```
   public HashJoinDataSet hashJoin(HashTable hashTable, String leftJoinKeyField, String[] hashTableSelectFields);
   ```

3. HashJoinDataSet构造器addHashTable，继续添加

**调用过程：**

1. 如果要关联N个小DataSet，分别转换为HashTabl
2.  通过hashJoin获得构造器HashJoinDataSet
3. 在构造器中添加HashTable，设置左表选择字段
4. Finish()返回DataSet

**示例**

```
HashTable productLT = productDataSet.select(new String[]{"fid productId", "fname productName"}).toHashTable("productId");

HashTable orgLT = orgDataSet.select(new String[]{"fid orgId", "fname orgName"}).toHashTable("orgId");

DataSet joinDataSet = factDataSet.hashJoin(productLT,  "fproductid", new String[]{"productName as pName"}, true)
.addHashTable(orgLT,  "forgid", new String[]{"orgName"}, true)
.selectLeftFields(new String[]{"fproductid", "famount amount", "fqty qty"}).finish();
```



**说明：**

HashJoin默认结果类似于InnerJoin，也可以实现Left Join的效果，即大表中有，小表中没有，通过includeNotExist，ncludeNotExist是作用于每个连接上，所以，每个连接可以includeNotExist值不同的

- 大表连接HashTable时，如left.faccountid=hashTable.fid, 如果left.faccountid在HashTable中不存在，默认是不会选择该行

- 如果传入includeNotExist=true，那么会选择该行，等价于left join，右表字段全部为null



crossJoin

- 什么是crossJoin，参考下图

  ![](image\06.png)



#### HashJoinDataSet

添加一个HashTable关联：

HashJoinDataSet addHashTable(HashTable hashTable, String leftJoinKeyField, String[] hashTableSelectFields, boolean includeNotExist);

设置左边的选择字段HashJoinDataSet selectLeftFields(String[] leftFields);

finish();



#### count

**int count(String field, boolean distinct)**

1. 类似sql
2. 不包括null值
3. DataSet执行count后，自动close



#### print

**print(boolean copy)**

打印输出到console，copy表示是否copy dataset。调试时，可以调用print(true)打印；跟ORMUtil.dumpDataSet(dataSet.copy())类似



#### copy

 **DataSet copy()**
&ensp;&ensp;&ensp;&ensp;Copy是有资源消耗的，默认DataSet只能被遍历一次，因为它可能是在线的，即底层可能是ResultSet，Copy后会变成离线的，占用内存
**什么时候需要copy**

1. DataSet需要遍历多次

2. DataSet既要被引用，又要遍历使用

3. 调试打印时用，ORMUtil.dumpDataSet或DataSet.print

**不该copy的场景**

1. dataset.copy().join() copy结果没有用到
2. 调试时用了copy()，正式代码需要删除掉
   



##  高级API

### cache

#### cache 介绍

**public CachedDataSet cache(CacheHint cacheHint);**

- dataSet.cache(),dataSet是离线的，只能顺序遍历，遍历一次，无状态

- CachedDataSet是将DataSet缓存起来，通过id多次访问，并提供随机按Range访问

- CachedDataSet默认是有超时时间的(30分钟)，业务可以自己设置

  ![Cache](image\07.png)

**示例**

```java
//写入缓存
CacheHint hint = new CacheHint();
Hint.setTimeout(60* 60 * 1000); //默认超时是30分钟
CachedDataSet cachedDataSet = DataSet.cache(cacheHint);
String id = cachedDataSet.getCachedId();
 //获取CachedDataSet
CachedDataSet cachedDataSet = Algo.get CachedDataSet(id);
//遍历缓存
Iterator<Row> iterator cachedDataSet.iterator(int begin, int length);
或者
List<Row> list = cachedDataSet. getList(int begin, int length);

//关闭
cachedDataSet.close();
```

#### cache API

- DataSet:

  1. CachedDataSet cache(CacheHint cacheHint)

  2. CachedDataSet.Builder cacheBuilder(CacheHint hint)

- CachedDataSet.Builder(cache构造器,当前dataset cache后可以继续添加row)

  1. public void append(Row row);

  2. public void append(Iterator<Row> rowIterator);
  3. CachedDataSet build();

- CachedDataSet

  1. public String getCacheId();
  2. int getRowCount();
  3. public RowMeta getRowMeta();
  4. List<Row> getList(int begin, int length);
  5. Iterator<Row> iterator(int begin, int length);
  6. public void close();  //释放资源

- Algo

  1. public String getCachedDataSet(String cacheId);


### Cache Builder

- 应用场景： 当前dataset cache后可以继续添加row

```java
//写入缓存
CacheHint hint = new CacheHint();
Hint.setTimeout(60* 60 * 1000); //默认超时是30分钟
CachedDataSet cachedDataSet = DataSet.cache(cacheHint);
String id = cachedDataSet.getCachedId();


 //获取CachedDataSet
CachedDataSet cachedDataSet = Algo.get CachedDataSet(id);
//遍历缓存
Iterator<Row> iterator cachedDataSet.iterator(int begin, int length);
或者
List<Row> list = cachedDataSet. getList(int begin, int length);

//关闭
cachedDataSet.close();
```


### DataSetBuilder

​	DataSetBuilder提供内存构造DataSet的功能，DataSetBuilder不同于CachedDataSet.Builder

 **示例：**
```java
RowMeta rowMeta = xxx;
DataSetBuilder builder = Algo.createDataSetBuilder(rowMeta);
builder.append(new Object[]{xxx});
builder.append(new Object[]{xxx});
DataSet dataset = builder.build();

```

### Input

Input是一种数据源接口,通过Input可以创建一个DataSet,接口如下：

```java
DataSet createDataSet(Input... inputs);
```

执行并行取数，如果传入多个Input，默认启动4个并行查询

Input有4个子类：
- OrmInput
- DbInput
- OqlInput
- CollectInput

Input有一个子接口CustomizedInput，供自定义Input

**示例：**

```java
int n = 8;
OrmInput[] inputs = new OrmInput[n];
for(int i=0;i<n;i++){
   Qfilter[] filters = …;  //把filters拆成多个，可并行执行
   Inputs[i] = new OrmInput(algoKey, String entityName, selectFields, filters);
}
DataSet dataset = Algo.createDataSet(inputs);
```


### CustomizedInput

CustomizedInput是Input的子接口，实现该接口实现自定义数据源，接口如下：

```
public interface CustomizedInput extends Input, Closeable{
	public abstract Iterator<Object[]> createIterator();
	public abstract void close();
}
```

&nbsp;

### 计算表达式

#### 特性

- expr支持基本四则运算，包括：+,-,*,/,()
- 支持常量数字，字符串
- 支持逻辑表达式： <,>,<=,>=,<>,!=, and, or, xor, not
- 支持宏: NULL, TRUE, FALSE
- 别名: expr alias, expr as alias
- 支持跟SQL一样的Case When语法，2种
- 支持函数

**示例：** 

```java
1. famount
2. famount as amount
3. famount * 2 as amount, famount + 2 as amount, famount / fqty as amount, famount * fqty as mount,
4. (famount + qty) * 2 as amount
5. famount > fqty as b
6. famount > fqty and fqty > 100 as c
7. null as c, true as c, false as c
8. 100 as amount, 'abc' as name
9. fname + 'abc' as name
```

<div STYLE="page-break-after: always;"></div>

#### 表达式语法

| 类型                 | 语法                                                         | 说明                                  |
| -------------------- | ------------------------------------------------------------ | ------------------------------------- |
| 数值四则运算         | +,-,*,/,%,()                                                 | %为求余                               |
| 字符串拼接           | +                                                            | 或者用concat函数                      |
| 字符串like           | like %abc%                                                   | 跟sql类似，通过%实现左右like匹配      |
| 别名                 | expr as alias                                                | A as c, a+b as c                      |
| 类型转换             | Cast(expr as DataType)                                       |                                       |
| 布尔比较符           | =, <,<br/><= , >, >=, <>, !=                                 | <,<=,>,>=只适用于数值比较<> 等价于 != |
| 布尔连接符           | and，or                                                      |                                       |
| Case When语句        | 1.Case 表达式 When 值 then 值 [else 值] end<br/>2.Case When 布尔表达式 then 值 [else 值] end | 跟sql一样，有两种形式                 |
| In                   | expr in (v1, v2,vN)                                          | 跟sql一样                             |
| Is Null，Is Not Null | 1.Expr is Null<br/>2.Expr is Not Null                        | 等价于expr=null, expr<>null`          |
| 宏                   | True, False, Null                                            |                                       |
| 参数化？             | expr>?                                                       | ?是参数，filter函数通过Map传入值      |
| 函数                 | Func(arg1,arg2)                                              |                                       |

<div STYLE="page-break-after: always;"></div>

### 日期函数

|函数|说明|
|:--|:--|
|Now()<br/>Date()|	返回当前时间|
|Year(date)|	返回date年月日中的年|
|Month(date)|	返回date年月日中的月|
|Day(date)|	返回date年月日中的日|
|Date(year,month,day)|	根据year，month，day返回Date字段|
|TO_DATE(str,format)	|如to_date(“1999-1-1”,”yyyy-MM-dd”)，这里的format是Java的DateFormat规范，跟SQL的不兼容|
|TO_CHAR(str,format)	|如to_char(date,”yyyy-MM-dd”)，这里的format是Java的DateFormat规范，跟SQL的不兼容|
|Dateadd(datepart,number,date)|	DATEADD函数需要3个参数,格式(参考SQL)：DATEADD(datepart,number,date),datepart可以为Year,Month,Day,Hour,Minute,Second|
|DATEDIF(start_date,end_date,unit)|	unit可以为Y,M,D|



### 字符串函数

- concat(str1,str2,str3)

  字符串拼接符，等价于str1+str2+str3

- contains(left, right)

  返回boolean，left是否包含right

- startsWith(left, right)

  返回boolean

- endsWith(left,right)

- lower(str)

  返回小写字符串

- upper(str)

  返回大写字符串

- len(str)

  返回字符串长度int
  
  <div STYLE="page-break-after: always;"></div>

###  聚合函数

适用于GroupBy的select中

| 类型         | 方法                                                         | 说明                                            | 其它                                        |
| :------------ |: ------------------------------------------------------------ |: ----------------------------------------------- |: ------------------------------------------- |
| 普通聚合函数 | sum(String field)<br/>sum(String expr, String alias)         | expr：表达式                                    |                                             |
| 普通聚合函数 | avg(String field)<br/>avg(String expr, String alias)         | expr：表达式                                    |                                             |
| 普通聚合函数 | max(String field)<br/>max(String expr, String alias)         | expr：表达式                                    |                                             |
| 普通聚合函数 | min(String field)<br/>min(String expr, String alias)         | expr：表达式                                    |                                             |
| 普通聚合函数 | count()<br/>count(String alias)                              | 等价于select count(1)等价于select(1)            | count不需要指定field，因为count(1)=count(*) |
| 特殊聚合函数 | maxP(String field, String propertyField)<br/>maxP(String expr, String propertyField,String alias) | 用field/expr计算最大行，结果取propertyField字段 |                                             |
| 特殊聚合函数 | minP(String field, String propertyField)<br/>minP(String expr, String propertyField, String alias) | 用field/expr计算最小行，结果取propertyField字段 |                                             |
| 控制         | finish()                                                     | 返回DataSet接口                                 |                                             |



### 特殊函数

- preRowValue()

  取上行本列值

- preRowValue("field")

  取上行字段field的值

  <div STYLE="page-break-after: always;"></div>

##  Algo注意事项

### 关闭DataSet

&ensp;&ensp;DataSet 经过多次转换后，会形成一棵引用关系树，如：
```java
DataSet c = a.union(b);
DataSet e = c.select(new String[]{“fid”,”fname”});
DataSet f = c.join(d,xxx).finish();
```
![DataSet树](image\08.png)

- 非叶子节点都是被引用的DataSet

- 每个DataSet节点都会消耗资源或者引用资源，close时会释放资源

- DataSet.close时，会自动close引用节点；所以，所有叶子节点close，会自动close整棵树

- 叶子节点必须close

- DataSet实现AutoCloseable，可以使用jdk7的try(resource){}语法， 更简洁的try{}finally{}

###  DataSet执行SQL注意事项
- 没有from table
- 目前还不支持join，hashjoin，union，请使用api方式
- 除了join，hashjoin，union，其他api都可以用sql查询替代
- group by和order by只支持字段，还不支持表达式和函数
- Sql函数不全，支持的表达式和函数请看后面文档，具体看文档
### copy注意事项
-  尽量少用copy，copy有成本，会保存数据在磁盘中
### Row访问注意事项
- Row是访问游标，不是数组，不能保存起来用

### 表达式
- 不能用表达式的地方: orderBy字段，groupBy字段，join中的on字段


