first commit
commit
bc43f9f1ca
@ -0,0 +1,23 @@
|
||||
/GFSData/
|
||||
/tablestoreConf.json
|
||||
/log/
|
||||
/*/target/
|
||||
/tablestore-grid-master/tableConf.json
|
||||
/tablestore-grid-master/tablestoreConf.json
|
||||
/tablestore-grid-master/out/
|
||||
|
||||
|
||||
### STS ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
.sts4-cache
|
||||
|
||||
### IntelliJ IDEA ###
|
||||
.idea
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
@ -0,0 +1,122 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.aliyun.tablestore</groupId>
|
||||
<artifactId>tablestore-grid</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>unidata-all</id>
|
||||
<name>Unidata All</name>
|
||||
<url>https://artifacts.unidata.ucar.edu/repository/unidata-all/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>edu.ucar</groupId>
|
||||
<artifactId>cdm-core</artifactId>
|
||||
<version>5.5.3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>edu.ucar</groupId>
|
||||
<artifactId>grib</artifactId>
|
||||
<version>5.5.3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.aliyun.openservices</groupId>
|
||||
<artifactId>tablestore</artifactId>
|
||||
<version>5.16.0</version>
|
||||
<classifier>jar-with-dependencies</classifier>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpasyncclient</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>2.11.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>3.12.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<version>1.4.12</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.18.30</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to
|
||||
parent pom) -->
|
||||
<plugins>
|
||||
<!-- clean lifecycle, see
|
||||
https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
|
||||
<plugin>
|
||||
<artifactId>maven-clean-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
</plugin>
|
||||
<!-- default lifecycle, jar packaging: see
|
||||
https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
|
||||
<plugin>
|
||||
<artifactId>maven-resources-plugin</artifactId>
|
||||
<version>3.0.2</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.8.0</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>2.22.1</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>3.0.2</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-install-plugin</artifactId>
|
||||
<version>2.5.2</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<version>2.8.2</version>
|
||||
</plugin>
|
||||
<!-- site lifecycle, see
|
||||
https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
|
||||
<plugin>
|
||||
<artifactId>maven-site-plugin</artifactId>
|
||||
<version>3.7.1</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-project-info-reports-plugin</artifactId>
|
||||
<version>3.0.0</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>8</source>
|
||||
<target>8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
@ -0,0 +1,54 @@
|
||||
package com.aliyun.tablestore.example.grid;
|
||||
|
||||
import com.alicloud.openservices.tablestore.model.search.FieldSchema;
|
||||
import com.alicloud.openservices.tablestore.model.search.FieldType;
|
||||
import com.alicloud.openservices.tablestore.model.search.IndexSchema;
|
||||
import com.aliyun.tablestore.example.grid.common.ExampleConfig;
|
||||
import com.aliyun.tablestore.example.grid.common.TableStoreGridExample;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* this example will create table and index.
|
||||
*/
|
||||
public class CreateStoreExample extends TableStoreGridExample {
|
||||
|
||||
public CreateStoreExample() {
|
||||
super(ExampleConfig.GRID_DATA_TABLE_NAME, ExampleConfig.GRID_META_TABLE_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
* we must create store before we can use it.
|
||||
* @throws Exception
|
||||
*/
|
||||
private void createStore() throws Exception {
|
||||
this.tableStoreGrid.createStore();
|
||||
}
|
||||
|
||||
/**
|
||||
* this example create an index which contains these columns: status, tag1, tag2, create_time.
|
||||
* you can create an index which contains any other columns.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
private void createIndex() throws Exception {
|
||||
IndexSchema indexSchema = new IndexSchema();
|
||||
indexSchema.setFieldSchemas(Arrays.asList(
|
||||
new FieldSchema("status", FieldType.KEYWORD).setIndex(true).setEnableSortAndAgg(true),
|
||||
new FieldSchema("tag1", FieldType.KEYWORD).setIndex(true).setEnableSortAndAgg(true),
|
||||
new FieldSchema("tag2", FieldType.KEYWORD).setIndex(true).setEnableSortAndAgg(true),
|
||||
new FieldSchema("create_time", FieldType.LONG).setIndex(true).setEnableSortAndAgg(true)
|
||||
));
|
||||
this.tableStoreGrid.createMetaIndex(ExampleConfig.GRID_META_INDEX_NAME, indexSchema);
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
CreateStoreExample example = new CreateStoreExample();
|
||||
try {
|
||||
example.createStore();
|
||||
example.createIndex();
|
||||
} finally {
|
||||
example.close();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
package com.aliyun.tablestore.example.grid;
|
||||
|
||||
import com.aliyun.tablestore.example.grid.common.ExampleConfig;
|
||||
import com.aliyun.tablestore.example.grid.common.TableStoreGridExample;
|
||||
import com.aliyun.tablestore.grid.GridDataFetcher;
|
||||
import com.aliyun.tablestore.grid.model.grid.Grid4D;
|
||||
import ucar.ma2.Array;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
||||
public class DataFetchExample extends TableStoreGridExample {
|
||||
|
||||
public DataFetchExample() {
|
||||
super(ExampleConfig.GRID_DATA_TABLE_NAME, ExampleConfig.GRID_META_TABLE_NAME);
|
||||
}
|
||||
|
||||
public Array queryByTableStore(String dataSetId, String variable, int[] origin, int[] shape) throws Exception {
|
||||
GridDataFetcher fetcher = this.tableStoreGrid.getDataFetcher(this.tableStoreGrid.getDataSetMeta(dataSetId));
|
||||
fetcher.setVariablesToGet(Collections.singletonList(variable));
|
||||
fetcher.setOriginShape(origin, shape);
|
||||
Grid4D grid4D = fetcher.fetch().getVariable(variable);
|
||||
return grid4D.toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* get a plane.
|
||||
* @throws Exception
|
||||
*/
|
||||
public void fetch1() throws Exception {
|
||||
int[] origin = new int[] {0, 0, 0, 0};
|
||||
int[] shape = new int[] {1, 1, ExampleConfig.EXAMPLE_GRID_DATA_SHAPE[2], ExampleConfig.EXAMPLE_GRID_DATA_SHAPE[3]};
|
||||
Array array = queryByTableStore(ExampleConfig.EXAMPLE_GRID_DATA_SET_ID,
|
||||
ExampleConfig.EXAMPLE_GRID_DATA_VARIABLE,
|
||||
origin, shape);
|
||||
System.out.println("Shape: " + array.shapeToString());
|
||||
System.out.println("Data: " + array);
|
||||
}
|
||||
|
||||
/**
|
||||
* get an sequence of point with different levels.
|
||||
* @throws Exception
|
||||
*/
|
||||
public void fetch2() throws Exception {
|
||||
int[] origin = new int[] {0, 0, 0, 0};
|
||||
int[] shape = new int[] {1, ExampleConfig.EXAMPLE_GRID_DATA_SHAPE[1], 1, 1};
|
||||
Array array = queryByTableStore(ExampleConfig.EXAMPLE_GRID_DATA_SET_ID,
|
||||
ExampleConfig.EXAMPLE_GRID_DATA_VARIABLE,
|
||||
origin, shape);
|
||||
System.out.println("Shape:" + array.shapeToString());
|
||||
System.out.println("Data:" + array);
|
||||
}
|
||||
|
||||
/**
|
||||
* get arbitrary 4-dimension data.
|
||||
* @throws Exception
|
||||
*/
|
||||
public void fetch3() throws Exception {
|
||||
int[] origin = new int[] {2, 5, 10, 10};
|
||||
int[] shape = new int[] {3, 10, 30, 30};
|
||||
Array array = queryByTableStore(ExampleConfig.EXAMPLE_GRID_DATA_SET_ID,
|
||||
ExampleConfig.EXAMPLE_GRID_DATA_VARIABLE,
|
||||
origin, shape);
|
||||
System.out.println("Shape:" + array.shapeToString());
|
||||
System.out.println("Data:" + array);
|
||||
}
|
||||
|
||||
public void run() throws Exception {
|
||||
fetch1();
|
||||
fetch2();
|
||||
fetch3();
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
DataFetchExample example = new DataFetchExample();
|
||||
try {
|
||||
example.run();
|
||||
} finally {
|
||||
example.close();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,110 @@
|
||||
package com.aliyun.tablestore.example.grid;
|
||||
|
||||
import com.aliyun.tablestore.example.grid.common.ExampleConfig;
|
||||
import com.aliyun.tablestore.example.grid.common.TableStoreGridExample;
|
||||
import com.aliyun.tablestore.grid.GridDataWriter;
|
||||
import com.aliyun.tablestore.grid.model.GridDataSetMeta;
|
||||
import com.aliyun.tablestore.grid.model.StoreOptions;
|
||||
import com.aliyun.tablestore.grid.model.grid.Grid2D;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import ucar.ma2.Array;
|
||||
import ucar.ma2.DataType;
|
||||
import ucar.nc2.NetcdfFile;
|
||||
import ucar.nc2.Variable;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
public class DataImportExample extends TableStoreGridExample {
|
||||
|
||||
public DataImportExample() {
|
||||
super(ExampleConfig.GRID_DATA_TABLE_NAME, ExampleConfig.GRID_META_TABLE_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
* init meta data to table store.
|
||||
* @param dataSetID
|
||||
* @param dataType
|
||||
* @param variables
|
||||
* @param shape
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public GridDataSetMeta initMeta(String dataSetID, DataType dataType, List<String> variables, int[] shape) throws Exception {
|
||||
GridDataSetMeta meta = new GridDataSetMeta(
|
||||
dataSetID,
|
||||
dataType,
|
||||
variables,
|
||||
shape[0],
|
||||
shape[1],
|
||||
shape[2],
|
||||
shape[3],
|
||||
new StoreOptions(StoreOptions.StoreType.SLICE));
|
||||
meta.addAttribute("status", "INIT");
|
||||
meta.addAttribute("create_time", System.currentTimeMillis());
|
||||
tableStoreGrid.putDataSetMeta(meta);
|
||||
return meta;
|
||||
}
|
||||
|
||||
/**
|
||||
* update meta and set status to DONE when data import finished.
|
||||
* @param meta
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public GridDataSetMeta updateMeta(GridDataSetMeta meta) throws Exception {
|
||||
meta.addAttribute("status", "DONE");
|
||||
tableStoreGrid.updateDataSetMeta(meta);
|
||||
return meta;
|
||||
}
|
||||
|
||||
/**
|
||||
* read data from netcdf file and write data to table store.
|
||||
* @param meta
|
||||
* @param ncFileName
|
||||
* @throws Exception
|
||||
*/
|
||||
public void importFromNcFile(GridDataSetMeta meta, String ncFileName) throws Exception {
|
||||
GridDataWriter writer = tableStoreGrid.getDataWriter(meta);
|
||||
NetcdfFile ncFile = NetcdfFile.open(ncFileName);
|
||||
List<Variable> variables = ncFile.getVariables();
|
||||
|
||||
for (Variable variable : variables) {
|
||||
if (meta.getVariables().contains(variable.getShortName())) {
|
||||
for (int t = 0; t < meta.gettSize(); t++) {
|
||||
for (int z = 0; z < meta.getzSize(); z++) {
|
||||
Array array = variable.read(new int[]{t, z, 0, 0}, new int[]{1, 1, meta.getxSize(), meta.getySize()});
|
||||
Grid2D grid2D = new Grid2D(array.getDataAsByteBuffer(), variable.getDataType(),
|
||||
new int[] {0, 0}, new int[] {meta.getxSize(), meta.getySize()});
|
||||
writer.writeGrid2D(variable.getShortName(), t, z, grid2D);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void run() throws Exception {
|
||||
String dataSetId = ExampleConfig.EXAMPLE_GRID_DATA_SET_ID;
|
||||
String filePath = ExampleConfig.EXAMPLE_GRID_DATA_SET_NC_FILE_PATH;
|
||||
String variable = ExampleConfig.EXAMPLE_GRID_DATA_VARIABLE;
|
||||
int[] shape = ExampleConfig.EXAMPLE_GRID_DATA_SHAPE;
|
||||
DataType dataType = ExampleConfig.EXAMPLE_GRID_DATA_TYPE;
|
||||
|
||||
GridDataSetMeta meta = initMeta(dataSetId, dataType, Collections.singletonList(variable), shape);
|
||||
importFromNcFile(meta, filePath);
|
||||
updateMeta(meta);
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
DataImportExample example = new DataImportExample();
|
||||
try {
|
||||
log.info("导入数据");
|
||||
example.run();
|
||||
} finally {
|
||||
example.close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
package com.aliyun.tablestore.example.grid;
|
||||
|
||||
import com.alicloud.openservices.tablestore.model.search.sort.FieldSort;
|
||||
import com.alicloud.openservices.tablestore.model.search.sort.Sort;
|
||||
import com.alicloud.openservices.tablestore.model.search.sort.SortOrder;
|
||||
import com.aliyun.tablestore.example.grid.common.ExampleConfig;
|
||||
import com.aliyun.tablestore.example.grid.common.TableStoreGridExample;
|
||||
import com.aliyun.tablestore.grid.core.QueryBuilder;
|
||||
import com.aliyun.tablestore.grid.model.GridDataSetMeta;
|
||||
import com.aliyun.tablestore.grid.model.QueryGridDataSetResult;
|
||||
import com.aliyun.tablestore.grid.model.QueryParams;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
public class MetaDeleteExample extends TableStoreGridExample {
|
||||
public MetaDeleteExample() {
|
||||
super(ExampleConfig.GRID_DATA_TABLE_NAME, ExampleConfig.GRID_META_TABLE_NAME);
|
||||
}
|
||||
|
||||
private List<GridDataSetMeta> query() throws Exception {
|
||||
QueryGridDataSetResult result = tableStoreGrid.queryDataSets(
|
||||
ExampleConfig.GRID_META_INDEX_NAME,
|
||||
QueryBuilder.or()
|
||||
.equal("status", "DONE")
|
||||
.equal("status", "INIT")
|
||||
.build(),
|
||||
new QueryParams(0, 1000, new Sort(Collections.singletonList(new FieldSort("create_time", SortOrder.DESC)))));
|
||||
|
||||
return result.getGridDataSetMetas();
|
||||
}
|
||||
|
||||
private void batchDeleteRow() throws Exception {
|
||||
List<GridDataSetMeta> metaList = query();
|
||||
while (!metaList.isEmpty()) {
|
||||
for (GridDataSetMeta meta : metaList) {
|
||||
// 获取行的主键
|
||||
String gridDataSetId = meta.getGridDataSetId();
|
||||
if (!"test_echam_spectral_example".equals(gridDataSetId)) {
|
||||
log.info("删除行:{}", gridDataSetId);
|
||||
tableStoreGrid.deleteDataSetMeta(gridDataSetId);
|
||||
}
|
||||
}
|
||||
metaList = query();
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
MetaDeleteExample example = new MetaDeleteExample();
|
||||
try {
|
||||
example.batchDeleteRow();
|
||||
} finally {
|
||||
example.close();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,116 @@
|
||||
package com.aliyun.tablestore.example.grid;
|
||||
|
||||
import com.alicloud.openservices.tablestore.model.search.sort.FieldSort;
|
||||
import com.alicloud.openservices.tablestore.model.search.sort.Sort;
|
||||
import com.alicloud.openservices.tablestore.model.search.sort.SortOrder;
|
||||
import com.aliyun.tablestore.example.grid.common.ExampleConfig;
|
||||
import com.aliyun.tablestore.example.grid.common.TableStoreGridExample;
|
||||
import com.aliyun.tablestore.grid.core.QueryBuilder;
|
||||
import com.aliyun.tablestore.grid.model.GridDataSetMeta;
|
||||
import com.aliyun.tablestore.grid.model.QueryGridDataSetResult;
|
||||
import com.aliyun.tablestore.grid.model.QueryParams;
|
||||
import com.aliyun.tablestore.grid.model.StoreOptions;
|
||||
import ucar.ma2.DataType;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class MetaQueryExample extends TableStoreGridExample {
|
||||
|
||||
public MetaQueryExample() {
|
||||
super(ExampleConfig.GRID_DATA_TABLE_NAME, ExampleConfig.GRID_META_TABLE_NAME);
|
||||
}
|
||||
|
||||
private GridDataSetMeta initMeta(String uniqueKey, DataType dataType, List<String> variables, int[] shape, Map<String, Object> attributes) throws Exception {
|
||||
GridDataSetMeta meta = new GridDataSetMeta(
|
||||
uniqueKey,
|
||||
dataType,
|
||||
variables,
|
||||
shape[0],
|
||||
shape[1],
|
||||
shape[2],
|
||||
shape[3],
|
||||
new StoreOptions(StoreOptions.StoreType.SLICE));
|
||||
meta.setAttributes(attributes);
|
||||
tableStoreGrid.putDataSetMeta(meta);
|
||||
return meta;
|
||||
}
|
||||
|
||||
/**
|
||||
* write some metas to table store for test.
|
||||
* @throws Exception
|
||||
*/
|
||||
private void prepareMetas() throws Exception {
|
||||
for (String tagA : Arrays.asList("A", "B", "C")) {
|
||||
for (String tagB : Arrays.asList("X", "Y", "Z")) {
|
||||
for (int i = 0; i < 10; i++) {
|
||||
String dataSetId = UUID.randomUUID().toString();
|
||||
Map<String, Object> objectMap = new HashMap<String, Object>();
|
||||
objectMap.put("create_time", System.currentTimeMillis());
|
||||
objectMap.put("tag1", tagA);
|
||||
objectMap.put("tag2", tagB);
|
||||
objectMap.put("status", ((i % 2) == 0)?"INIT":"DONE");
|
||||
initMeta(dataSetId, DataType.FLOAT, Collections.singletonList("var"), new int[]{1, 1, 1, 1}, objectMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* query by arbitrary combination conditions.
|
||||
* @throws Exception
|
||||
*/
|
||||
private void query() throws Exception {
|
||||
/**
|
||||
* query condition : (status == DONE) and (create_time > System.currentTimeMillis - 86400000) and (tag1 == A or tag2 == X)
|
||||
* sort by create_time, desc.
|
||||
*/
|
||||
QueryGridDataSetResult result = tableStoreGrid.queryDataSets(
|
||||
ExampleConfig.GRID_META_INDEX_NAME,
|
||||
QueryBuilder.and()
|
||||
.equal("status", "DONE")
|
||||
.greaterThan("create_time", System.currentTimeMillis() - 86400000)
|
||||
// .equal("accuracy", "1km")
|
||||
.query(QueryBuilder.or()
|
||||
.equal("tag1", "A")
|
||||
.equal("tag2", "X")
|
||||
// .equal("source", "ECMWF")
|
||||
// .equal("source", "NMC")
|
||||
.build())
|
||||
.build(),
|
||||
new QueryParams(0, 10, new Sort(Collections.singletonList(new FieldSort("create_time", SortOrder.DESC)))));
|
||||
|
||||
System.out.println("GetMetaCount: " + result.getGridDataSetMetas().size());
|
||||
for (GridDataSetMeta meta : result.getGridDataSetMetas()) {
|
||||
System.out.println("Meta: " + meta.getGridDataSetId());
|
||||
System.out.println(meta.getAttributes());
|
||||
}
|
||||
}
|
||||
private void query1() throws Exception {
|
||||
/**
|
||||
* query condition : (status == DONE) and (create_time > System.currentTimeMillis - 86400000) and (tag1 == A or tag2 == X)
|
||||
* sort by create_time, desc.
|
||||
*/
|
||||
QueryGridDataSetResult result = tableStoreGrid.queryDataSets(
|
||||
"gfs_meta_table_index",
|
||||
QueryBuilder.and()
|
||||
.equal("status", "DONE")
|
||||
.greaterThanEqual("reference_time", 1684368800000L)
|
||||
.build(),
|
||||
new QueryParams(0, 10, new Sort(Collections.singletonList(new FieldSort("create_time", SortOrder.DESC)))));
|
||||
|
||||
System.out.println("GetMetaCount: " + result.getGridDataSetMetas().size());
|
||||
for (GridDataSetMeta meta : result.getGridDataSetMetas()) {
|
||||
System.out.println("Meta: " + meta.getGridDataSetId());
|
||||
System.out.println(meta.getAttributes());
|
||||
}
|
||||
}
|
||||
public static void main(String[] args) throws Exception {
|
||||
MetaQueryExample example = new MetaQueryExample();
|
||||
try {
|
||||
System.out.println("Query...");
|
||||
example.query1();
|
||||
} finally {
|
||||
example.close();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
package com.aliyun.tablestore.example.grid.common;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStream;
|
||||
|
||||
|
||||
|
||||
public class TableStoreConf {
|
||||
|
||||
private String endpoint;
|
||||
private String accessId;
|
||||
private String accessKey;
|
||||
private String instanceName;
|
||||
|
||||
/**
|
||||
* 从目标配置文件中读取 数据库instance相关信息
|
||||
*/
|
||||
public static TableStoreConf newInstance(String path) {
|
||||
try {
|
||||
InputStream f = new FileInputStream(path);
|
||||
Gson gson = new Gson();
|
||||
return gson.fromJson(IOUtils.toString(f), TableStoreConf.class);
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public String getEndpoint() {
|
||||
return endpoint;
|
||||
}
|
||||
|
||||
public void setEndpoint(String endpoint) {
|
||||
this.endpoint = endpoint;
|
||||
}
|
||||
|
||||
public String getAccessId() {
|
||||
return accessId;
|
||||
}
|
||||
|
||||
public void setAccessId(String accessId) {
|
||||
this.accessId = accessId;
|
||||
}
|
||||
|
||||
public String getAccessKey() {
|
||||
return accessKey;
|
||||
}
|
||||
|
||||
public void setAccessKey(String accessKey) {
|
||||
this.accessKey = accessKey;
|
||||
}
|
||||
|
||||
public String getInstanceName() {
|
||||
return instanceName;
|
||||
}
|
||||
|
||||
public void setInstanceName(String instanceName) {
|
||||
this.instanceName = instanceName;
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package com.aliyun.tablestore.example.grid.common;
|
||||
|
||||
import com.aliyun.tablestore.grid.TableStoreGrid;
|
||||
import com.aliyun.tablestore.grid.TableStoreGridConfig;
|
||||
|
||||
public abstract class TableStoreGridExample {
|
||||
|
||||
protected TableStoreGrid tableStoreGrid;
|
||||
// private String pathSeperator = "/";
|
||||
|
||||
public TableStoreGridExample(String dataTableName, String metaTableName) {
|
||||
// String os = System.getProperty("os.name");
|
||||
// if (os.toLowerCase().startsWith("win")) {
|
||||
// pathSeparator = "\\";
|
||||
// }
|
||||
String pathSeparator = System.getProperty("file.separator");
|
||||
TableStoreConf conf = TableStoreConf.newInstance(System.getProperty("user.dir") + pathSeparator + "tablestoreConf.json");
|
||||
TableStoreGridConfig config = new TableStoreGridConfig();
|
||||
config.setTableStoreEndpoint(conf.getEndpoint());
|
||||
config.setAccessId(conf.getAccessId());
|
||||
config.setAccessKey(conf.getAccessKey());
|
||||
config.setTableStoreInstance(conf.getInstanceName());
|
||||
config.setDataTableName(dataTableName);
|
||||
config.setMetaTableName(metaTableName);
|
||||
tableStoreGrid = new TableStoreGrid(config);
|
||||
}
|
||||
|
||||
public void close() {
|
||||
if (tableStoreGrid != null) {
|
||||
tableStoreGrid.close();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package com.aliyun.tablestore.grid;
|
||||
|
||||
import com.aliyun.tablestore.grid.model.grid.Grid2D;
|
||||
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
public interface GridDataDeleter {
|
||||
|
||||
void delete(String dataSetId) throws ExecutionException, InterruptedException;
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
package com.aliyun.tablestore.grid;
|
||||
|
||||
import com.aliyun.tablestore.grid.model.GridDataSet;
|
||||
import com.aliyun.tablestore.grid.model.grid.Range;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public interface GridDataFetcher {
|
||||
|
||||
/**
|
||||
* 设置要查询的变量。
|
||||
* @param variables
|
||||
* @return
|
||||
*/
|
||||
GridDataFetcher setVariablesToGet(Collection<String> variables);
|
||||
|
||||
/**
|
||||
* 设置要读取的各维度起始点和大小。
|
||||
* @param origin 各维度起始点。
|
||||
* @param shape 各维度大小。
|
||||
* @return
|
||||
*/
|
||||
GridDataFetcher setOriginShape(int[] origin, int[] shape);
|
||||
|
||||
/**
|
||||
* 获取数据。
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
GridDataSet fetch() throws Exception;
|
||||
|
||||
GridDataFetcher setT(int t);
|
||||
|
||||
GridDataFetcher setTRange(Range tRange);
|
||||
|
||||
GridDataFetcher setZ(int z);
|
||||
|
||||
GridDataFetcher setZRange(Range zRange);
|
||||
|
||||
GridDataFetcher setX(int x);
|
||||
|
||||
GridDataFetcher setXRange(Range xRange);
|
||||
|
||||
GridDataFetcher setY(int y);
|
||||
|
||||
GridDataFetcher setYRange(Range yRange);
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package com.aliyun.tablestore.grid;
|
||||
|
||||
import com.aliyun.tablestore.grid.model.grid.Grid2D;
|
||||
|
||||
public interface GridDataWriter {
|
||||
/**
|
||||
* 写入一个二维平面。
|
||||
* @param variable 变量名。
|
||||
* @param t 时间维的值。
|
||||
* @param z 高度维的值。
|
||||
* @param grid2D 平面数据。
|
||||
* @throws Exception
|
||||
*/
|
||||
void writeGrid2D(String variable, int t, int z, Grid2D grid2D) throws Exception;
|
||||
}
|
@ -0,0 +1,191 @@
|
||||
package com.aliyun.tablestore.grid;
|
||||
|
||||
import com.alicloud.openservices.tablestore.*;
|
||||
import com.alicloud.openservices.tablestore.core.ErrorCode;
|
||||
import com.alicloud.openservices.tablestore.model.GetRowResponse;
|
||||
import com.alicloud.openservices.tablestore.model.Row;
|
||||
import com.alicloud.openservices.tablestore.model.TableOptions;
|
||||
import com.alicloud.openservices.tablestore.model.UpdateTableRequest;
|
||||
import com.alicloud.openservices.tablestore.model.search.CreateSearchIndexRequest;
|
||||
import com.alicloud.openservices.tablestore.model.search.IndexSchema;
|
||||
import com.alicloud.openservices.tablestore.model.search.SearchResponse;
|
||||
import com.alicloud.openservices.tablestore.model.search.query.Query;
|
||||
import com.alicloud.openservices.tablestore.writer.WriterConfig;
|
||||
import com.aliyun.tablestore.grid.core.TableStoreDataDeleter;
|
||||
import com.aliyun.tablestore.grid.core.RequestBuilder;
|
||||
import com.aliyun.tablestore.grid.core.RowParser;
|
||||
import com.aliyun.tablestore.grid.core.TableStoreDataFetcher;
|
||||
import com.aliyun.tablestore.grid.core.TableStoreDataWriter;
|
||||
import com.aliyun.tablestore.grid.model.GridDataSetMeta;
|
||||
import com.aliyun.tablestore.grid.model.QueryGridDataSetResult;
|
||||
import com.aliyun.tablestore.grid.model.QueryParams;
|
||||
import ucar.nc2.ft.point.standard.TableConfig;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class TableStoreGrid implements GridStore {
|
||||
|
||||
private final TableStoreGridConfig config;
|
||||
private final AsyncClientInterface asyncClient;
|
||||
private ExecutorService writerExecutor;
|
||||
private TableStoreWriter writer;
|
||||
private TableOptions tableOptions;
|
||||
|
||||
public TableStoreGrid(TableStoreGridConfig config) {
|
||||
this.config = config;
|
||||
this.asyncClient = new AsyncClient(config.getTableStoreEndpoint(),
|
||||
config.getAccessId(), config.getAccessKey(),
|
||||
config.getTableStoreInstance());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createStore() throws Exception {
|
||||
this.tableOptions = new TableOptions(-1, 1);
|
||||
createStore(tableOptions);
|
||||
}
|
||||
@Override
|
||||
public void createStore(TableOptions tableOptions) throws Exception {
|
||||
// create meta table
|
||||
try {
|
||||
this.tableOptions = tableOptions;
|
||||
this.asyncClient.createTable(RequestBuilder.buildCreateMetaTableRequest(config.getMetaTableName(), tableOptions), null).get();
|
||||
} catch (TableStoreException ex) {
|
||||
if (!ex.getErrorCode().equals(ErrorCode.OBJECT_ALREADY_EXIST)) {
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
// create buffer table
|
||||
try {
|
||||
tableOptions.setAllowUpdate(false); // 禁止update操作
|
||||
this.asyncClient.createTable(RequestBuilder.buildCreateDataTableRequest(config.getDataTableName(), tableOptions), null).get();
|
||||
} catch (TableStoreException ex) {
|
||||
if (!ex.getErrorCode().equals(ErrorCode.OBJECT_ALREADY_EXIST)) {
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新表设置
|
||||
* @param tableOptionsForUpdate
|
||||
* @throws Exception
|
||||
*/
|
||||
public void updateStoreOption(TableOptions tableOptionsForUpdate) throws Exception {
|
||||
// create meta table
|
||||
try {
|
||||
UpdateTableRequest metaUpdate = new UpdateTableRequest(config.getMetaTableName());
|
||||
metaUpdate.setTableOptionsForUpdate(tableOptionsForUpdate);
|
||||
this.asyncClient.updateTable(metaUpdate, null).get();
|
||||
} catch (TableStoreException ex) {
|
||||
if (!ex.getErrorCode().equals(ErrorCode.OBJECT_ALREADY_EXIST)) {
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
// create buffer table
|
||||
try {
|
||||
UpdateTableRequest dataUpdate = new UpdateTableRequest(config.getDataTableName());
|
||||
dataUpdate.setTableOptionsForUpdate(tableOptionsForUpdate);
|
||||
this.asyncClient.updateTable(dataUpdate, null).get();
|
||||
} catch (TableStoreException ex) {
|
||||
if (!ex.getErrorCode().equals(ErrorCode.OBJECT_ALREADY_EXIST)) {
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void putDataSetMeta(GridDataSetMeta meta) throws Exception {
|
||||
this.asyncClient.putRow(
|
||||
RequestBuilder.buildPutMetaRequest(config.getMetaTableName(), meta), null).get();
|
||||
}
|
||||
|
||||
public void deleteDataSetMeta(String uniqueKey) throws Exception {
|
||||
this.asyncClient.deleteRow(
|
||||
RequestBuilder.buildDeleteMetaRequest(config.getMetaTableName(), uniqueKey),
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateDataSetMeta(GridDataSetMeta meta) throws Exception {
|
||||
this.asyncClient.updateRow(
|
||||
RequestBuilder.buildUpdateMetaRequest(config.getMetaTableName(), meta), null).get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public GridDataSetMeta getDataSetMeta(String gridDataSetId) throws Exception {
|
||||
GetRowResponse getRowResponse = this.asyncClient.getRow(
|
||||
RequestBuilder.buildGetMetaRequest(config.getMetaTableName(), gridDataSetId), null).get();
|
||||
if (getRowResponse.getRow() == null) {
|
||||
return null;
|
||||
}
|
||||
return RowParser.parseMetaFromRow(getRowResponse.getRow());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createMetaIndex(String indexName, IndexSchema indexSchema) throws Exception {
|
||||
CreateSearchIndexRequest request = new CreateSearchIndexRequest();
|
||||
request.setTableName(config.getMetaTableName());
|
||||
request.setIndexName(indexName);
|
||||
request.setIndexSchema(indexSchema);
|
||||
request.setTimeToLive(tableOptions.getTimeToLive(), TimeUnit.SECONDS);
|
||||
this.asyncClient.createSearchIndex(request, null).get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryGridDataSetResult queryDataSets(String indexName, Query query, QueryParams queryParams) throws Exception {
|
||||
SearchResponse searchResponse = this.asyncClient.search(
|
||||
RequestBuilder.buildSearchRequest(config.getMetaTableName(), indexName, query, queryParams),
|
||||
null).get();
|
||||
List<GridDataSetMeta> metaList = new ArrayList<GridDataSetMeta>();
|
||||
for (Row row : searchResponse.getRows()) {
|
||||
metaList.add(RowParser.parseMetaFromRow(row));
|
||||
}
|
||||
QueryGridDataSetResult result = new QueryGridDataSetResult();
|
||||
result.setGridDataSetMetas(metaList);
|
||||
result.setAllSuccess(searchResponse.isAllSuccess());
|
||||
result.setNextToken(searchResponse.getNextToken());
|
||||
result.setTotalCount(searchResponse.getTotalCount());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GridDataWriter getDataWriter(GridDataSetMeta meta) {
|
||||
if (writer == null) {
|
||||
synchronized (this) {
|
||||
if (writer == null) {
|
||||
this.writerExecutor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
|
||||
this.writer = new DefaultTableStoreWriter(this.asyncClient, config.getDataTableName(), new WriterConfig(), null, this.writerExecutor);
|
||||
}
|
||||
}
|
||||
}
|
||||
return new TableStoreDataWriter(writer, config.getDataTableName(), meta);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GridDataFetcher getDataFetcher(GridDataSetMeta meta) {
|
||||
return new TableStoreDataFetcher(asyncClient, config.getDataTableName(), meta, config.getDataSizeLimitForFetch());
|
||||
}
|
||||
|
||||
public GridDataDeleter getDataDeleter(GridDataSetMeta meta) {
|
||||
return new TableStoreDataDeleter(asyncClient, config.getDataTableName(), meta);
|
||||
}
|
||||
@Override
|
||||
public synchronized void close() {
|
||||
if (writer != null) {
|
||||
this.writer.close();
|
||||
this.writerExecutor.shutdown();
|
||||
}
|
||||
this.asyncClient.shutdown();
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
package com.aliyun.tablestore.grid;
|
||||
|
||||
public class TableStoreGridConfig {
|
||||
|
||||
private String tableStoreEndpoint;
|
||||
private String accessId;
|
||||
private String accessKey;
|
||||
private String tableStoreInstance;
|
||||
|
||||
private String metaTableName;
|
||||
private String dataTableName;
|
||||
|
||||
private long dataSizeLimitForFetch = 20 * 1024 * 1024;
|
||||
|
||||
public String getTableStoreEndpoint() {
|
||||
return tableStoreEndpoint;
|
||||
}
|
||||
|
||||
public void setTableStoreEndpoint(String tableStoreEndpoint) {
|
||||
this.tableStoreEndpoint = tableStoreEndpoint;
|
||||
}
|
||||
|
||||
public String getAccessId() {
|
||||
return accessId;
|
||||
}
|
||||
|
||||
public void setAccessId(String accessId) {
|
||||
this.accessId = accessId;
|
||||
}
|
||||
|
||||
public String getAccessKey() {
|
||||
return accessKey;
|
||||
}
|
||||
|
||||
public void setAccessKey(String accessKey) {
|
||||
this.accessKey = accessKey;
|
||||
}
|
||||
|
||||
public String getTableStoreInstance() {
|
||||
return tableStoreInstance;
|
||||
}
|
||||
|
||||
public void setTableStoreInstance(String tableStoreInstance) {
|
||||
this.tableStoreInstance = tableStoreInstance;
|
||||
}
|
||||
|
||||
public String getMetaTableName() {
|
||||
return metaTableName;
|
||||
}
|
||||
|
||||
public void setMetaTableName(String metaTableName) {
|
||||
this.metaTableName = metaTableName;
|
||||
}
|
||||
|
||||
public String getDataTableName() {
|
||||
return dataTableName;
|
||||
}
|
||||
|
||||
public void setDataTableName(String dataTableName) {
|
||||
this.dataTableName = dataTableName;
|
||||
}
|
||||
|
||||
public long getDataSizeLimitForFetch() {
|
||||
return dataSizeLimitForFetch;
|
||||
}
|
||||
|
||||
public void setDataSizeLimitForFetch(long dataSizeLimitForFetch) {
|
||||
this.dataSizeLimitForFetch = dataSizeLimitForFetch;
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
package com.aliyun.tablestore.grid.consts;
|
||||
|
||||
/**
|
||||
* @Author : shiyi
|
||||
* @Date : 2024/5/8 15:27
|
||||
* @Description : meta表属性枚举
|
||||
*/
|
||||
public enum AttributionEnum {
|
||||
//
|
||||
STATUS("status", "导入状态"),
|
||||
CREATE_TIME("create_time", "创建时间"),
|
||||
REFERENCE_TIME("reference_time", "起报时间"),
|
||||
;
|
||||
public String name;
|
||||
|
||||
public String info;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getInfo() {
|
||||
return info;
|
||||
}
|
||||
AttributionEnum(String name, String info) {
|
||||
this.name = name;
|
||||
this.info = info;
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package com.aliyun.tablestore.grid.consts;
|
||||
|
||||
|
||||
public class Constants {
|
||||
|
||||
public static String GRID_DATA_SET_ID_PK_NAME = "_id";
|
||||
public static String VARIABLE_PK_NAME = "_variable";
|
||||
public static String T_PK_NAME = "_t";
|
||||
public static String Z_PK_NAME = "_z";
|
||||
|
||||
public static String DATA_TYPE_COL_NAME = "_data_type";
|
||||
public static String VARIABLE_LIST_COL_NAME = "_variable_list";
|
||||
public static String T_SIZE_COL_NAME = "_t_size";
|
||||
public static String Z_SIZE_COL_NAME = "_z_size";
|
||||
public static String X_SIZE_COL_NAME = "_x_size";
|
||||
public static String Y_SIZE_COL_NAME = "_y_size";
|
||||
public static String STORE_TYPE_COL_NAME = "_store_type";
|
||||
public static String X_SPLIT_COUNT_COL_NAME = "_x_split_count";
|
||||
public static String Y_SPLIT_COUNT_COL_NAME = "_y_split_count";
|
||||
|
||||
public static String DATA_BLOCK_COL_NAME_PREFIX = "block_";
|
||||
public static String DATA_BLOCK_COL_NAME_FORMAT = "block_%s_%s";
|
||||
|
||||
public static String T_LIST_COL_NAME = "time_list"; // 1M
|
||||
public static int MAX_REQUEST_SIZE = 2 * 1024 * 1024;
|
||||
}
|
@ -0,0 +1,134 @@
|
||||
package com.aliyun.tablestore.grid.core;
|
||||
|
||||
import com.alicloud.openservices.tablestore.model.ColumnValue;
|
||||
import com.alicloud.openservices.tablestore.model.search.query.*;
|
||||
import com.aliyun.tablestore.grid.utils.ValueUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class QueryBuilder {
|
||||
|
||||
enum Operator {
|
||||
AND,
|
||||
OR
|
||||
}
|
||||
|
||||
private final Operator operator;
|
||||
private List<Query> filterQueries;
|
||||
private List<Query> shouldQueries;
|
||||
|
||||
QueryBuilder(Operator operator) {
|
||||
this.operator = operator;
|
||||
switch (operator) {
|
||||
case AND: {
|
||||
this.filterQueries = new ArrayList<Query>();
|
||||
break;
|
||||
}
|
||||
case OR: {
|
||||
this.shouldQueries = new ArrayList<Query>();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
public static QueryBuilder or() {
|
||||
return new QueryBuilder(Operator.OR);
|
||||
}
|
||||
|
||||
public static QueryBuilder and() {
|
||||
return new QueryBuilder(Operator.AND);
|
||||
}
|
||||
|
||||
public QueryBuilder equal(String columnName, Object... values) {
|
||||
TermsQuery termsQuery = new TermsQuery();
|
||||
termsQuery.setFieldName(columnName);
|
||||
List<ColumnValue> columnValues = new ArrayList<ColumnValue>();
|
||||
for (Object value : values) {
|
||||
columnValues.add(ValueUtil.toColumnValue(value));
|
||||
}
|
||||
termsQuery.setTerms(columnValues);
|
||||
return query(termsQuery);
|
||||
}
|
||||
|
||||
public QueryBuilder notEqual(String columnName, Object value) {
|
||||
TermQuery termQuery = new TermQuery();
|
||||
termQuery.setFieldName(columnName);
|
||||
termQuery.setTerm(ValueUtil.toColumnValue(value));
|
||||
BoolQuery boolQuery = new BoolQuery();
|
||||
boolQuery.setMustNotQueries(Collections.singletonList(termQuery));
|
||||
return query(boolQuery);
|
||||
}
|
||||
|
||||
public QueryBuilder greaterThan(String columnName, Object value) {
|
||||
RangeQuery rangeQuery = new RangeQuery();
|
||||
rangeQuery.setFieldName(columnName);
|
||||
rangeQuery.greaterThan(ValueUtil.toColumnValue(value));
|
||||
return query(rangeQuery);
|
||||
}
|
||||
|
||||
public QueryBuilder greaterThanEqual(String columnName, Object value) {
|
||||
RangeQuery rangeQuery = new RangeQuery();
|
||||
rangeQuery.setFieldName(columnName);
|
||||
rangeQuery.greaterThanOrEqual(ValueUtil.toColumnValue(value));
|
||||
return query(rangeQuery);
|
||||
}
|
||||
|
||||
public QueryBuilder lessThan(String columnName, Object value) {
|
||||
RangeQuery rangeQuery = new RangeQuery();
|
||||
rangeQuery.setFieldName(columnName);
|
||||
rangeQuery.lessThan(ValueUtil.toColumnValue(value));
|
||||
return query(rangeQuery);
|
||||
}
|
||||
|
||||
public QueryBuilder lessThanEqual(String columnName, Object value) {
|
||||
RangeQuery rangeQuery = new RangeQuery();
|
||||
rangeQuery.setFieldName(columnName);
|
||||
rangeQuery.lessThanOrEqual(ValueUtil.toColumnValue(value));
|
||||
return query(rangeQuery);
|
||||
}
|
||||
|
||||
public QueryBuilder prefix(String columnName, String prefix) {
|
||||
PrefixQuery prefixQuery = new PrefixQuery();
|
||||
prefixQuery.setFieldName(columnName);
|
||||
prefixQuery.setPrefix(prefix);
|
||||
return query(prefixQuery);
|
||||
}
|
||||
|
||||
public QueryBuilder query(Query query) {
|
||||
switch (operator) {
|
||||
case AND: {
|
||||
this.filterQueries.add(query);
|
||||
break;
|
||||
}
|
||||
case OR: {
|
||||
this.shouldQueries.add(query);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Query build() {
|
||||
switch (operator) {
|
||||
case AND: {
|
||||
BoolQuery boolQuery = new BoolQuery();
|
||||
boolQuery.setFilterQueries(filterQueries);
|
||||
return boolQuery;
|
||||
}
|
||||
case OR: {
|
||||
BoolQuery boolQuery = new BoolQuery();
|
||||
boolQuery.setShouldQueries(shouldQueries);
|
||||
return boolQuery;
|
||||
}
|
||||
default:
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,149 @@
|
||||
package com.aliyun.tablestore.grid.core;
|
||||
|
||||
import com.alicloud.openservices.tablestore.core.utils.StringUtils;
|
||||
import com.alicloud.openservices.tablestore.model.*;
|
||||
import com.alicloud.openservices.tablestore.model.search.SearchQuery;
|
||||
import com.alicloud.openservices.tablestore.model.search.SearchRequest;
|
||||
import com.alicloud.openservices.tablestore.model.search.query.Query;
|
||||
import com.aliyun.tablestore.grid.model.*;
|
||||
import com.aliyun.tablestore.grid.utils.ValueUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.aliyun.tablestore.grid.consts.Constants.*;
|
||||
|
||||
public class RequestBuilder {
|
||||
|
||||
public static CreateTableRequest buildCreateMetaTableRequest(String tableName, TableOptions tableOptions) {
|
||||
TableMeta meta = new TableMeta(tableName);
|
||||
meta.addPrimaryKeyColumn(new PrimaryKeySchema(GRID_DATA_SET_ID_PK_NAME, PrimaryKeyType.STRING));
|
||||
return new CreateTableRequest(meta, tableOptions);
|
||||
}
|
||||
|
||||
public static CreateTableRequest buildCreateDataTableRequest(String tableName, TableOptions tableOptions) {
|
||||
TableMeta meta = new TableMeta(tableName);
|
||||
meta.addPrimaryKeyColumn(new PrimaryKeySchema(GRID_DATA_SET_ID_PK_NAME, PrimaryKeyType.STRING));
|
||||
meta.addPrimaryKeyColumn(new PrimaryKeySchema(VARIABLE_PK_NAME, PrimaryKeyType.STRING));
|
||||
meta.addPrimaryKeyColumn(new PrimaryKeySchema(T_PK_NAME, PrimaryKeyType.INTEGER));
|
||||
meta.addPrimaryKeyColumn(new PrimaryKeySchema(Z_PK_NAME, PrimaryKeyType.INTEGER));
|
||||
return new CreateTableRequest(meta, tableOptions);
|
||||
}
|
||||
|
||||
private static List<Column> buildMetaColumns(GridDataSetMeta meta) {
|
||||
List<Column> columns = new ArrayList<Column>();
|
||||
columns.add(new Column(DATA_TYPE_COL_NAME, ColumnValue.fromString(meta.getDataType().toString())));
|
||||
columns.add(new Column(VARIABLE_LIST_COL_NAME, ColumnValue.fromString(StringUtils.join(",", meta.getVariables()))));
|
||||
columns.add(new Column(T_SIZE_COL_NAME, ColumnValue.fromLong(meta.gettSize())));
|
||||
columns.add(new Column(Z_SIZE_COL_NAME, ColumnValue.fromLong(meta.getzSize())));
|
||||
columns.add(new Column(X_SIZE_COL_NAME, ColumnValue.fromLong(meta.getxSize())));
|
||||
columns.add(new Column(Y_SIZE_COL_NAME, ColumnValue.fromLong(meta.getySize())));
|
||||
columns.add(new Column(STORE_TYPE_COL_NAME, ColumnValue.fromString(meta.getStoreOptions().getStoreType().name())));
|
||||
if (meta.getStoreOptions().getStoreType().equals(StoreOptions.StoreType.SLICE)) {
|
||||
columns.add(new Column(X_SPLIT_COUNT_COL_NAME, ColumnValue.fromLong(meta.getStoreOptions().getxSplitCount())));
|
||||
columns.add(new Column(Y_SPLIT_COUNT_COL_NAME, ColumnValue.fromLong(meta.getStoreOptions().getySplitCount())));
|
||||
}
|
||||
if (meta.getAttributes() != null) {
|
||||
for (Map.Entry<String, Object> entry : meta.getAttributes().entrySet()) {
|
||||
columns.add(new Column(entry.getKey(), ValueUtil.toColumnValue(entry.getValue())));
|
||||
}
|
||||
}
|
||||
if (meta.getForecastHours() != null) {
|
||||
columns.add(new Column(T_LIST_COL_NAME, ColumnValue.fromString(StringUtils.join(",", meta.getForecastHours()))));
|
||||
}
|
||||
return columns;
|
||||
}
|
||||
|
||||
public static PutRowRequest buildPutMetaRequest(String metaTableName, GridDataSetMeta meta) {
|
||||
PrimaryKeyBuilder builder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
|
||||
builder.addPrimaryKeyColumn(GRID_DATA_SET_ID_PK_NAME, PrimaryKeyValue.fromString(meta.getGridDataSetId()));
|
||||
PrimaryKey pk = builder.build();
|
||||
RowPutChange rowPutChange = new RowPutChange(metaTableName, pk);
|
||||
rowPutChange.addColumns(buildMetaColumns(meta));
|
||||
return new PutRowRequest(rowPutChange);
|
||||
}
|
||||
|
||||
public static UpdateRowRequest buildUpdateMetaRequest(String metaTableName, GridDataSetMeta meta) {
|
||||
PrimaryKeyBuilder builder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
|
||||
builder.addPrimaryKeyColumn(GRID_DATA_SET_ID_PK_NAME, PrimaryKeyValue.fromString(meta.getGridDataSetId()));
|
||||
PrimaryKey pk = builder.build();
|
||||
RowUpdateChange rowUpdateChange = new RowUpdateChange(metaTableName, pk);
|
||||
rowUpdateChange.put(buildMetaColumns(meta));
|
||||
return new UpdateRowRequest(rowUpdateChange);
|
||||
}
|
||||
|
||||
public static GetRowRequest buildGetMetaRequest(String metaTableName, String uniqueKey) {
|
||||
PrimaryKeyBuilder builder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
|
||||
builder.addPrimaryKeyColumn(GRID_DATA_SET_ID_PK_NAME, PrimaryKeyValue.fromString(uniqueKey));
|
||||
PrimaryKey pk = builder.build();
|
||||
SingleRowQueryCriteria criteria = new SingleRowQueryCriteria(metaTableName);
|
||||
criteria.setMaxVersions(1);
|
||||
criteria.setPrimaryKey(pk);
|
||||
GetRowRequest getRowRequest = new GetRowRequest();
|
||||
getRowRequest.setRowQueryCriteria(criteria);
|
||||
return getRowRequest;
|
||||
}
|
||||
|
||||
public static SearchRequest buildSearchRequest(String metaTableName, String indexName, Query query, QueryParams params) {
|
||||
SearchQuery searchQuery = new SearchQuery();
|
||||
searchQuery.setQuery(query);
|
||||
if (params.getOffset() != null) {
|
||||
searchQuery.setOffset(params.getOffset());
|
||||
}
|
||||
if (params.getLimit() != null) {
|
||||
searchQuery.setLimit(params.getLimit());
|
||||
}
|
||||
if (params.getSort() != null) {
|
||||
searchQuery.setSort(params.getSort());
|
||||
}
|
||||
if (params.getToken() != null) {
|
||||
searchQuery.setToken(params.getToken());
|
||||
}
|
||||
searchQuery.setGetTotalCount(params.isGetTotalCount());
|
||||
SearchRequest searchRequest = new SearchRequest(metaTableName, indexName, searchQuery);
|
||||
SearchRequest.ColumnsToGet columnsToGet = new SearchRequest.ColumnsToGet();
|
||||
columnsToGet.setReturnAll(true);
|
||||
searchRequest.setColumnsToGet(columnsToGet);
|
||||
return searchRequest;
|
||||
}
|
||||
|
||||
public static GetRowRequest buildGetDataRequest(GetDataParam getDataParam) {
|
||||
PrimaryKeyBuilder builder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
|
||||
builder.addPrimaryKeyColumn(GRID_DATA_SET_ID_PK_NAME, PrimaryKeyValue.fromString(getDataParam.getDataSetId()));
|
||||
builder.addPrimaryKeyColumn(VARIABLE_PK_NAME, PrimaryKeyValue.fromString(getDataParam.getVariable()));
|
||||
builder.addPrimaryKeyColumn(T_PK_NAME, PrimaryKeyValue.fromLong(getDataParam.getT()));
|
||||
builder.addPrimaryKeyColumn(Z_PK_NAME, PrimaryKeyValue.fromLong(getDataParam.getZ()));
|
||||
PrimaryKey pk = builder.build();
|
||||
|
||||
SingleRowQueryCriteria criteria = new SingleRowQueryCriteria(getDataParam.getDataTableName());
|
||||
criteria.setMaxVersions(1);
|
||||
criteria.setPrimaryKey(pk);
|
||||
if (getDataParam.getColumnsToGet() != null) {
|
||||
criteria.addColumnsToGet(getDataParam.getColumnsToGet());
|
||||
}
|
||||
return new GetRowRequest(criteria);
|
||||
}
|
||||
|
||||
public static DeleteRowRequest buildDeleteDataRequest(DeleteDataParam deleteDataParam) {
|
||||
PrimaryKeyBuilder builder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
|
||||
builder.addPrimaryKeyColumn(GRID_DATA_SET_ID_PK_NAME, PrimaryKeyValue.fromString(deleteDataParam.getDataSetId()));
|
||||
builder.addPrimaryKeyColumn(VARIABLE_PK_NAME, PrimaryKeyValue.fromString(deleteDataParam.getVariable()));
|
||||
builder.addPrimaryKeyColumn(T_PK_NAME, PrimaryKeyValue.fromLong(deleteDataParam.getT()));
|
||||
builder.addPrimaryKeyColumn(Z_PK_NAME, PrimaryKeyValue.fromLong(deleteDataParam.getZ()));
|
||||
PrimaryKey pk = builder.build();
|
||||
|
||||
RowDeleteChange rowDeleteChange = new RowDeleteChange(deleteDataParam.getDataTableName(), pk);
|
||||
return new DeleteRowRequest(rowDeleteChange);
|
||||
}
|
||||
public static DeleteRowRequest buildDeleteMetaRequest(String metaTableName, String uniqueKey) {
|
||||
PrimaryKeyBuilder builder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
|
||||
builder.addPrimaryKeyColumn(GRID_DATA_SET_ID_PK_NAME, PrimaryKeyValue.fromString(uniqueKey));
|
||||
PrimaryKey pk = builder.build();
|
||||
SingleRowQueryCriteria criteria = new SingleRowQueryCriteria(metaTableName);
|
||||
criteria.setMaxVersions(1);
|
||||
criteria.setPrimaryKey(pk);
|
||||
RowDeleteChange rowDeleteChange = new RowDeleteChange(metaTableName, pk);
|
||||
return new DeleteRowRequest(rowDeleteChange);
|
||||
}
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
package com.aliyun.tablestore.grid.core;
|
||||
|
||||
import com.alicloud.openservices.tablestore.model.Column;
|
||||
import com.alicloud.openservices.tablestore.model.Row;
|
||||
import com.aliyun.tablestore.grid.model.GridDataSetMeta;
|
||||
import com.aliyun.tablestore.grid.model.StoreOptions;
|
||||
import com.aliyun.tablestore.grid.model.grid.Grid2D;
|
||||
import com.aliyun.tablestore.grid.model.grid.Plane;
|
||||
import com.aliyun.tablestore.grid.model.grid.Range;
|
||||
import com.aliyun.tablestore.grid.utils.BlockUtil;
|
||||
import com.aliyun.tablestore.grid.utils.ValueUtil;
|
||||
import ucar.ma2.DataType;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.*;
|
||||
|
||||
import static com.aliyun.tablestore.grid.consts.Constants.*;
|
||||
|
||||
public class RowParser {
|
||||
|
||||
public static GridDataSetMeta parseMetaFromRow(Row row) {
|
||||
String uniqueKey = row.getPrimaryKey().getPrimaryKeyColumn(GRID_DATA_SET_ID_PK_NAME).getValue().asString();
|
||||
DataType dataType = DataType.getType(row.getColumn(DATA_TYPE_COL_NAME).get(0).getValue().asString());
|
||||
List<String> variables = Arrays.asList(row.getColumn(VARIABLE_LIST_COL_NAME).get(0).getValue().asString().split(","));
|
||||
int tSize = (int) row.getColumn(T_SIZE_COL_NAME).get(0).getValue().asLong();
|
||||
int zSize = (int) row.getColumn(Z_SIZE_COL_NAME).get(0).getValue().asLong();
|
||||
int xSize = (int) row.getColumn(X_SIZE_COL_NAME).get(0).getValue().asLong();
|
||||
int ySize = (int) row.getColumn(Y_SIZE_COL_NAME).get(0).getValue().asLong();
|
||||
|
||||
List<String> refTimes = Arrays.asList(row.getColumn(T_LIST_COL_NAME).get(0).getValue().asString().split(","));
|
||||
|
||||
StoreOptions.StoreType storeType = StoreOptions.StoreType.valueOf(
|
||||
row.getColumn(STORE_TYPE_COL_NAME).get(0).getValue().asString());
|
||||
StoreOptions storeOptions = new StoreOptions(storeType);
|
||||
if (storeType.equals(StoreOptions.StoreType.SLICE)) {
|
||||
storeOptions.setxSplitCount((int) row.getColumn(X_SPLIT_COUNT_COL_NAME).get(0).getValue().asLong());
|
||||
storeOptions.setySplitCount((int) row.getColumn(Y_SPLIT_COUNT_COL_NAME).get(0).getValue().asLong());
|
||||
}
|
||||
Map<String, Object> attributes = new HashMap<String, Object>();
|
||||
for (Column column : row.getColumns()) {
|
||||
if (!column.getName().startsWith("_")) {
|
||||
attributes.put(column.getName(), ValueUtil.toObject(column.getValue()));
|
||||
}
|
||||
}
|
||||
GridDataSetMeta meta = new GridDataSetMeta(uniqueKey, dataType, variables, tSize, zSize, xSize, ySize, storeOptions);
|
||||
meta.setForecastHours(refTimes);
|
||||
meta.setAttributes(attributes);
|
||||
return meta;
|
||||
}
|
||||
|
||||
public static Grid2D parseGridFromRow(Row row, Plane plane, GridDataSetMeta meta, byte[] buffer, int pos) {
|
||||
if (!meta.getStoreOptions().getStoreType().equals(StoreOptions.StoreType.SLICE)) {
|
||||
throw new IllegalArgumentException("unsupported store type");
|
||||
}
|
||||
int blockXSize = (meta.getxSize() - 1) / meta.getStoreOptions().getxSplitCount() + 1;
|
||||
int blockYSize = (meta.getySize() - 1) / meta.getStoreOptions().getySplitCount() + 1;
|
||||
List<Grid2D> blocks = new ArrayList<Grid2D>();
|
||||
for (Column column : row.getColumns()) {
|
||||
if (column.getName().startsWith(DATA_BLOCK_COL_NAME_PREFIX)) {
|
||||
String[] strs = column.getName().split("_");
|
||||
int xStart = Integer.valueOf(strs[strs.length - 2]);
|
||||
int yStart = Integer.valueOf(strs[strs.length - 1]);
|
||||
Range xRange = new Range(xStart, Math.min(xStart + blockXSize, meta.getxSize()));
|
||||
Range yRange = new Range(yStart, Math.min(yStart + blockYSize, meta.getySize()));
|
||||
int[] origin = new int[] {xStart, yStart};
|
||||
int[] shape = new int[] {xRange.getSize(), yRange.getSize()};
|
||||
Grid2D grid2D = new Grid2D(ByteBuffer.wrap(column.getValue().asBinary()), meta.getDataType(), origin, shape);
|
||||
blocks.add(grid2D);
|
||||
}
|
||||
}
|
||||
Grid2D grid2D = BlockUtil.buildGrid2DFromBlocks(plane, meta.getDataType(), blocks, buffer, pos);
|
||||
return grid2D;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,224 @@
|
||||
package com.aliyun.tablestore.grid.core;
|
||||
|
||||
import com.alicloud.openservices.tablestore.AsyncClientInterface;
|
||||
import com.alicloud.openservices.tablestore.TableStoreCallback;
|
||||
import com.alicloud.openservices.tablestore.model.GetRowRequest;
|
||||
import com.alicloud.openservices.tablestore.model.GetRowResponse;
|
||||
import com.aliyun.tablestore.grid.GridDataFetcher;
|
||||
import com.aliyun.tablestore.grid.model.GetDataParam;
|
||||
import com.aliyun.tablestore.grid.model.GridDataSet;
|
||||
import com.aliyun.tablestore.grid.model.GridDataSetMeta;
|
||||
import com.aliyun.tablestore.grid.model.StoreOptions;
|
||||
import com.aliyun.tablestore.grid.model.grid.*;
|
||||
import com.aliyun.tablestore.grid.utils.BlockUtil;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import static com.aliyun.tablestore.grid.consts.Constants.DATA_BLOCK_COL_NAME_FORMAT;
|
||||
|
||||
/**
|
||||
* not thread-safe
|
||||
*/
|
||||
public class TableStoreDataFetcher implements GridDataFetcher {
|
||||
|
||||
private final AsyncClientInterface asyncClient;
|
||||
private final GridDataSetMeta meta;
|
||||
private final String tableName;
|
||||
private final long dataSizeLimitForFetch;
|
||||
private Collection<String> variables;
|
||||
private Range tRange;
|
||||
private Range zRange;
|
||||
private Range xRange;
|
||||
private Range yRange;
|
||||
|
||||
public TableStoreDataFetcher(AsyncClientInterface asyncClient, String tableName, GridDataSetMeta meta, long dataSizeLimitForFetch) {
|
||||
this.asyncClient = asyncClient;
|
||||
this.tableName = tableName;
|
||||
this.meta = meta;
|
||||
this.dataSizeLimitForFetch = dataSizeLimitForFetch;
|
||||
this.variables = this.meta.getVariables();
|
||||
this.tRange = new Range(0, this.meta.gettSize());
|
||||
this.zRange = new Range(0, this.meta.getzSize());
|
||||
this.xRange = new Range(0, this.meta.getxSize());
|
||||
this.yRange = new Range(0, this.meta.getySize());
|
||||
}
|
||||
|
||||
@Override
|
||||
public GridDataFetcher setVariablesToGet(Collection<String> variables) {
|
||||
this.variables = variables;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GridDataFetcher setT(int t) {
|
||||
return setTRange(new Range(t, t+1));
|
||||
}
|
||||
|
||||
@Override
|
||||
public GridDataFetcher setTRange(Range range) {
|
||||
if (range.getStart() < 0 || range.getEnd() > meta.gettSize()) {
|
||||
throw new IllegalArgumentException("range invalid");
|
||||
}
|
||||
this.tRange = range;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GridDataFetcher setZ(int z) {
|
||||
return setZRange(new Range(z, z+1));
|
||||
}
|
||||
|
||||
@Override
|
||||
public GridDataFetcher setZRange(Range range) {
|
||||
if (range.getStart() < 0 || range.getEnd() > meta.getzSize()) {
|
||||
throw new IllegalArgumentException("range invalid");
|
||||
}
|
||||
this.zRange = range;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GridDataFetcher setX(int x) {
|
||||
return setXRange(new Range(x, x+1));
|
||||
}
|
||||
|
||||
@Override
|
||||
public GridDataFetcher setXRange(Range range) {
|
||||
if (range.getStart() < 0 || range.getEnd() > meta.getxSize()) {
|
||||
throw new IllegalArgumentException("range invalid");
|
||||
}
|
||||
this.xRange = range;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GridDataFetcher setY(int y) {
|
||||
return setYRange(new Range(y, y+1));
|
||||
}
|
||||
|
||||
@Override
|
||||
public GridDataFetcher setYRange(Range range) {
|
||||
if (range.getStart() < 0 || range.getEnd() > meta.getySize()) {
|
||||
throw new IllegalArgumentException("range invalid");
|
||||
}
|
||||
this.yRange = range;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GridDataFetcher setOriginShape(int[] origin, int[] shape) {
|
||||
if (origin.length != 4 || shape.length != 4) {
|
||||
throw new IllegalArgumentException("the length of origin and shape must be 4");
|
||||
}
|
||||
setTRange(new Range(origin[0], origin[0] + shape[0]));
|
||||
setZRange(new Range(origin[1], origin[1] + shape[1]));
|
||||
setXRange(new Range(origin[2], origin[2] + shape[2]));
|
||||
setYRange(new Range(origin[3], origin[3] + shape[3]));
|
||||
return this;
|
||||
}
|
||||
|
||||
public int[] getOrigin() {
|
||||
return new int[] {tRange.getStart(), zRange.getStart(), xRange.getStart(), yRange.getStart()};
|
||||
}
|
||||
|
||||
public int[] getShape() {
|
||||
return new int[] {tRange.getSize(), zRange.getSize(), xRange.getSize(), yRange.getSize()};
|
||||
}
|
||||
|
||||
private long calcDataSize(int variableCount) {
|
||||
long dataSize = variableCount;
|
||||
return dataSize * meta.getDataType().getSize() * tRange.getSize() * zRange.getSize() * xRange.getSize() * yRange.getSize();
|
||||
}
|
||||
|
||||
private List<String> getColumnsToGet() {
|
||||
if (!meta.getStoreOptions().getStoreType().equals(StoreOptions.StoreType.SLICE)) {
|
||||
throw new IllegalArgumentException("unsupported store type");
|
||||
}
|
||||
Plane plane = new Plane(new Range(meta.getxSize()), new Range(meta.getySize()));
|
||||
Plane subPlane = new Plane(xRange, yRange);
|
||||
if (plane.equals(subPlane)) {
|
||||
return null;
|
||||
}
|
||||
List<String> columnsToGet = new ArrayList<String>();
|
||||
List<Point> points = BlockUtil.calcBlockPointsCanCoverSubPlane(plane, subPlane,
|
||||
meta.getStoreOptions().getxSplitCount(), meta.getStoreOptions().getySplitCount());
|
||||
for (Point point : points) {
|
||||
columnsToGet.add(String.format(DATA_BLOCK_COL_NAME_FORMAT, point.getX(), point.getY()));
|
||||
}
|
||||
return columnsToGet;
|
||||
}
|
||||
|
||||
private void addTask(final AtomicInteger counter, final byte[] buffer, final int pos, String variable, int t, int z, final CountDownLatch latch, final Queue<Exception> exceptions) {
|
||||
GetDataParam param = new GetDataParam(tableName, meta.getGridDataSetId(), variable, t, z, getColumnsToGet());
|
||||
asyncClient.getRow(RequestBuilder.buildGetDataRequest(param), new TableStoreCallback<GetRowRequest, GetRowResponse>() {
|
||||
@Override
|
||||
public void onCompleted(GetRowRequest req, GetRowResponse res) {
|
||||
try {
|
||||
if (res.getRow() == null) {
|
||||
exceptions.add(new RuntimeException("the row in not exist, pk: " + req.getRowQueryCriteria().getPrimaryKey()));
|
||||
}
|
||||
RowParser.parseGridFromRow(res.getRow(), new Plane(xRange, yRange), meta, buffer, pos);
|
||||
counter.incrementAndGet();
|
||||
} catch (Exception ex) {
|
||||
exceptions.add(ex);
|
||||
} finally {
|
||||
latch.countDown();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailed(GetRowRequest req, Exception ex) {
|
||||
try {
|
||||
exceptions.add(ex);
|
||||
} finally {
|
||||
latch.countDown();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public GridDataSet fetch() throws Exception {
|
||||
long totalFetchDataSize = calcDataSize(variables.size());
|
||||
if (totalFetchDataSize == 0) {
|
||||
throw new RuntimeException("no data to fetch");
|
||||
}
|
||||
if (totalFetchDataSize > dataSizeLimitForFetch) {
|
||||
throw new RuntimeException("exceed the max data limit for fetch");
|
||||
}
|
||||
GridDataSet dataSet = new GridDataSet(meta);
|
||||
CountDownLatch latch = new CountDownLatch(variables.size() * tRange.getSize() * zRange.getSize());
|
||||
Queue<Exception> exceptions = new ConcurrentLinkedQueue<Exception>();
|
||||
AtomicInteger counter = new AtomicInteger();
|
||||
int taskCount = 0;
|
||||
for (String variable : variables) {
|
||||
int dataSize = (int) calcDataSize(1);
|
||||
byte[] data = new byte[dataSize];
|
||||
ByteBuffer buffer = ByteBuffer.wrap(data).asReadOnlyBuffer();
|
||||
dataSet.addVariable(variable, new Grid4D(buffer, meta.getDataType(), getOrigin(), getShape()));
|
||||
int curPos = 0;
|
||||
for (int t = tRange.getStart(); t < tRange.getEnd(); t++) {
|
||||
for (int z = zRange.getStart(); z < zRange.getEnd(); z++) {
|
||||
addTask(counter, data, curPos, variable, t, z, latch, exceptions);
|
||||
curPos += xRange.getSize() * yRange.getSize() * meta.getDataType().getSize();
|
||||
taskCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
latch.await();
|
||||
if (!exceptions.isEmpty()) {
|
||||
throw exceptions.peek();
|
||||
}
|
||||
if (counter.get() != taskCount) {
|
||||
throw new RuntimeException("not all task success");
|
||||
}
|
||||
return dataSet;
|
||||
}
|
||||
}
|
@ -0,0 +1,98 @@
|
||||
package com.aliyun.tablestore.grid.core;
|
||||
|
||||
import com.alicloud.openservices.tablestore.TableStoreWriter;
|
||||
import com.alicloud.openservices.tablestore.model.*;
|
||||
import com.aliyun.tablestore.grid.GridDataWriter;
|
||||
import com.aliyun.tablestore.grid.model.grid.Grid2D;
|
||||
import com.aliyun.tablestore.grid.model.GridDataSetMeta;
|
||||
import com.aliyun.tablestore.grid.model.StoreOptions;
|
||||
import com.aliyun.tablestore.grid.model.grid.Plane;
|
||||
import com.aliyun.tablestore.grid.utils.BlockUtil;
|
||||
import ucar.ma2.InvalidRangeException;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static com.aliyun.tablestore.grid.consts.Constants.*;
|
||||
|
||||
public class TableStoreDataWriter implements GridDataWriter {
|
||||
|
||||
private final String tableName;
|
||||
private final GridDataSetMeta meta;
|
||||
private final TableStoreWriter writer;
|
||||
|
||||
public TableStoreDataWriter(TableStoreWriter writer, String tableName, GridDataSetMeta dataSetMeta) {
|
||||
this.writer = writer;
|
||||
this.tableName = tableName;
|
||||
this.meta = dataSetMeta;
|
||||
}
|
||||
|
||||
private void checkDataSize(String variable, int t, int z, Grid2D grid2D) {
|
||||
if (!meta.getVariables().contains(variable)) {
|
||||
throw new IllegalArgumentException("The data set dose not include this variable: " + variable);
|
||||
}
|
||||
if (t >= meta.gettSize()) {
|
||||
throw new IllegalArgumentException("t must be in range: [0, " + meta.gettSize() + ")");
|
||||
}
|
||||
if (z >= meta.getzSize()) {
|
||||
throw new IllegalArgumentException("z must be in range: [0, " + meta.getzSize() + ")");
|
||||
}
|
||||
Plane plane = new Plane(grid2D.getOrigin(), grid2D.getShape());
|
||||
if (plane.getxRange().getStart() != 0 || plane.getyRange().getStart() != 0) {
|
||||
throw new IllegalArgumentException("xStart and yStart in grid2D must be 0");
|
||||
}
|
||||
if (plane.getxRange().getSize() != meta.getxSize()) {
|
||||
throw new IllegalArgumentException("xSize in grid2D must be equal to gridDataSetMeta's xSize");
|
||||
}
|
||||
if (plane.getyRange().getSize() != meta.getySize()) {
|
||||
throw new IllegalArgumentException("ySize in grid2D must be equal to gridDataSetMeta's ySize");
|
||||
}
|
||||
}
|
||||
|
||||
private List<Column> splitDataToColumns(Grid2D grid2D) throws InvalidRangeException {
|
||||
List<Column> columns = new ArrayList<Column>();
|
||||
List<Grid2D> blocks = BlockUtil.splitGrid2DToBlocks(grid2D, meta.getStoreOptions().getxSplitCount(), meta.getStoreOptions().getySplitCount());
|
||||
for (Grid2D block : blocks) {
|
||||
columns.add(new Column(String.format(DATA_BLOCK_COL_NAME_FORMAT, block.getPlane().getxRange().getStart(),
|
||||
block.getPlane().getyRange().getStart()), ColumnValue.fromBinary(block.getDataAsByteArray())));
|
||||
}
|
||||
return columns;
|
||||
}
|
||||
|
||||
private void writeToTableStore(String variable, int t, int z, List<Column> columns) {
|
||||
if (columns.size() == 0) {
|
||||
throw new IllegalArgumentException("columns are empty");
|
||||
}
|
||||
PrimaryKeyBuilder builder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
|
||||
builder.addPrimaryKeyColumn(GRID_DATA_SET_ID_PK_NAME, PrimaryKeyValue.fromString(meta.getGridDataSetId()));
|
||||
builder.addPrimaryKeyColumn(VARIABLE_PK_NAME, PrimaryKeyValue.fromString(variable));
|
||||
builder.addPrimaryKeyColumn(T_PK_NAME, PrimaryKeyValue.fromLong(t));
|
||||
builder.addPrimaryKeyColumn(Z_PK_NAME, PrimaryKeyValue.fromLong(z));
|
||||
PrimaryKey pk = builder.build();
|
||||
|
||||
RowUpdateChange rowUpdateChange = new RowUpdateChange(tableName, pk);
|
||||
int currentSize = 0;
|
||||
for (int i = 0; i < columns.size(); i++) {
|
||||
if (currentSize != 0 && (currentSize + columns.get(i).getDataSize()) > MAX_REQUEST_SIZE) {
|
||||
writer.addRowChange(rowUpdateChange);
|
||||
rowUpdateChange = new RowUpdateChange(tableName, pk);
|
||||
currentSize = 0;
|
||||
}
|
||||
rowUpdateChange.put(columns.get(i));
|
||||
currentSize += columns.get(i).getDataSize();
|
||||
}
|
||||
writer.addRowChange(rowUpdateChange);
|
||||
writer.flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeGrid2D(String variable, int t, int z, Grid2D grid2D) throws Exception {
|
||||
checkDataSize(variable, t, z, grid2D);
|
||||
if (meta.getStoreOptions().getStoreType().equals(StoreOptions.StoreType.SLICE)) {
|
||||
List<Column> columns = splitDataToColumns(grid2D);
|
||||
writeToTableStore(variable, t, z, columns);
|
||||
} else {
|
||||
throw new IllegalArgumentException("unsupported store type");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package com.aliyun.tablestore.grid.model;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class DeleteDataParam {
|
||||
private String dataTableName;
|
||||
private String dataSetId;
|
||||
private String variable;
|
||||
private int t;
|
||||
private int z;
|
||||
|
||||
public DeleteDataParam(String dataTableName, String dataSetId, String variable, int t, int z) {
|
||||
this.dataTableName = dataTableName;
|
||||
this.dataSetId = dataSetId;
|
||||
this.variable = variable;
|
||||
this.t = t;
|
||||
this.z = z;
|
||||
}
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
package com.aliyun.tablestore.grid.model;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class GetDataParam {
|
||||
|
||||
private String dataTableName;
|
||||
private String dataSetId;
|
||||
private String variable;
|
||||
private int t;
|
||||
private int z;
|
||||
private List<String> columnsToGet;
|
||||
|
||||
public GetDataParam(String dataTableName, String dataSetId, String variable, int t, int z, List<String> columnsToGet) {
|
||||
this.dataTableName = dataTableName;
|
||||
this.dataSetId = dataSetId;
|
||||
this.variable = variable;
|
||||
this.t = t;
|
||||
this.z = z;
|
||||
this.columnsToGet = columnsToGet;
|
||||
}
|
||||
|
||||
public String getDataTableName() {
|
||||
return dataTableName;
|
||||
}
|
||||
|
||||
public void setDataTableName(String dataTableName) {
|
||||
this.dataTableName = dataTableName;
|
||||
}
|
||||
|
||||
public String getDataSetId() {
|
||||
return dataSetId;
|
||||
}
|
||||
|
||||
public void setDataSetId(String dataSetId) {
|
||||
this.dataSetId = dataSetId;
|
||||
}
|
||||
|
||||
public String getVariable() {
|
||||
return variable;
|
||||
}
|
||||
|
||||
public void setVariable(String variable) {
|
||||
this.variable = variable;
|
||||
}
|
||||
|
||||
public int getT() {
|
||||
return t;
|
||||
}
|
||||
|
||||
public void setT(int t) {
|
||||
this.t = t;
|
||||
}
|
||||
|
||||
public int getZ() {
|
||||
return z;
|
||||
}
|
||||
|
||||
public void setZ(int z) {
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
public List<String> getColumnsToGet() {
|
||||
return columnsToGet;
|
||||
}
|
||||
|
||||
public void setColumnsToGet(List<String> columnsToGet) {
|
||||
this.columnsToGet = columnsToGet;
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
package com.aliyun.tablestore.grid.model;
|
||||
|
||||
import com.aliyun.tablestore.grid.model.grid.Grid4D;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class GridDataSet {
|
||||
|
||||
private final GridDataSetMeta meta;
|
||||
|
||||
private final Map<String, Grid4D> variables;
|
||||
|
||||
public GridDataSet(GridDataSetMeta meta) {
|
||||
this.meta = meta;
|
||||
this.variables = new ConcurrentHashMap<String, Grid4D>();
|
||||
}
|
||||
|
||||
public GridDataSet(GridDataSetMeta meta, Map<String, Grid4D> variables) {
|
||||
this.meta = meta;
|
||||
this.variables = variables;
|
||||
}
|
||||
|
||||
public void addVariable(String variable, Grid4D grid4D) {
|
||||
this.variables.put(variable, grid4D);
|
||||
}
|
||||
|
||||
public Grid4D getVariable(String variable) {
|
||||
if (variables == null) {
|
||||
return null;
|
||||
}
|
||||
return variables.get(variable);
|
||||
}
|
||||
|
||||
public Map<String, Grid4D> getVariables() {
|
||||
return variables;
|
||||
}
|
||||
|
||||
public GridDataSetMeta getMeta() {
|
||||
return meta;
|
||||
}
|
||||
}
|
@ -0,0 +1,124 @@
|
||||
package com.aliyun.tablestore.grid.model;
|
||||
|
||||
import ucar.ma2.DataType;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class GridDataSetMeta {
|
||||
|
||||
private String gridDataSetId;
|
||||
private final DataType dataType;
|
||||
private List<String> variables;
|
||||
private int tSize;
|
||||
private int zSize;
|
||||
private int xSize;
|
||||
private int ySize;
|
||||
private List<String> forecastHours;
|
||||
private final StoreOptions storeOptions;
|
||||
private Map<String, Object> attributes;
|
||||
|
||||
public GridDataSetMeta(String gridDataSetId, DataType dataType, List<String> variables, int tSize, int zSize, int xSize, int ySize, StoreOptions storeOptions) {
|
||||
assert gridDataSetId != null;
|
||||
assert variables != null;
|
||||
assert storeOptions != null;
|
||||
|
||||
this.gridDataSetId = gridDataSetId;
|
||||
this.dataType = dataType;
|
||||
this.variables = variables;
|
||||
this.tSize = tSize;
|
||||
this.zSize = zSize;
|
||||
this.xSize = xSize;
|
||||
this.ySize = ySize;
|
||||
this.storeOptions = storeOptions;
|
||||
}
|
||||
|
||||
public String getGridDataSetId() {
|
||||
return gridDataSetId;
|
||||
}
|
||||
|
||||
public void setGridDataSetId(String gridDataSetId) {
|
||||
this.gridDataSetId = gridDataSetId;
|
||||
}
|
||||
|
||||
public List<String> getVariables() {
|
||||
return variables;
|
||||
}
|
||||
|
||||
public void setVariables(List<String> variables) {
|
||||
this.variables = variables;
|
||||
}
|
||||
|
||||
public int gettSize() {
|
||||
return tSize;
|
||||
}
|
||||
|
||||
public void settSize(int tSize) {
|
||||
this.tSize = tSize;
|
||||
}
|
||||
|
||||
public int getzSize() {
|
||||
return zSize;
|
||||
}
|
||||
|
||||
public void setzSize(int zSize) {
|
||||
this.zSize = zSize;
|
||||
}
|
||||
|
||||
public int getxSize() {
|
||||
return xSize;
|
||||
}
|
||||
|
||||
public void setxSize(int xSize) {
|
||||
this.xSize = xSize;
|
||||
}
|
||||
|
||||
public int getySize() {
|
||||
return ySize;
|
||||
}
|
||||
|
||||
public void setySize(int ySize) {
|
||||
this.ySize = ySize;
|
||||
}
|
||||
|
||||
public Map<String, Object> getAttributes() {
|
||||
return attributes;
|
||||
}
|
||||
|
||||
public void setAttributes(Map<String, Object> attributes) {
|
||||
assert attributes != null;
|
||||
for (String key : attributes.keySet()) {
|
||||
if (key.startsWith("_")) {
|
||||
throw new IllegalArgumentException("attribute key can't start with \"_\"");
|
||||
}
|
||||
}
|
||||
this.attributes = attributes;
|
||||
}
|
||||
|
||||
public void addAttribute(String key, Object value) {
|
||||
if (key.startsWith("_")) {
|
||||
throw new IllegalArgumentException("attribute key can't start with \"_\"");
|
||||
}
|
||||
if (this.attributes == null) {
|
||||
this.attributes = new ConcurrentHashMap<String, Object>();
|
||||
}
|
||||
this.attributes.put(key, value);
|
||||
}
|
||||
|
||||
public StoreOptions getStoreOptions() {
|
||||
return storeOptions;
|
||||
}
|
||||
|
||||
public DataType getDataType() {
|
||||
return dataType;
|
||||
}
|
||||
|
||||
public void setForecastHours(List<String> forecastHours) {
|
||||
this.forecastHours = forecastHours;
|
||||
}
|
||||
|
||||
public List<String> getForecastHours() {
|
||||
return forecastHours;
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
package com.aliyun.tablestore.grid.model;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class QueryGridDataSetResult {
|
||||
|
||||
private List<GridDataSetMeta> gridDataSetMetas;
|
||||
private long totalCount;
|
||||
private boolean isAllSuccess;
|
||||
private byte[] nextToken;
|
||||
|
||||
public List<GridDataSetMeta> getGridDataSetMetas() {
|
||||
return gridDataSetMetas;
|
||||
}
|
||||
|
||||
public void setGridDataSetMetas(List<GridDataSetMeta> gridDataSetMetas) {
|
||||
this.gridDataSetMetas = gridDataSetMetas;
|
||||
}
|
||||
|
||||
public long getTotalCount() {
|
||||
return totalCount;
|
||||
}
|
||||
|
||||
public void setTotalCount(long totalCount) {
|
||||
this.totalCount = totalCount;
|
||||
}
|
||||
|
||||
public boolean isAllSuccess() {
|
||||
return isAllSuccess;
|
||||
}
|
||||
|
||||
public void setAllSuccess(boolean allSuccess) {
|
||||
isAllSuccess = allSuccess;
|
||||
}
|
||||
|
||||
public byte[] getNextToken() {
|
||||
return nextToken;
|
||||
}
|
||||
|
||||
public void setNextToken(byte[] nextToken) {
|
||||
this.nextToken = nextToken;
|
||||
}
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
package com.aliyun.tablestore.grid.model;
|
||||
|
||||
|
||||
import com.alicloud.openservices.tablestore.model.search.sort.Sort;
|
||||
|
||||
public class QueryParams {
|
||||
|
||||
private Integer offset;
|
||||
private Integer limit;
|
||||
private Sort sort;
|
||||
private byte[] token;
|
||||
private boolean getTotalCount = false;
|
||||
|
||||
public QueryParams() {
|
||||
}
|
||||
|
||||
public QueryParams(int limit) {
|
||||
this.limit = limit;
|
||||
}
|
||||
|
||||
public QueryParams(int offset, int limit) {
|
||||
this.offset = offset;
|
||||
this.limit = limit;
|
||||
}
|
||||
|
||||
public QueryParams(int offset, int limit, Sort sort) {
|
||||
this.offset = offset;
|
||||
this.limit = limit;
|
||||
this.sort = sort;
|
||||
}
|
||||
|
||||
public QueryParams(byte[] token, int limit) {
|
||||
this.token = token;
|
||||
this.limit = limit;
|
||||
}
|
||||
|
||||
|
||||
public Integer getOffset() {
|
||||
return offset;
|
||||
}
|
||||
|
||||
public QueryParams setOffset(Integer offset) {
|
||||
this.offset = offset;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Integer getLimit() {
|
||||
return limit;
|
||||
}
|
||||
|
||||
public QueryParams setLimit(Integer limit) {
|
||||
this.limit = limit;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Sort getSort() {
|
||||
return sort;
|
||||
}
|
||||
|
||||
public QueryParams setSort(Sort sort) {
|
||||
this.sort = sort;
|
||||
return this;
|
||||
}
|
||||
|
||||
public byte[] getToken() {
|
||||
return token;
|
||||
}
|
||||
|
||||
public QueryParams setToken(byte[] token) {
|
||||
this.token = token;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isGetTotalCount() {
|
||||
return getTotalCount;
|
||||
}
|
||||
|
||||
public QueryParams setGetTotalCount(boolean getTotalCount) {
|
||||
this.getTotalCount = getTotalCount;
|
||||
return this;
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
package com.aliyun.tablestore.grid.model;
|
||||
|
||||
public class StoreOptions {
|
||||
|
||||
public enum StoreType {
|
||||
SLICE
|
||||
}
|
||||
|
||||
private StoreType storeType;
|
||||
private int xSplitCount = 10;
|
||||
private int ySplitCount = 10;
|
||||
|
||||
public StoreOptions(StoreType storeType) {
|
||||
this.storeType = storeType;
|
||||
}
|
||||
|
||||
public StoreType getStoreType() {
|
||||
return storeType;
|
||||
}
|
||||
|
||||
public void setStoreType(StoreType storeType) {
|
||||
this.storeType = storeType;
|
||||
}
|
||||
|
||||
public int getxSplitCount() {
|
||||
return xSplitCount;
|
||||
}
|
||||
|
||||
public void setxSplitCount(int xSplitCount) {
|
||||
this.xSplitCount = xSplitCount;
|
||||
}
|
||||
|
||||
public int getySplitCount() {
|
||||
return ySplitCount;
|
||||
}
|
||||
|
||||
public void setySplitCount(int ySplitCount) {
|
||||
this.ySplitCount = ySplitCount;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
package com.aliyun.tablestore.grid.model.grid;
|
||||
|
||||
import ucar.ma2.Array;
|
||||
import ucar.ma2.DataType;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public abstract class Grid {
|
||||
|
||||
protected ByteBuffer buffer;
|
||||
protected DataType dataType;
|
||||
protected int[] origin;
|
||||
protected int[] shape;
|
||||
|
||||
public Grid(ByteBuffer buffer, DataType dataType, int[] origin, int[] shape) {
|
||||
this.buffer = buffer;
|
||||
this.dataType = dataType;
|
||||
this.origin = origin;
|
||||
this.shape = shape;
|
||||
int size = dataType.getSize();
|
||||
for (int i = 0; i < shape.length; i++) {
|
||||
size *= shape[i];
|
||||
}
|
||||
if (buffer.remaining() != size) {
|
||||
throw new IllegalArgumentException("data length and shape mismatch");
|
||||
}
|
||||
if (origin.length != shape.length) {
|
||||
throw new IllegalArgumentException("the length of origin and shape mismatch");
|
||||
}
|
||||
}
|
||||
|
||||
public int getDataSize() {
|
||||
return buffer.remaining();
|
||||
}
|
||||
|
||||
public byte[] getDataAsByteArray() {
|
||||
byte[] data = new byte[getDataSize()];
|
||||
buffer.duplicate().get(data);
|
||||
return data;
|
||||
}
|
||||
|
||||
public int[] getOrigin() {
|
||||
return origin;
|
||||
}
|
||||
|
||||
public int[] getShape() {
|
||||
return shape;
|
||||
}
|
||||
|
||||
public DataType getDataType() {
|
||||
return dataType;
|
||||
}
|
||||
|
||||
public Array toArray() {
|
||||
Array array = Array.factory(dataType, shape, buffer.duplicate());
|
||||
return array;
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package com.aliyun.tablestore.grid.model.grid;
|
||||
|
||||
import ucar.ma2.DataType;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public class Grid2D extends Grid {
|
||||
|
||||
public Grid2D(ByteBuffer data, DataType dataType, int[] origin, int[] shape) {
|
||||
super(data, dataType, origin, shape);
|
||||
if (origin.length != 2 || shape.length != 2) {
|
||||
throw new IllegalArgumentException("the length of origin and shape must be 2");
|
||||
}
|
||||
}
|
||||
|
||||
public Plane getPlane() {
|
||||
return new Plane(getOrigin(), getShape());
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package com.aliyun.tablestore.grid.model.grid;
|
||||
|
||||
import ucar.ma2.DataType;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class Grid3D extends Grid {
|
||||
|
||||
public Grid3D(ByteBuffer data, DataType dataType, int[] origin, int[] shape) {
|
||||
super(data, dataType, origin, shape);
|
||||
if (origin.length != 3 || shape.length != 3) {
|
||||
throw new IllegalArgumentException("the length of origin and shape must be 2");
|
||||
}
|
||||
}
|
||||
|
||||
public Grid2D getGrid2D(int idx) {
|
||||
if (idx < 0 || idx >= shape[0]) {
|
||||
throw new IllegalArgumentException("index out of range");
|
||||
}
|
||||
int itemSize = shape[1] * shape[2] * dataType.getSize();
|
||||
int pos = idx * itemSize;
|
||||
ByteBuffer newBuffer = buffer.slice();
|
||||
newBuffer.position(pos);
|
||||
newBuffer.limit(pos + itemSize);
|
||||
newBuffer = newBuffer.slice();
|
||||
return new Grid2D(newBuffer, dataType, Arrays.copyOfRange(origin, 1, origin.length),
|
||||
Arrays.copyOfRange(shape, 1, shape.length));
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package com.aliyun.tablestore.grid.model.grid;
|
||||
|
||||
import ucar.ma2.DataType;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class Grid4D extends Grid {
|
||||
|
||||
public Grid4D(ByteBuffer data, DataType dataType, int[] origin, int[] shape) {
|
||||
super(data, dataType, origin, shape);
|
||||
if (origin.length != 4 || shape.length != 4) {
|
||||
throw new IllegalArgumentException("the length of origin and shape must be 2");
|
||||
}
|
||||
}
|
||||
|
||||
public Grid3D getGrid3D(int idx) {
|
||||
if (idx < 0 || idx >= shape[0]) {
|
||||
throw new IllegalArgumentException("index out of range");
|
||||
}
|
||||
int itemSize = shape[1] * shape[2] * shape[3] * dataType.getSize();
|
||||
int pos = idx * itemSize;
|
||||
ByteBuffer newBuffer = buffer.slice();
|
||||
newBuffer.position(pos);
|
||||
newBuffer.limit(pos + itemSize);
|
||||
newBuffer = newBuffer.slice();
|
||||
return new Grid3D(newBuffer, dataType, Arrays.copyOfRange(origin, 1, origin.length),
|
||||
Arrays.copyOfRange(shape, 1, shape.length));
|
||||
}
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
package com.aliyun.tablestore.grid.model.grid;
|
||||
|
||||
public class Plane {
|
||||
|
||||
private Range xRange;
|
||||
private Range yRange;
|
||||
|
||||
public Plane(Range xRange, Range yRange) {
|
||||
this.xRange = xRange;
|
||||
this.yRange = yRange;
|
||||
}
|
||||
|
||||
public Plane(int[] origin, int[] shape) {
|
||||
if (origin.length != 2 || shape.length != 2) {
|
||||
throw new IllegalArgumentException("the length of origin and shape must be 2");
|
||||
}
|
||||
this.xRange = new Range(origin[0], origin[0] + shape[0]);
|
||||
this.yRange = new Range(origin[1], origin[1] + shape[1]);
|
||||
}
|
||||
|
||||
public int[] getOrigin() {
|
||||
return new int[] {xRange.getStart(), yRange.getStart()};
|
||||
}
|
||||
|
||||
public int[] getShape() {
|
||||
return new int[] {xRange.getSize(), yRange.getSize()};
|
||||
}
|
||||
|
||||
public Range getxRange() {
|
||||
return xRange;
|
||||
}
|
||||
|
||||
public void setxRange(Range xRange) {
|
||||
this.xRange = xRange;
|
||||
}
|
||||
|
||||
public Range getyRange() {
|
||||
return yRange;
|
||||
}
|
||||
|
||||
public void setyRange(Range yRange) {
|
||||
this.yRange = yRange;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o instanceof Plane) {
|
||||
return xRange.equals(((Plane) o).getxRange()) && yRange.equals(((Plane) o).getyRange());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
package com.aliyun.tablestore.grid.model.grid;
|
||||
|
||||
public class Point {
|
||||
|
||||
private int x;
|
||||
private int y;
|
||||
|
||||
public Point(int x, int y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public int getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public void setX(int x) {
|
||||
this.x = x;
|
||||
}
|
||||
|
||||
public int getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
public void setY(int y) {
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o instanceof Point) {
|
||||
return x == ((Point) o).x && y == ((Point) o).y;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
package com.aliyun.tablestore.grid.model.grid;
|
||||
|
||||
public class Range {
|
||||
|
||||
private int start;
|
||||
private int end;
|
||||
|
||||
public Range(int end) {
|
||||
this.start = 0;
|
||||
this.end = end;
|
||||
}
|
||||
|
||||
public Range(int start, int end) {
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
}
|
||||
|
||||
public int getStart() {
|
||||
return start;
|
||||
}
|
||||
|
||||
public void setStart(int start) {
|
||||
this.start = start;
|
||||
}
|
||||
|
||||
public int getEnd() {
|
||||
return end;
|
||||
}
|
||||
|
||||
public void setEnd(int end) {
|
||||
this.end = end;
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
return this.end - this.start;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o instanceof Range) {
|
||||
return start == ((Range) o).start && end == ((Range) o).end;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return ("[" + start + ", " + end + ")");
|
||||
}
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
package com.aliyun.tablestore.grid.utils;
|
||||
|
||||
import com.aliyun.tablestore.grid.model.grid.Grid2D;
|
||||
import com.aliyun.tablestore.grid.model.grid.Plane;
|
||||
import com.aliyun.tablestore.grid.model.grid.Point;
|
||||
import com.aliyun.tablestore.grid.model.grid.Range;
|
||||
import ucar.ma2.Array;
|
||||
import ucar.ma2.DataType;
|
||||
import ucar.ma2.InvalidRangeException;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class BlockUtil {
|
||||
|
||||
public static List<Grid2D> splitGrid2DToBlocks(Grid2D grid2D, int xSplitCount, int ySplitCount) throws InvalidRangeException {
|
||||
Array array = grid2D.toArray();
|
||||
int blockXSize = (grid2D.getPlane().getxRange().getSize() - 1) / xSplitCount + 1;
|
||||
int blockYSize = (grid2D.getPlane().getyRange().getSize() - 1) / ySplitCount + 1;
|
||||
List<Grid2D> result = new ArrayList<Grid2D>();
|
||||
for (int i = 0; i < xSplitCount; i++) {
|
||||
int startX = i * blockXSize;
|
||||
int endX = Math.min(grid2D.getPlane().getxRange().getSize(), startX + blockXSize);
|
||||
if (startX >= grid2D.getPlane().getxRange().getSize()) {
|
||||
break;
|
||||
}
|
||||
for (int j = 0; j < ySplitCount; j++) {
|
||||
int startY = j * blockYSize;
|
||||
int endY = Math.min(grid2D.getPlane().getyRange().getSize(), startY + blockYSize);
|
||||
if (startY >= grid2D.getPlane().getyRange().getSize()) {
|
||||
break;
|
||||
}
|
||||
int[] origin = new int[] { startX, startY };
|
||||
int[] shape = new int[] { endX - startX, endY - startY };
|
||||
Array section = array.section(origin, shape);
|
||||
Grid2D block = new Grid2D(section.getDataAsByteBuffer(), grid2D.getDataType(), origin, shape);
|
||||
result.add(block);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static List<Point> calcBlockPointsCanCoverSubPlane(Plane plane, Plane subPlane, int xSplitCount, int ySplitCount) {
|
||||
int blockXSize = (plane.getxRange().getSize() - 1) / xSplitCount + 1;
|
||||
int blockYSize = (plane.getyRange().getSize() - 1) / ySplitCount + 1;
|
||||
|
||||
Range xBlockIndexRange = new Range(
|
||||
subPlane.getxRange().getStart() / blockXSize,
|
||||
(subPlane.getxRange().getEnd() - 1) / blockXSize + 1);
|
||||
Range yBlockIndexRange = new Range(
|
||||
subPlane.getyRange().getStart() / blockYSize,
|
||||
(subPlane.getyRange().getEnd() - 1) / blockYSize + 1);
|
||||
|
||||
List<Point> points = new ArrayList<Point>();
|
||||
for (int xIdx = xBlockIndexRange.getStart(); xIdx < xBlockIndexRange.getEnd(); xIdx++) {
|
||||
for (int yIdx = yBlockIndexRange.getStart(); yIdx < yBlockIndexRange.getEnd(); yIdx++) {
|
||||
Point point = new Point(xIdx * blockXSize, yIdx * blockYSize);
|
||||
points.add(point);
|
||||
}
|
||||
}
|
||||
return points;
|
||||
}
|
||||
|
||||
public static Grid2D buildGrid2DFromBlocks(Plane plane, DataType dataType, List<Grid2D> blocks, byte[] buffer, int pos) {
|
||||
int size = plane.getxRange().getSize() * plane.getyRange().getSize() * dataType.getSize();
|
||||
if (buffer.length - pos < size) {
|
||||
throw new IllegalArgumentException("buffer not enough");
|
||||
}
|
||||
int count = 0;
|
||||
for (Grid2D block : blocks) {
|
||||
Plane blockPlane = block.getPlane();
|
||||
for (int x = Math.max(blockPlane.getxRange().getStart(), plane.getxRange().getStart());
|
||||
x < Math.min(blockPlane.getxRange().getEnd(), plane.getxRange().getEnd()); x++) {
|
||||
for (int y = Math.max(blockPlane.getyRange().getStart(), plane.getyRange().getStart());
|
||||
y < Math.min(blockPlane.getyRange().getEnd(), plane.getyRange().getEnd()); y++) {
|
||||
int posInBlock = dataType.getSize() * ((x - blockPlane.getxRange().getStart()) * (blockPlane.getyRange().getSize()) + (y - blockPlane.getyRange().getStart())) ;
|
||||
int posInData = dataType.getSize() * ((x - plane.getxRange().getStart()) * plane.getyRange().getSize() + (y - plane.getyRange().getStart()));
|
||||
System.arraycopy(block.getDataAsByteArray(), posInBlock, buffer, pos + posInData, dataType.getSize());
|
||||
count += dataType.getSize();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (count != size) {
|
||||
throw new RuntimeException("the blocks does not contain enough data");
|
||||
}
|
||||
ByteBuffer byteBuffer = ByteBuffer.wrap(buffer, pos, size);
|
||||
return new Grid2D(byteBuffer, dataType, plane.getOrigin(), plane.getShape());
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
package com.aliyun.tablestore.grid.utils;
|
||||
|
||||
import com.alicloud.openservices.tablestore.model.ColumnValue;
|
||||
|
||||
public class ValueUtil {
|
||||
|
||||
public static ColumnValue toColumnValue(Object value) {
|
||||
if (value instanceof Long) {
|
||||
return ColumnValue.fromLong((Long) value);
|
||||
} else if (value instanceof Integer) {
|
||||
return ColumnValue.fromLong(((Integer) value).longValue());
|
||||
} else if (value instanceof Double) {
|
||||
return ColumnValue.fromDouble((Double) value);
|
||||
} else if (value instanceof String) {
|
||||
return ColumnValue.fromString((String) value);
|
||||
} else if (value instanceof Boolean) {
|
||||
return ColumnValue.fromBoolean((Boolean) value);
|
||||
} else if (value instanceof byte[]) {
|
||||
return ColumnValue.fromBinary((byte[]) value);
|
||||
} else {
|
||||
throw new IllegalArgumentException("unsupported type: " + value.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
public static Object toObject(ColumnValue value) {
|
||||
switch (value.getType()) {
|
||||
case INTEGER: {
|
||||
return value.asLong();
|
||||
}
|
||||
case STRING: {
|
||||
return value.asString();
|
||||
}
|
||||
case BOOLEAN: {
|
||||
return value.asBoolean();
|
||||
}
|
||||
case DOUBLE: {
|
||||
return value.asDouble();
|
||||
}
|
||||
case BINARY: {
|
||||
return value.asBinary();
|
||||
}
|
||||
default: {
|
||||
throw new RuntimeException("unexpected");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
Manifest-Version: 1.0
|
||||
Class-Path: httpservices-5.5.3.jar re2j-1.3.jar udunits-5.5.3.jar jsr305
|
||||
-3.0.2.jar tablestore-5.16.0-jar-with-dependencies.jar cdm-core-5.5.3.j
|
||||
ar j2objc-annotations-1.3.jar disruptor-3.4.4.jar logback-core-1.2.12.j
|
||||
ar flatbuffers-java-1.11.0.jar jcommander-1.78.jar httpcore-4.4.13.jar
|
||||
slf4j-api-1.7.28.jar listenablefuture-9999.0-empty-to-avoid-conflict-wi
|
||||
th-guava.jar joda-time-2.10.3.jar lombok-1.18.30.jar commons-io-2.11.0.
|
||||
jar commons-codec-1.11.jar protobuf-java-3.19.3.jar jdom2-2.0.6.jar fai
|
||||
lureaccess-1.0.1.jar checker-qual-3.5.0.jar jj2000-5.4.jar httpclient-4
|
||||
.5.13.jar commons-logging-1.2.jar guava-30.1-jre.jar gson-2.8.5.jar err
|
||||
or_prone_annotations-2.3.4.jar logback-classic-1.2.12.jar httpmime-4.5.
|
||||
13.jar grib-5.5.3.jar
|
||||
|
@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration scan = "true" debug="false">
|
||||
<!-- 控制台日志输出-->
|
||||
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%highlight(%-5level) %d{HH:mm:ss.SSS} %magenta([%thread]) %cyan(%logger{36}) - %msg%n</pattern>
|
||||
<!-- <pattern>${log.pattern}</pattern> -->
|
||||
</encoder>
|
||||
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
|
||||
<level>debug</level>
|
||||
</filter>
|
||||
</appender>
|
||||
<!-- 定义某个包的日志级别 -->
|
||||
<logger name="com" level="debug"> <!-- 添加控制台输出 -->
|
||||
<appender-ref ref="console"/>
|
||||
</logger>
|
||||
<logger name="com.alicloud.openservices" level="WARN"/>
|
||||
<logger name="com.aliyun.ots" level="WARN"/>
|
||||
</configuration>
|
||||
|
||||
|
@ -0,0 +1,60 @@
|
||||
import ucar.ma2.Array;
|
||||
import ucar.ma2.Index;
|
||||
import ucar.ma2.InvalidRangeException;
|
||||
import ucar.nc2.NetcdfFile;
|
||||
import ucar.nc2.NetcdfFiles;
|
||||
import ucar.nc2.Variable;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
/**
|
||||
* Unit test for simple App.
|
||||
*/
|
||||
public class TestReadGrib2ByNC {
|
||||
public static void main(String[] args){
|
||||
// String ncFile = "surface.nc";
|
||||
String file = "C:\\Users\\shi_y\\Desktop\\java_learn\\data_download\\GFSData\\UTC-20230910\\BJT-20230911-0200.grib2";
|
||||
try (NetcdfFile ncFile = NetcdfFiles.open(file)) {
|
||||
// 打印文件相关信息
|
||||
// System.out.println(ncfile.toString());
|
||||
|
||||
// 获取时间变量
|
||||
Variable timeVar = ncFile.findVariable("time");
|
||||
String units = timeVar.findAttribute("units").getStringValue();
|
||||
System.out.println(units);
|
||||
// 读取时间变量 surface.nc的单位是"hours since 1900-01-01 00:00:00.0"
|
||||
System.out.println(timeVar.getFileTypeId());
|
||||
double[] timeArray = (double[]) timeVar.read().copyTo1DJavaArray();
|
||||
|
||||
DateTimeFormatter unitsFormat = DateTimeFormatter.ofPattern("'Hour since 'yyyy-MM-dd'T'HH:mm:ss'Z'");
|
||||
LocalDateTime unitsDateTime = LocalDateTime.parse(units, unitsFormat).plusHours((long) timeArray[0]);
|
||||
System.out.println(unitsDateTime);
|
||||
// 指定变量名读取变量
|
||||
Variable t2m = ncFile.findVariable("Temperature_isobaric");
|
||||
|
||||
// 打印变量的相关信息
|
||||
System.out.println(t2m.toString());
|
||||
|
||||
if (t2m != null) {
|
||||
System.out.println(t2m.findDimensionIndex("lon"));
|
||||
}
|
||||
// 读取所有的数据
|
||||
assert t2m != null;
|
||||
Array v = t2m.read("0, 0, 10:20, 20:30").reduce(0).reduce(0);
|
||||
Index index = v.getIndex(); // 用于跟踪当前索引的位置
|
||||
index = index.set(1);
|
||||
System.out.println(v.getShort(index));
|
||||
|
||||
|
||||
} catch (IOException ioe) {
|
||||
// Handle less-cool exceptions here
|
||||
throw new RuntimeException(ioe);
|
||||
} catch (InvalidRangeException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,159 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.htfp.weather</groupId>
|
||||
<artifactId>weather-service</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<name>weather-service</name>
|
||||
<description>weather-service</description>
|
||||
<properties>
|
||||
<java.version>1.8</java.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<spring-boot.version>2.6.13</spring-boot.version>
|
||||
</properties>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>unidata-all</id>
|
||||
<name>Unidata All</name>
|
||||
<url>https://artifacts.unidata.ucar.edu/repository/unidata-all/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>edu.ucar</groupId>
|
||||
<artifactId>cdm-core</artifactId>
|
||||
<version>5.5.3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>edu.ucar</groupId>
|
||||
<artifactId>grib</artifactId>
|
||||
<version>5.5.3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.aliyun.openservices</groupId>
|
||||
<artifactId>tablestore</artifactId>
|
||||
<version>5.16.0</version>
|
||||
<classifier>jar-with-dependencies</classifier>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpasyncclient</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>ai.djl</groupId>
|
||||
<artifactId>api</artifactId>
|
||||
<version>0.27.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ai.djl.pytorch</groupId>
|
||||
<artifactId>pytorch-engine</artifactId>
|
||||
<version>0.27.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>2.11.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-thymeleaf</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
<version>4.9.0</version>
|
||||
<!-- 去掉Android的包 -->
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>com.google.android</groupId>
|
||||
<artifactId>android</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.aliyun.tablestore</groupId>
|
||||
<artifactId>tablestore-grid</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<!-- springmvc的参数valid校验依赖 开始 -->
|
||||
<dependency>
|
||||
<groupId>javax.validation</groupId>
|
||||
<artifactId>validation-api</artifactId>
|
||||
<version>2.0.1.Final</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-validator</artifactId>
|
||||
<version>6.0.16.Final</version>
|
||||
</dependency>
|
||||
<!-- springmvc的参数valid校验依赖 结束 -->
|
||||
</dependencies>
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-dependencies</artifactId>
|
||||
<version>${spring-boot.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.8.1</version>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
<encoding>UTF-8</encoding>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<version>${spring-boot.version}</version>
|
||||
<configuration>
|
||||
<mainClass>com.htfp.weather.WeatherServiceApplication</mainClass>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>repackage</id>
|
||||
<goals>
|
||||
<goal>repackage</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
@ -0,0 +1,19 @@
|
||||
package com.htfp.weather;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
|
||||
@EnableScheduling
|
||||
@SpringBootApplication
|
||||
public class WeatherServiceApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
try {
|
||||
SpringApplication.run(WeatherServiceApplication.class, args);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package com.htfp.weather.config;
|
||||
|
||||
import com.htfp.weather.griddata.common.TableConfig;
|
||||
import com.htfp.weather.griddata.common.TableConfigBean;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* @Author : shiyi
|
||||
* @Date : 2024/1/22 19:02
|
||||
* @Description :
|
||||
*/
|
||||
@Component("config")
|
||||
public class Config {
|
||||
@Resource
|
||||
TableConfigBean tableConfigBean;
|
||||
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package com.htfp.weather.download;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
|
||||
/**
|
||||
* @author shiyi
|
||||
*/
|
||||
|
||||
@Data
|
||||
@ToString
|
||||
public class FileInfo {
|
||||
/**保存文件名*/
|
||||
private String fileName;
|
||||
/**数据起报时间*/
|
||||
private String refTimeStr;
|
||||
/**预报时效*/
|
||||
private Integer forecastHour;
|
||||
/**预报时效对应的北京时间*/
|
||||
private String forecastBJTimeStr;
|
||||
/**预报时效对应的UTC时间*/
|
||||
private String forecastUTCTimeStr;
|
||||
/**下载链接*/
|
||||
private String url;
|
||||
|
||||
private String savePath;
|
||||
|
||||
public FileInfo() {
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
package com.htfp.weather.griddata.common;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* @Author : shiyi
|
||||
* @Date : 2024/1/15 14:54
|
||||
* @Description : 文件变量名和表中变量名的映射
|
||||
*/
|
||||
public enum GfsVariableNameEnum {
|
||||
//
|
||||
TEMP("temp", "Temperature_isobaric"),
|
||||
CLOUD("cloud", "Total_cloud_cover_isobaric"),
|
||||
WIND_SPEED("windSpeed", "Wind_speed_isobaric"),
|
||||
WIND360("wind360", "Wind_direction_isobaric"),
|
||||
;
|
||||
private static final ConcurrentHashMap<String, String> variableName = new ConcurrentHashMap<String, String>() {{
|
||||
put("temp", "Temperature_isobaric");
|
||||
put("cloud", "Total_cloud_cover_isobaric");
|
||||
put("windSpeed", "Wind_speed_isobaric");
|
||||
put("wind360", "Wind_direction_isobaric");
|
||||
}};
|
||||
String nameInApi;
|
||||
String nameInFile;
|
||||
|
||||
GfsVariableNameEnum(String nameInApi, String nameInFile) {
|
||||
this.nameInApi = nameInApi;
|
||||
this.nameInFile = nameInFile;
|
||||
}
|
||||
|
||||
public String getNameInApi() {
|
||||
return nameInApi;
|
||||
}
|
||||
|
||||
public String getNameInFile() {
|
||||
return nameInFile;
|
||||
}
|
||||
public static String getGfsVariableName(GfsVariableNameEnum gfsVariableNameEnum) {
|
||||
return variableName.get(gfsVariableNameEnum.nameInApi);
|
||||
}
|
||||
public static String getGfsVariableName(String tableVariableName) {
|
||||
return variableName.get(tableVariableName);
|
||||
}
|
||||
|
||||
public static List<String> getVariableNamesInApi() {
|
||||
return new ArrayList<>(variableName.keySet());
|
||||
}
|
||||
|
||||
public static List<String> getVariableNamesInFile() {
|
||||
return new ArrayList<>(variableName.values());
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package com.htfp.weather.griddata.common;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Data
|
||||
@Configuration("tableStoreConf")
|
||||
@ConfigurationProperties("tablestore")
|
||||
public class TableStoreConf {
|
||||
private String endpoint;
|
||||
private String accessId;
|
||||
private String accessKey;
|
||||
private String instanceName;
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
package com.htfp.weather.griddata.operation;
|
||||
|
||||
|
||||
import com.aliyun.tablestore.grid.TableStoreGridConfig;
|
||||
import com.aliyun.tablestore.grid.TableStoreGrid;
|
||||
import com.google.common.collect.Tables;
|
||||
import com.htfp.weather.griddata.common.TableConfig;
|
||||
import com.htfp.weather.griddata.common.TableConfigBean;
|
||||
import com.htfp.weather.griddata.common.TableStoreConf;
|
||||
import org.checkerframework.checker.units.qual.A;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.DependsOn;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
@DependsOn("tableStoreConf")
|
||||
public abstract class BaseTableOperation{
|
||||
|
||||
protected TableStoreGrid tableStoreGrid;
|
||||
// private String pathSeperator = "/";
|
||||
@Autowired
|
||||
private TableConfigBean tableConfigBean;
|
||||
@Autowired
|
||||
private TableStoreConf tableStoreConf;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
TableStoreGridConfig config = new TableStoreGridConfig();
|
||||
config.setTableStoreEndpoint(tableStoreConf.getEndpoint());
|
||||
config.setAccessId(tableStoreConf.getAccessId());
|
||||
config.setAccessKey(tableStoreConf.getAccessKey());
|
||||
config.setTableStoreInstance(tableStoreConf.getInstanceName());
|
||||
config.setDataTableName(tableConfigBean.getDataTableName());
|
||||
config.setMetaTableName(tableConfigBean.getMetaTableName());
|
||||
tableStoreGrid = new TableStoreGrid(config);
|
||||
}
|
||||
|
||||
public void close() {
|
||||
if (tableStoreGrid != null) {
|
||||
tableStoreGrid.close();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
package com.htfp.weather.griddata.operation;
|
||||
|
||||
import com.alicloud.openservices.tablestore.model.TableOptions;
|
||||
import com.alicloud.openservices.tablestore.model.search.FieldSchema;
|
||||
import com.alicloud.openservices.tablestore.model.search.FieldType;
|
||||
import com.alicloud.openservices.tablestore.model.search.IndexSchema;
|
||||
import com.htfp.weather.griddata.common.TableConfig;
|
||||
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* @Author : shiyi
|
||||
* @Date : 2024/1/15 15:10
|
||||
* @Description : 创建表
|
||||
*/
|
||||
public class CreateTable extends BaseTableOperation {
|
||||
|
||||
/**
|
||||
* we must create store before we can use it.
|
||||
* @throws Exception
|
||||
*/
|
||||
private void createStore() throws Exception {
|
||||
TableOptions tableOptions = new TableOptions(TableConfig.TIME_TO_LIVE, 1);
|
||||
this.tableStoreGrid.createStore(tableOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* this example create an index which contains these columns: status, tag1, tag2, create_time.
|
||||
* you can create an index which contains any other columns.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
private void createIndex() throws Exception {
|
||||
IndexSchema indexSchema = new IndexSchema();
|
||||
indexSchema.setFieldSchemas(Arrays.asList(
|
||||
new FieldSchema("status", FieldType.KEYWORD).setIndex(true).setEnableSortAndAgg(true),
|
||||
new FieldSchema("create_time", FieldType.LONG).setIndex(true).setEnableSortAndAgg(true),
|
||||
new FieldSchema("ref_time", FieldType.LONG).setIndex(true).setEnableSortAndAgg(true)
|
||||
));
|
||||
this.tableStoreGrid.createMetaIndex(TableConfig.META_INDEX_NAME, indexSchema);
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
CreateTable example = new CreateTable();
|
||||
try {
|
||||
example.createStore();
|
||||
example.createIndex();
|
||||
} finally {
|
||||
example.close();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,137 @@
|
||||
package com.htfp.weather.griddata.operation;
|
||||
|
||||
import com.aliyun.tablestore.grid.GridDataFetcher;
|
||||
import com.aliyun.tablestore.grid.model.GridDataSet;
|
||||
|
||||
import com.htfp.weather.griddata.common.TableConfigBean;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.annotation.DependsOn;
|
||||
import org.springframework.stereotype.Component;
|
||||
import ucar.ma2.Array;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @Author : shiyi
|
||||
* @Date : 2024/1/22 13:53
|
||||
* @Description : 根据维度信息获取数据
|
||||
*/
|
||||
@Slf4j @Component
|
||||
@DependsOn({"tableStoreConf","tableConfigBean"})
|
||||
public class GfsDataFetcher extends BaseTableOperation {
|
||||
@Resource
|
||||
TableConfigBean tableConfigBean;
|
||||
|
||||
/**
|
||||
* 获取指定变量的四维数据(time, lev, lat, lon)
|
||||
* @param dataSetId 数据id
|
||||
* @param variables 变量名列表
|
||||
* @param origin 维度起始索引
|
||||
* @param shape 数据形状
|
||||
* @return {@link GridDataSet}
|
||||
* @throws Exception
|
||||
*/
|
||||
public GridDataSet queryByTableStore(String dataSetId, List<String> variables, int[] origin, int[] shape) throws Exception {
|
||||
GridDataFetcher fetcher = tableStoreGrid.getDataFetcher(tableStoreGrid.getDataSetMeta(dataSetId));
|
||||
fetcher.setVariablesToGet(variables);
|
||||
fetcher.setOriginShape(origin, shape);
|
||||
GridDataSet gridDataSet = fetcher.fetch();
|
||||
// Grid4D grid4D = fetcher.fetch().getVariable(variable);
|
||||
return gridDataSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定变量的二维全平面数据
|
||||
* @param variable 变量名
|
||||
* @param iLev 高度索引
|
||||
* @return {@link Array}
|
||||
* @throws Exception
|
||||
*/
|
||||
public Array getPlane(String dataSetId, String variable, int iTime, int iLev) throws Exception {
|
||||
int[] origin = new int[] {iTime, iLev, 0, 0};
|
||||
int[] shape = new int[] {1, 1, tableConfigBean.latSize, tableConfigBean.lonSize};
|
||||
GridDataSet gridDataSet = queryByTableStore(dataSetId, Collections.singletonList(variable),
|
||||
origin, shape);
|
||||
Array array = gridDataSet.getVariable(variable).toArray();
|
||||
System.out.println("Shape: " + array.shapeToString());
|
||||
System.out.println("Data: " + array);
|
||||
return array;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取给定变量的二维平面范围数据
|
||||
* @param variable 变量名
|
||||
* @param iLev 高度索引
|
||||
* @param iLonStart 起始经度索引
|
||||
* @param iLatLength 纬度格点数量
|
||||
* @param iLonLength 经度格点数量
|
||||
* @return {@link Array}
|
||||
* @throws Exception
|
||||
*/
|
||||
public Array getPlane(String dataSetId, String variable, int iTime, int iLev, int iLatStart, int iLonStart, int iLatLength, int iLonLength) throws Exception {
|
||||
int[] origin = new int[] {iTime, iLev, iLatStart, iLonStart};
|
||||
int[] shape = new int[] {1, 1, iLatLength, iLonLength};
|
||||
GridDataSet gridDataSet = queryByTableStore(dataSetId, Collections.singletonList(variable),
|
||||
origin, shape);
|
||||
Array array = gridDataSet.getVariable(variable).toArray();
|
||||
System.out.println("Shape: " + array.shapeToString());
|
||||
System.out.println("Data: " + array);
|
||||
return array;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定变量在某位置随高度的分布
|
||||
* @param variable 变量名
|
||||
* @param iLat 纬度索引
|
||||
* @param iLon 经度索引
|
||||
* @return {@link Array}
|
||||
* @throws Exception
|
||||
*/
|
||||
public Array getProfile(String dataSetId, String variable, int iTime, int iLat, int iLon) throws Exception {
|
||||
int[] origin = new int[] {iTime, 0, iLat, iLon};
|
||||
int[] shape = new int[] {1, tableConfigBean.levSize, 1, 1};
|
||||
GridDataSet gridDataSet = queryByTableStore(dataSetId, Collections.singletonList(variable),
|
||||
origin, shape);
|
||||
Array array = gridDataSet.getVariable(variable).toArray();
|
||||
return array;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定变量在某经纬高处的预报序列
|
||||
* @param dataSetId 数据集ID
|
||||
* @param variable 变量名
|
||||
* @param iLev 高度索引
|
||||
* @param iLat 纬度索引
|
||||
* @param iLon 经度索引
|
||||
* @throws Exception
|
||||
*/
|
||||
public Array getSeries(String dataSetId, String variable, int[] iTimeList, int iLev, int iLat, int iLon) throws Exception {
|
||||
int[] origin = new int[] {iTimeList[0], iLev, iLat, iLon};
|
||||
int[] shape = new int[] {iTimeList.length, 1, 1, 1};
|
||||
GridDataSet gridDataSet = queryByTableStore(dataSetId, Collections.singletonList(variable), origin, shape);
|
||||
Array array = gridDataSet.getVariable(variable).toArray();
|
||||
System.out.println("Shape: " + array.shapeToString());
|
||||
System.out.println("Data: " + array);
|
||||
return array;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定变量在某位置随时间的变化
|
||||
* @param dataSetId 数据集ID
|
||||
* @param variableList 变量名列表
|
||||
* @param iTImes 时间索引数组
|
||||
* @param iLev 高度索引
|
||||
* @param iLat 纬度索引
|
||||
* @param iLon 经度索引
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public GridDataSet getSeries(String dataSetId, List<String> variableList, int[] iTImes, int iLev, int iLat, int iLon) throws Exception {
|
||||
int[] origin = new int[] {iTImes[0], iLev, iLat, iLon};
|
||||
int[] shape = new int[] {iTImes.length, 1, 1, 1};
|
||||
return queryByTableStore(dataSetId, variableList, origin, shape);
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package com.htfp.weather.griddata.operation;
|
||||
|
||||
/**
|
||||
* @Author : shiyi
|
||||
* @Date : 2024/2/2 13:47
|
||||
* @Description : 获取数据
|
||||
*/
|
||||
public interface IDataFetch {
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
package com.htfp.weather.griddata.operation;
|
||||
|
||||
import com.alicloud.openservices.tablestore.model.search.sort.FieldSort;
|
||||
import com.alicloud.openservices.tablestore.model.search.sort.Sort;
|
||||
import com.alicloud.openservices.tablestore.model.search.sort.SortOrder;
|
||||
import com.aliyun.tablestore.grid.core.QueryBuilder;
|
||||
import com.aliyun.tablestore.grid.model.GridDataSetMeta;
|
||||
import com.aliyun.tablestore.grid.model.QueryGridDataSetResult;
|
||||
import com.aliyun.tablestore.grid.model.QueryParams;
|
||||
import com.htfp.weather.griddata.common.TableConfigBean;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @Author : shiyi
|
||||
* @Date : 2024/3/4 17:45
|
||||
* @Description : 查询属性表
|
||||
*/
|
||||
@Component
|
||||
public class QueryMeta extends BaseTableOperation {
|
||||
@Resource
|
||||
TableConfigBean tableConfigBean;
|
||||
/**
|
||||
* 查询最新的数据集信息
|
||||
*
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public GridDataSetMeta getLastGridDataSetMeta() throws Exception {
|
||||
|
||||
QueryGridDataSetResult result = tableStoreGrid.queryDataSets(
|
||||
tableConfigBean.metaIndexName,
|
||||
QueryBuilder.and()
|
||||
.equal("status", "DONE")
|
||||
.build(),
|
||||
new QueryParams(0, 10, new Sort(Collections.singletonList(new FieldSort("reference_time", SortOrder.DESC)))));
|
||||
List<GridDataSetMeta> gridDataSetMetas = result.getGridDataSetMetas();
|
||||
if (CollectionUtils.isEmpty(gridDataSetMetas)) {
|
||||
throw new RuntimeException("meta table为空");
|
||||
}
|
||||
return gridDataSetMetas.get(0);
|
||||
}
|
||||
public String queryLastReferenceTime() throws Exception {
|
||||
GridDataSetMeta gridDataSetMeta = getLastGridDataSetMeta();
|
||||
return gridDataSetMeta.getGridDataSetId();
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
package com.htfp.weather.griddata.operation;
|
||||
|
||||
import com.alicloud.openservices.tablestore.model.TableOptions;
|
||||
import com.htfp.weather.griddata.common.TableConfig;
|
||||
|
||||
/**
|
||||
* @Author : shiyi
|
||||
* @Date : 2024/2/3 17:54
|
||||
* @Description :
|
||||
*/
|
||||
public class UpdateTable extends BaseTableOperation {
|
||||
|
||||
private void update() throws Exception {
|
||||
TableOptions tableOptions = new TableOptions(TableConfig.TIME_TO_LIVE);
|
||||
this.tableStoreGrid.updateStoreOption(tableOptions);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
TableConfig.initDatasetConfig();
|
||||
UpdateTable example = new UpdateTable();
|
||||
try {
|
||||
example.update();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
example.close();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
package com.htfp.weather.info;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @Author : shiyi
|
||||
* @Date : 2024/4/18 13:37
|
||||
* @Description : 彩云天气相关映射
|
||||
*/
|
||||
public class CaiYunInfo {
|
||||
private static final Map<String, String> skyconMap = new HashMap<>();
|
||||
private static final Map<String, String> alertNameMap = new HashMap<>();
|
||||
private static final Map<String, String> alertColorMap = new HashMap<>();
|
||||
static {
|
||||
// 彩云天气天气现象映射
|
||||
skyconMap.put("CLEAR_DAY", "晴(白天)");
|
||||
skyconMap.put("CLEAR_NIGHT", "晴(夜间)");
|
||||
skyconMap.put("PARTLY_CLOUDY_DAY", "多云(白天)");
|
||||
skyconMap.put("PARTLY_CLOUDY_NIGHT", "多云(夜间)");
|
||||
skyconMap.put("CLOUDY", "阴");
|
||||
skyconMap.put("LIGHT_HAZE", "轻度雾霾");
|
||||
skyconMap.put("MODERATE_HAZE", "中度雾霾");
|
||||
skyconMap.put("HEAVY_HAZE", "重度雾霾");
|
||||
skyconMap.put("LIGHT_RAIN", "小雨");
|
||||
skyconMap.put("MODERATE_RAIN", "中雨");
|
||||
skyconMap.put("HEAVY_RAIN", "大雨");
|
||||
skyconMap.put("STORM_RAIN", "暴雨");
|
||||
skyconMap.put("FOG", "雾");
|
||||
skyconMap.put("LIGHT_SNOW", "小雪");
|
||||
skyconMap.put("MODERATE_SNOW", "中雪");
|
||||
skyconMap.put("HEAVY_SNOW", "大雪");
|
||||
skyconMap.put("STORM_SNOW", "暴雪");
|
||||
skyconMap.put("DUST", "浮尘");
|
||||
skyconMap.put("SAND", "沙尘");
|
||||
skyconMap.put("WIND", "大风");
|
||||
skyconMap.put("THUNDER_SHOWER", "雷阵雨");
|
||||
skyconMap.put("HAIL", "冰雹");
|
||||
skyconMap.put("SLEET", "雨夹雪");
|
||||
|
||||
|
||||
// 彩云天气预警类型映射
|
||||
alertNameMap.put("01", "台风");
|
||||
alertNameMap.put("02", "暴雨");
|
||||
alertNameMap.put("03", "暴雪");
|
||||
alertNameMap.put("04", "寒潮");
|
||||
alertNameMap.put("05", "大风");
|
||||
alertNameMap.put("06", "沙尘暴");
|
||||
alertNameMap.put("07", "高温");
|
||||
alertNameMap.put("08", "干旱");
|
||||
alertNameMap.put("09", "雷电");
|
||||
alertNameMap.put("10", "冰雹");
|
||||
alertNameMap.put("11", "霜冻");
|
||||
alertNameMap.put("12", "大雾");
|
||||
alertNameMap.put("13", "霾");
|
||||
alertNameMap.put("14", "道路结冰");
|
||||
alertNameMap.put("15", "森林火险");
|
||||
alertNameMap.put("16", "雷雨大风");
|
||||
alertNameMap.put("17", "春季沙尘天气趋势预警");
|
||||
alertNameMap.put("18", "沙尘");
|
||||
//
|
||||
alertColorMap.put("00", "白色");
|
||||
alertColorMap.put("01", "蓝色");
|
||||
alertColorMap.put("02", "黄色");
|
||||
alertColorMap.put("03", "橙色");
|
||||
alertColorMap.put("04", "红色");
|
||||
|
||||
}
|
||||
|
||||
public static String getSkyConName(String skycon) {
|
||||
return skyconMap.getOrDefault(skycon, "未知天气现象");
|
||||
}
|
||||
|
||||
public static String getAlertName(String code) {
|
||||
return alertNameMap.getOrDefault(code.substring(0,2), "未知预警类型");
|
||||
}
|
||||
public static String getAlertColor(String code) {
|
||||
return alertColorMap.getOrDefault(code.substring(2,4), "未知预警等级");
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package com.htfp.weather.info;
|
||||
|
||||
/**
|
||||
* @Author : shiyi
|
||||
* @Date : 2024/5/8 12:02
|
||||
* @Description :
|
||||
*/
|
||||
public class Constant {
|
||||
public static final String DATA_SET_ID_FORMAT_STRING = "'UTC-'yyyyMMdd.HH";
|
||||
public static final String DATA_FOLDER_STRING = "'UTC-'yyyyMMdd.HH";
|
||||
public static final String UTC_TIME_STRING = "'UTC-'yyyyMMdd.HH";
|
||||
public static final String BJT_TIME_STRING = "'BJT-'yyyyMMdd.HH";
|
||||
public static final String API_TIME_STRING = "yyyy-MM-dd'T'HH:mmxxx";
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
package com.htfp.weather.info;
|
||||
|
||||
/**
|
||||
* @Author : shiyi
|
||||
* @Date : 2024/4/28 16:31
|
||||
* @Description : GFS变量枚举
|
||||
*/
|
||||
public enum GfsDownloadVariableEnum {
|
||||
//
|
||||
TEMPERATURE("TMP", "温度"),
|
||||
U_WIND("UGRD", "东西风分量"),
|
||||
V_WIND("VGRD", "南北风分量"),
|
||||
CLOUD("TCDC", "云量"),
|
||||
RELATIVE_HUMIDITY("RH", "相对湿度"),
|
||||
VERTICAL_VELOCITY("DZDT", "垂直速度"),
|
||||
|
||||
;
|
||||
private final String code;
|
||||
private final String info;
|
||||
|
||||
GfsDownloadVariableEnum(String code, String info) {
|
||||
this.code = code;
|
||||
this.info = info;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public String getInfo() {
|
||||
return info;
|
||||
}
|
||||
|
||||
public static boolean contains(String test) {
|
||||
for (GfsDownloadVariableEnum c : GfsDownloadVariableEnum.values()) {
|
||||
if (c.getCode().equals(test)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
package com.htfp.weather.info;
|
||||
|
||||
/**
|
||||
* @Author : shiyi
|
||||
* @Date : 2024/4/28 16:45
|
||||
* @Description : 高度层枚举
|
||||
*/
|
||||
public enum GfsLevelsEnum {
|
||||
//
|
||||
SURFACE(9999, "地面"),
|
||||
PRES_1000hPa(1000, "1000 hPa"),
|
||||
PRES_975hPa(975, "975 hPa"),
|
||||
PRES_950hPa(950, "950 hPa"),
|
||||
PRES_925hPa(925, "925 hPa"),
|
||||
PRES_900hPa(900, "900 hPa"),
|
||||
PRES_850hPa(850, "850 hPa"),
|
||||
PRES_800hPa(800, "800 hPa"),
|
||||
PRES_750hPa(750, "750 hPa"),
|
||||
PRES_700hPa(700, "700 hPa"),
|
||||
PRES_650hPa(650, "650 hPa"),
|
||||
PRES_600hPa(600, "600 hPa"),
|
||||
PRES_550hPa(550, "550 hPa"),
|
||||
PRES_500hPa(500, "500 hPa"),
|
||||
PRES_450hPa(450, "450 hPa"),
|
||||
PRES_400hPa(400, "400 hPa"),
|
||||
PRES_350hPa(350, "350 hPa"),
|
||||
|
||||
;
|
||||
|
||||
|
||||
private final Integer code;
|
||||
private final String info;
|
||||
|
||||
GfsLevelsEnum(Integer code, String info) {
|
||||
this.code = code;
|
||||
this.info = info;
|
||||
}
|
||||
|
||||
public Integer getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public String getInfo() {
|
||||
return info;
|
||||
}
|
||||
public static boolean contains(Integer test) {
|
||||
for (GfsLevelsEnum c : GfsLevelsEnum.values()) {
|
||||
if (c.getCode().equals(test)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package com.htfp.weather.utils;
|
||||
|
||||
/**
|
||||
* @Author : shiyi
|
||||
* @Date : 2024/4/25 18:31
|
||||
* @Description : 文件下载https://www.jianshu.com/p/3b269082cbbb
|
||||
*/
|
||||
public class DownloadUtils {
|
||||
}
|
@ -0,0 +1,86 @@
|
||||
package com.htfp.weather.utils;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Request.Builder;
|
||||
import okhttp3.Response;
|
||||
import okhttp3.ResponseBody;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* @Author : shiyi
|
||||
* @Date : 2024/1/23 16:19
|
||||
* @Description : HttpClient工具类
|
||||
*/
|
||||
@Slf4j
|
||||
public class HttpClientUtils {
|
||||
private static final OkHttpClient OKHTTP_CLIENT = new OkHttpClient.Builder()
|
||||
.connectTimeout(30, TimeUnit.SECONDS)
|
||||
.readTimeout(60, TimeUnit.SECONDS)
|
||||
.writeTimeout(60, TimeUnit.SECONDS)
|
||||
.build();
|
||||
|
||||
// public static <T> T sendGet(String url, Map<String, String> params, Class<T> responseClass) {
|
||||
// MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<>();
|
||||
// if (params != null) {
|
||||
// params.forEach(queryParams::add);
|
||||
// }
|
||||
// Mono<T> mono = WebClient.create(url).method(HttpMethod.GET)
|
||||
// .uri(uriBuilder -> uriBuilder
|
||||
// .queryParams(queryParams)
|
||||
// .build()).retrieve().bodyToMono(responseClass);
|
||||
// T responseBody;
|
||||
// try {
|
||||
// responseBody = mono.block();
|
||||
// } catch (WebClientResponseException e) {
|
||||
// log.error("Get 请求错误, {}", e.getMessage());
|
||||
// return null;
|
||||
// }
|
||||
// return responseBody;
|
||||
// }
|
||||
public static <T> T sendGet(String url, Map<String, String> params, Class<T> responseClass) throws Exception {
|
||||
String jsonStr = sendGet(url, params);
|
||||
return JSONUtils.json2pojo(jsonStr, responseClass);
|
||||
}
|
||||
public static String sendGet(String url, Map<String, String> params) throws IOException {
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
if (!CollectionUtils.isEmpty(params)) {
|
||||
params.keySet().forEach(res -> {
|
||||
if (StringUtils.isNotBlank(stringBuilder)) {
|
||||
stringBuilder.append("&");
|
||||
} else {
|
||||
stringBuilder.append("?");
|
||||
}
|
||||
try {
|
||||
stringBuilder.append(String.format("%s=%s", res, URLEncoder.encode(params.get(res), "UTF-8")));
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
Request request = new Builder()
|
||||
.url(url + stringBuilder)
|
||||
.build();
|
||||
|
||||
try (Response response = OKHTTP_CLIENT.newCall(request).execute()) {
|
||||
if (!response.isSuccessful()) {
|
||||
throw new IOException("okhttp Unexpected code " + response);
|
||||
}
|
||||
ResponseBody body = response.body();
|
||||
if (body != null) {
|
||||
return body.string();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,92 @@
|
||||
package com.htfp.weather.utils;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class JSONUtils {
|
||||
|
||||
private final static ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
private JSONUtils() {
|
||||
|
||||
}
|
||||
|
||||
public static ObjectMapper getInstance() {
|
||||
|
||||
return objectMapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* javaBean,list,array convert to json string
|
||||
*/
|
||||
public static String obj2json(Object obj) throws Exception {
|
||||
return objectMapper.writeValueAsString(obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* json string convert to javaBean
|
||||
*/
|
||||
public static <T> T json2pojo(String jsonStr, Class<T> clazz)
|
||||
throws Exception {
|
||||
return objectMapper.readValue(jsonStr, clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* json string convert to map
|
||||
*/
|
||||
public static <T> Map<String, Object> json2map(String jsonStr)
|
||||
throws Exception {
|
||||
return objectMapper.readValue(jsonStr, Map.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* json string convert to map with javaBean
|
||||
*/
|
||||
public static <T> Map<String, T> json2map(String jsonStr, Class<T> clazz)
|
||||
throws Exception {
|
||||
Map<String, Map<String, Object>> map = (Map<String, Map<String, Object>>) objectMapper.readValue(jsonStr,
|
||||
new TypeReference<Map<String, T>>() {
|
||||
});
|
||||
Map<String, T> result = new HashMap<String, T>();
|
||||
for (Map.Entry<String, Map<String, Object>> entry : map.entrySet()) {
|
||||
result.put(entry.getKey(), map2pojo(entry.getValue(), clazz));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* json array string convert to list with javaBean
|
||||
*/
|
||||
public static <T> List<T> json2list(String jsonArrayStr, Class<T> clazz)
|
||||
throws Exception {
|
||||
List<Map<String, Object>> list = (List<Map<String, Object>>) objectMapper.readValue(jsonArrayStr,
|
||||
new TypeReference<List<T>>() {
|
||||
});
|
||||
List<T> result = new ArrayList<T>();
|
||||
for (Map<String, Object> map : list) {
|
||||
result.add(map2pojo(map, clazz));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* map convert to javaBean
|
||||
*/
|
||||
public static <T> T map2pojo(Map map, Class<T> clazz) {
|
||||
return objectMapper.convertValue(map, clazz);
|
||||
}
|
||||
|
||||
public static void pojo2jsonFile(Object obj, String filePath) throws IOException {
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
|
||||
objectMapper.writeValue(new File(filePath), obj);
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
package com.htfp.weather.utils;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @Author : shiyi
|
||||
* @Date : 2024/1/22 20:05
|
||||
* @Description : 多维数组工具类
|
||||
*/
|
||||
public class NdArrayUtils {
|
||||
/**
|
||||
* 查找距离目标值最近的索引
|
||||
*
|
||||
* @param list
|
||||
* @param target
|
||||
* @return
|
||||
*/
|
||||
public static int findNearestIndex(double[] list, double target) {
|
||||
int size = list.length;
|
||||
if (size == 0) {
|
||||
return -1;
|
||||
}
|
||||
if (size == 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int index = Arrays.binarySearch(list, target);
|
||||
if (index >= 0) {
|
||||
return index;
|
||||
}
|
||||
|
||||
// 插入点,即最大的小于等于目标值的元素索引
|
||||
int insertPoint = -(index + 1);
|
||||
if (insertPoint > 1 && Math.abs(list[insertPoint - 1] - target) <= Math.abs(list[insertPoint] - target)) {
|
||||
return insertPoint - 1;
|
||||
}
|
||||
return insertPoint;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
package com.htfp.weather.utils;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @Author : shiyi
|
||||
* @Date : 2024/1/5 15:51
|
||||
* @Description : Spring工具类
|
||||
*/
|
||||
|
||||
@Component
|
||||
public class SpringUtil<T> implements ApplicationContextAware {
|
||||
|
||||
private static ApplicationContext applicationContext;
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
if(SpringUtil.applicationContext == null) {
|
||||
SpringUtil.applicationContext = applicationContext;
|
||||
}
|
||||
}
|
||||
|
||||
//获取applicationContext
|
||||
public static ApplicationContext getApplicationContext() {
|
||||
return applicationContext;
|
||||
}
|
||||
|
||||
//通过name获取 Bean
|
||||
public static Object getBean(String name){
|
||||
return getApplicationContext().getBean(name);
|
||||
}
|
||||
|
||||
//通过class获取Bean.
|
||||
public static <T> T getBean(Class<T> clazz){
|
||||
return getApplicationContext().getBean(clazz);
|
||||
}
|
||||
|
||||
//通过name,以及Clazz返回指定的Bean
|
||||
public static <T> T getBean(String name,Class<T> clazz){
|
||||
return getApplicationContext().getBean(name, clazz);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package com.htfp.weather.web.config;
|
||||
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
||||
import org.springframework.web.filter.CorsFilter;
|
||||
|
||||
@Configuration
|
||||
public class CORSFilter {
|
||||
|
||||
@Bean
|
||||
public CorsFilter corsFilter(){
|
||||
CorsConfiguration corsConfiguration = new CorsConfiguration();
|
||||
corsConfiguration.addAllowedHeader("*");
|
||||
corsConfiguration.addAllowedOrigin("*");
|
||||
corsConfiguration.addAllowedMethod("*");
|
||||
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
|
||||
source.registerCorsConfiguration("/**",corsConfiguration);
|
||||
return new CorsFilter(source);
|
||||
}
|
||||
}
|
@ -0,0 +1,113 @@
|
||||
package com.htfp.weather.web.controller;
|
||||
|
||||
import com.htfp.weather.download.FileInfo;
|
||||
import com.htfp.weather.download.GfsDataConfig;
|
||||
import com.htfp.weather.download.GfsDownloader;
|
||||
import com.htfp.weather.griddata.common.TableConfigBean;
|
||||
import com.htfp.weather.griddata.operation.GfsDataImport;
|
||||
import com.htfp.weather.web.exception.AppExcpetion;
|
||||
import com.htfp.weather.web.exception.ErrorCode;
|
||||
import com.htfp.weather.web.pojo.response.Result;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.IOException;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @Author : shiyi
|
||||
* @Date : 2024/4/21 15:56
|
||||
* @Description : 配置文件管理
|
||||
*/
|
||||
@CrossOrigin
|
||||
@RestController
|
||||
@RequestMapping("/htfp/weather/config")
|
||||
public class ConfigController {
|
||||
@Resource
|
||||
TableConfigBean tableConfigBean;
|
||||
@Resource
|
||||
GfsDataConfig gfsDataConfig;
|
||||
@Resource
|
||||
GfsDownloader gfsDownloader;
|
||||
@Resource
|
||||
GfsDataImport gfsDataImport;
|
||||
|
||||
private final String SECRET = "htfpweather";
|
||||
|
||||
private void validSecret(String secret) {
|
||||
if (!SECRET.equals(secret)) {
|
||||
throw new AppExcpetion(ErrorCode.SECRET_ERROR);
|
||||
}
|
||||
}
|
||||
@RequestMapping("/queryDatabaseConfig")
|
||||
public Result queryDatabaseConfig() {
|
||||
return Result.success(tableConfigBean);
|
||||
}
|
||||
|
||||
@RequestMapping("/updateDatabaseConfig")
|
||||
public Result updateDatabaseConfig(@RequestParam String secret, @Validated @RequestBody TableConfigBean updateConfig) {
|
||||
validSecret(secret);
|
||||
if (updateConfig == null) {
|
||||
throw new AppExcpetion(ErrorCode.CONFIG_ERROR, "配置文件不能为空");
|
||||
}
|
||||
updateConfig.valid();
|
||||
try {
|
||||
tableConfigBean.writeConfig(updateConfig);
|
||||
} catch (IOException e) {
|
||||
throw new AppExcpetion(ErrorCode.CONFIG_ERROR, e);
|
||||
}
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
@RequestMapping("/queryDataSourceConfig")
|
||||
public Result queryDataSourceConfig() {
|
||||
return Result.success(gfsDataConfig);
|
||||
}
|
||||
|
||||
@RequestMapping("/updateDataSourceConfig")
|
||||
public Result updateDataSourceConfig(@RequestParam String secret, @Validated @RequestBody GfsDataConfig updateConfig) {
|
||||
validSecret(secret);
|
||||
if (updateConfig == null) {
|
||||
throw new AppExcpetion(ErrorCode.CONFIG_ERROR, "配置文件不能为空");
|
||||
}
|
||||
updateConfig.valid();
|
||||
try {
|
||||
gfsDataConfig.writeConfig(updateConfig);
|
||||
} catch (IOException e) {
|
||||
throw new AppExcpetion(ErrorCode.CONFIG_ERROR, e);
|
||||
}
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
@RequestMapping("/download")
|
||||
public Result download(@RequestParam String secret) {
|
||||
validSecret(secret);
|
||||
try {
|
||||
gfsDownloader.iniTimeSetting();
|
||||
List<FileInfo> fileInfoList = gfsDownloader.getFilesInfo();
|
||||
gfsDownloader.downloadAll(fileInfoList);
|
||||
return Result.success(fileInfoList);
|
||||
} catch (Exception e) {
|
||||
return Result.error(ErrorCode.DOWNLOAD_START_ERROR, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@RequestMapping("/import")
|
||||
public Result importData(@RequestBody Map<String, String> params) {
|
||||
String secret = params.get("secret");
|
||||
validSecret(secret);
|
||||
OffsetDateTime time = OffsetDateTime.parse(params.get("time"));
|
||||
try {
|
||||
gfsDataImport.importData(time);
|
||||
return Result.success();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return Result.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package com.htfp.weather.web.controller;
|
||||
|
||||
import com.htfp.weather.web.exception.AppExcpetion;
|
||||
import com.htfp.weather.web.exception.ErrorCode;
|
||||
import com.htfp.weather.web.pojo.response.Result;
|
||||
import org.springframework.validation.BindException;
|
||||
import org.springframework.validation.ObjectError;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
|
||||
/**
|
||||
* @Author : shiyi
|
||||
* @Date : 2024/3/14 16:28
|
||||
* @Description : 校验异常捕获
|
||||
*/
|
||||
@RestControllerAdvice
|
||||
public class ControllerExceptionAdvice {
|
||||
|
||||
@ExceptionHandler({BindException.class})
|
||||
public Result methodArgumentNotValidExceptionHandler(BindException e) {
|
||||
// 从异常对象中拿到ObjectError对象
|
||||
ObjectError objectError = e.getBindingResult().getAllErrors().get(0);
|
||||
return Result.error(ErrorCode.VALIDATE_ERROR, objectError.getDefaultMessage());
|
||||
}
|
||||
|
||||
// @ExceptionHandler({Exception.class})
|
||||
// public Result otherExceptionHandler(Exception e) {
|
||||
// return Result.error(e);
|
||||
// }
|
||||
|
||||
@ExceptionHandler({AppExcpetion.class})
|
||||
public Result appExceptionHandler(AppExcpetion e) {
|
||||
return Result.error(e.getErrorCode(), e.getMessage());
|
||||
}
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
package com.htfp.weather.web.controller;
|
||||
|
||||
import com.htfp.weather.web.pojo.hefeng.HeFengWarningResponse;
|
||||
import com.htfp.weather.web.pojo.request.Position2D;
|
||||
import com.htfp.weather.web.pojo.response.NowWeatherStatus;
|
||||
import com.htfp.weather.web.pojo.response.Result;
|
||||
import com.htfp.weather.web.pojo.response.SurfaceWeatherWarning;
|
||||
import com.htfp.weather.web.pojo.response.TimeSeriesDataset;
|
||||
import com.htfp.weather.web.service.surfaceapi.CaiYunServiceImpl;
|
||||
import com.htfp.weather.web.service.surfaceapi.HeFengServiceImpl;
|
||||
import com.htfp.weather.web.service.IDataService;
|
||||
import com.htfp.weather.web.service.surfaceapi.ISurfaceDataService;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @Author : shiyi
|
||||
* @Date : 2024/1/24 16:07
|
||||
* @Description : 地面天气状态
|
||||
*/
|
||||
@CrossOrigin
|
||||
@RestController
|
||||
@RequestMapping("/htfp/weather/surface/")
|
||||
public class SurfaceWeatherController {
|
||||
@Resource(name = "tablestore-gfs")
|
||||
IDataService dataService;
|
||||
@Resource(name = "caiyun")
|
||||
ISurfaceDataService surfaceDataService;
|
||||
|
||||
@PostMapping("/now")
|
||||
public Result queryNowWeather(@Validated @RequestBody Position2D position2D) throws Exception {
|
||||
double lat = position2D.getLatitude();
|
||||
double lon = position2D.getLongitude();
|
||||
NowWeatherStatus nowWeatherStatus = surfaceDataService.getNowSurfaceWeatherStatus(lat, lon);
|
||||
return Result.success(nowWeatherStatus);
|
||||
}
|
||||
|
||||
@PostMapping("/forecast")
|
||||
public Result querySurfaceForecastWeather(@Validated @RequestBody Position2D position2D) throws Exception {
|
||||
double lat = position2D.getLatitude();
|
||||
double lon = position2D.getLongitude();
|
||||
TimeSeriesDataset forecastSeries = surfaceDataService.getForecastSeries(lat, lon);
|
||||
return Result.success(forecastSeries);
|
||||
}
|
||||
|
||||
@PostMapping ("/warning")
|
||||
public Result warning(@Validated @RequestBody Position2D position2D) throws Exception {
|
||||
double lat = position2D.getLatitude();
|
||||
double lon = position2D.getLongitude();
|
||||
List<SurfaceWeatherWarning> warning = surfaceDataService.getSurfaceWarning(lat, lon);
|
||||
return Result.success(warning);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package com.htfp.weather.web.controller;
|
||||
|
||||
import com.htfp.weather.griddata.common.TableConfigBean;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* @Author : shiyi
|
||||
* @Date : 2024/4/20 17:30
|
||||
* @Description :
|
||||
*/
|
||||
@Controller
|
||||
public class ThymeleafTest {
|
||||
@Resource
|
||||
TableConfigBean tableConfigBean;
|
||||
|
||||
@GetMapping("index")// 页面的url地址
|
||||
public String getindex(Model model, String secret) {
|
||||
if (!"shiyi".equals(secret)){
|
||||
return "wrong";
|
||||
}
|
||||
model.addAttribute("tableConfig", tableConfigBean);
|
||||
return "index";// 与templates中index.html对应
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
package com.htfp.weather.web.controller;
|
||||
|
||||
import com.htfp.weather.utils.DateTimeUtils;
|
||||
import com.htfp.weather.web.pojo.request.PlaneRequest;
|
||||
import com.htfp.weather.web.pojo.request.Position3D;
|
||||
import com.htfp.weather.web.pojo.request.ProfileRequest;
|
||||
import com.htfp.weather.web.pojo.response.PlaneResponse;
|
||||
import com.htfp.weather.web.pojo.response.ProfileResponse;
|
||||
import com.htfp.weather.web.pojo.response.Result;
|
||||
import com.htfp.weather.web.pojo.response.TimeSeriesDataset;
|
||||
import com.htfp.weather.web.service.GfsDataServiceImpl;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.time.OffsetDateTime;
|
||||
|
||||
/**
|
||||
* @Author : shiyi
|
||||
* @Date : 2024/5/8 15:15
|
||||
* @Description :
|
||||
*/
|
||||
@CrossOrigin
|
||||
@RestController
|
||||
@RequestMapping("/htfp/weather/upper/")
|
||||
public class UpperWeatherController {
|
||||
|
||||
@Resource(name = "tablestore-gfs")
|
||||
GfsDataServiceImpl tablestoreService;
|
||||
|
||||
@RequestMapping("/profileByPressure")
|
||||
public Result queryProfile(@Validated @RequestBody ProfileRequest profileRequest) {
|
||||
OffsetDateTime time = OffsetDateTime.parse(profileRequest.getTime());
|
||||
OffsetDateTime utcDateTime = DateTimeUtils.getUTCDateTime(time);
|
||||
String variableName = profileRequest.getVariableName();
|
||||
double latitude = profileRequest.getLatitude();
|
||||
double longitude = profileRequest.getLongitude();
|
||||
ProfileResponse profileResponse = tablestoreService.getProfile(utcDateTime, variableName, latitude, longitude);
|
||||
return Result.success(profileResponse);
|
||||
}
|
||||
|
||||
@PostMapping("/forecast")
|
||||
public Result queryTimeSeries(@Validated @RequestBody Position3D position3D) {
|
||||
double latitude = position3D.getLatitude();
|
||||
double longitude = position3D.getLongitude();
|
||||
int level = position3D.getLevel();
|
||||
TimeSeriesDataset forecastSeries = tablestoreService.getForecastSeries(latitude, longitude, level);
|
||||
return Result.success(forecastSeries);
|
||||
}
|
||||
|
||||
@PostMapping("/plane")
|
||||
public Result queryPlane(@Validated @RequestBody PlaneRequest planeRequest) {
|
||||
planeRequest.valid();
|
||||
String variableName = planeRequest.getVariableName();
|
||||
OffsetDateTime time = OffsetDateTime.parse(planeRequest.getTime());
|
||||
OffsetDateTime utcDateTime = DateTimeUtils.getUTCDateTime(time);
|
||||
int level = planeRequest.getLevel();
|
||||
double minLat = planeRequest.getMinLat();
|
||||
double maxLat = planeRequest.getMaxLat();
|
||||
double minLon = planeRequest.getMinLon();
|
||||
double maxLon = planeRequest.getMaxLon();
|
||||
PlaneResponse forecastSeries = tablestoreService.getPlane(utcDateTime, variableName, level, minLat, maxLat, minLon, maxLon);
|
||||
return Result.success(forecastSeries);
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package com.htfp.weather.web.exception;
|
||||
|
||||
/**
|
||||
* @Author : shiyi
|
||||
* @Date : 2024/4/16 17:21
|
||||
* @Description : 自定义异常
|
||||
*/
|
||||
public class AppExcpetion extends RuntimeException{
|
||||
ErrorCode errorCode;
|
||||
|
||||
public ErrorCode getErrorCode() {
|
||||
return errorCode;
|
||||
}
|
||||
public AppExcpetion(ErrorCode errorCode) {
|
||||
this.errorCode = errorCode;
|
||||
}
|
||||
public AppExcpetion(ErrorCode errorCode, String message) {
|
||||
super(message);
|
||||
this.errorCode = errorCode;
|
||||
}
|
||||
public AppExcpetion(ErrorCode errorCode, Throwable e) {
|
||||
super(e);
|
||||
this.errorCode = errorCode;
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
package com.htfp.weather.web.pojo.caiyun;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @Author : shiyi
|
||||
* @Date : 2024/4/15 18:52
|
||||
* @Description :
|
||||
*/
|
||||
@Data
|
||||
public class CaiYunBaseResponse {
|
||||
@JsonProperty("status")
|
||||
private String status;
|
||||
|
||||
@JsonProperty("api_version")
|
||||
private String apiVersion;
|
||||
|
||||
@JsonProperty("api_status")
|
||||
private String apiStatus;
|
||||
|
||||
@JsonProperty("lang")
|
||||
private String lang;
|
||||
|
||||
@JsonProperty("unit")
|
||||
private String unit;
|
||||
|
||||
@JsonProperty("tzshift")
|
||||
private int tzshift;
|
||||
|
||||
@JsonProperty("timezone")
|
||||
private String timeZone;
|
||||
|
||||
@JsonProperty("server_time")
|
||||
private long serverTime;
|
||||
|
||||
@JsonProperty("location")
|
||||
private List<Double> location;
|
||||
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
package com.htfp.weather.web.pojo.caiyun;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @Author : shiyi
|
||||
* @Date : 2024/4/15 18:52
|
||||
* @Description :
|
||||
*/
|
||||
@Data
|
||||
public class CaiYunForecastResponse extends CaiYunBaseResponse{
|
||||
|
||||
@JsonProperty("result")
|
||||
private HourlyResult hourlyResult;
|
||||
|
||||
// Getters and Setters
|
||||
|
||||
@Data
|
||||
public static class HourlyResult {
|
||||
private Hourly hourly;
|
||||
private int primary;
|
||||
@JsonProperty("forecast_keypoint")
|
||||
private String forecastKeypoint;
|
||||
|
||||
@Data @JsonIgnoreProperties(value = {"skycon", "apparent_temperature","dswrf", "air_quality"}, ignoreUnknown = true)
|
||||
public static class Hourly {
|
||||
private String status;
|
||||
private String description;
|
||||
private List<BaseData> precipitation;
|
||||
private List<BaseData> temperature;
|
||||
private List<Wind> wind;
|
||||
private List<BaseData> humidity;
|
||||
private List<BaseData> cloudrate;
|
||||
private List<BaseData> pressure;
|
||||
private List<BaseData> visibility;
|
||||
}
|
||||
@Data @JsonIgnoreProperties(value = {"probability"}, ignoreUnknown = true)
|
||||
public static class BaseData {
|
||||
private String datetime;
|
||||
private Float value;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class Wind {
|
||||
private String datetime;
|
||||
private Float speed;
|
||||
private Float direction;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
package com.htfp.weather.web.pojo.caiyun;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* @Author : shiyi
|
||||
* @Date : 2024/4/15 18:52
|
||||
* @Description :
|
||||
*/
|
||||
@Data
|
||||
public class CaiYunNowResponse extends CaiYunBaseResponse{
|
||||
|
||||
@JsonProperty("result")
|
||||
private NowResult nowResult;
|
||||
|
||||
// Getters and Setters
|
||||
|
||||
@Data
|
||||
public static class NowResult {
|
||||
private RealTime realtime;
|
||||
private int primary;
|
||||
|
||||
@Data @JsonIgnoreProperties(value = {"apparent_temperature","dswrf", "air_quality", "life_index"}, ignoreUnknown = true)
|
||||
public static class RealTime {
|
||||
private String status;
|
||||
private String description;
|
||||
private Precipitation precipitation;
|
||||
private Float temperature;
|
||||
private Wind wind;
|
||||
private Float humidity;
|
||||
private Float cloudrate;
|
||||
private Float pressure;
|
||||
private Float visibility;
|
||||
private String skycon;
|
||||
}
|
||||
@Data
|
||||
public static class Wind {
|
||||
private Float speed;
|
||||
private Float direction;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class Precipitation {
|
||||
private Local local;
|
||||
private Nearest nearest;
|
||||
@Data
|
||||
public static class Local {
|
||||
private String status;
|
||||
private String datasource;
|
||||
private Float intensity;
|
||||
}
|
||||
@Data
|
||||
public static class Nearest {
|
||||
private String status;
|
||||
private Float distance;
|
||||
private Float intensity;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package com.htfp.weather.web.pojo.caiyun;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @Author : shiyi
|
||||
* @Date : 2024/4/15 18:52
|
||||
* @Description :
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class CaiYunWarningResponse extends CaiYunBaseResponse {
|
||||
@JsonProperty("result")
|
||||
private AlertResult result;
|
||||
|
||||
@Data @JsonIgnoreProperties(value = {"realtime"}, ignoreUnknown = true)
|
||||
public static class AlertResult{
|
||||
Alert alert;
|
||||
@Data @JsonIgnoreProperties(value = {"abcodes"}, ignoreUnknown = true)
|
||||
public static class Alert {
|
||||
String status;
|
||||
List<AlertContent> content;
|
||||
@Data
|
||||
public static class AlertContent {
|
||||
private String province;
|
||||
private String status;
|
||||
private String code;
|
||||
private String description;
|
||||
private String regionId;
|
||||
private String county;
|
||||
private Long pubtimestamp;
|
||||
private Float[] latlon;
|
||||
private String city;
|
||||
private String alertId;
|
||||
private String title;
|
||||
private String adcode;
|
||||
private String source;
|
||||
private String location;
|
||||
@JsonProperty("request_status")
|
||||
private String requestStatus;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package com.htfp.weather.web.pojo.hefeng;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @Author : shiyi
|
||||
* @Date : 2024/1/24 15:23
|
||||
* @Description :
|
||||
*/
|
||||
@Data
|
||||
public class BaseHeFengData {
|
||||
Float temp; // 温度; // 温度
|
||||
String icon; // 天气状况和图标的代码,图标可通过"icon"字段来调用
|
||||
String text; // 天气状况的文字描述,包括阴晴雨雪等天气状态的描述
|
||||
Float wind360; // 风向360角度
|
||||
String windDir; // 风向
|
||||
String windScale; // 风力等级
|
||||
Float windSpeed; // 风速,公里/小时
|
||||
Float humidity; // 相对湿度
|
||||
Float precip; // 当前小时累计降水量,默认单位:毫米
|
||||
Float pressure; // 大气压强,默认单位:百帕
|
||||
Float cloud; // 云量
|
||||
Float dew; // 露点温度
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package com.htfp.weather.web.pojo.hefeng;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @Author : shiyi
|
||||
* @Date : 2024/4/17 15:04
|
||||
* @Description :
|
||||
*/
|
||||
@Data
|
||||
public class HeFengBaseResponse {
|
||||
String code;
|
||||
String updateTime;
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package com.htfp.weather.web.pojo.hefeng;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @Author : shiyi
|
||||
* @Date : 2024/1/23 18:01
|
||||
* @Description : 和风天气预报响应
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data @JsonIgnoreProperties(value = {"fxLink", "refer"}, ignoreUnknown = true)
|
||||
public class HeFengForecastResponse extends HeFengBaseResponse {
|
||||
|
||||
List<HeFengForecastHour> hourly;
|
||||
|
||||
@Data @EqualsAndHashCode(callSuper = true)
|
||||
public static class HeFengForecastHour extends BaseHeFengData {
|
||||
String fxTime; // 预报时间
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package com.htfp.weather.web.pojo.hefeng;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* @Author : shiyi
|
||||
* @Date : 2024/1/23 18:00
|
||||
* @Description : 和风实时天气响应
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data @JsonIgnoreProperties(value = {"fxLink", "refer"}, ignoreUnknown = true)
|
||||
public class HeFengNowResponse extends HeFengBaseResponse{
|
||||
HeFengNow now;
|
||||
@Data @EqualsAndHashCode(callSuper = true)
|
||||
public static class HeFengNow extends BaseHeFengData {
|
||||
String obsTime; // 观测时间
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
package com.htfp.weather.web.pojo.hefeng;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @Author : shiyi
|
||||
* @Date : 2024/1/23 18:00
|
||||
* @Description : 和风实时天气响应
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data @JsonIgnoreProperties(value = {"fxLink", "refer"}, ignoreUnknown = true)
|
||||
public class HeFengWarningResponse extends HeFengBaseResponse{
|
||||
List<HeFengWarning> warning;
|
||||
|
||||
@Data
|
||||
public static class HeFengWarning{
|
||||
private String id;
|
||||
private String sender;
|
||||
private String pubTime;
|
||||
private String title;
|
||||
private String startTime;
|
||||
private String endTime;
|
||||
private String status;
|
||||
private String level;
|
||||
private String severity;
|
||||
private String severityColor;
|
||||
private String type;
|
||||
private String typeName;
|
||||
private String urgency;
|
||||
private String certainty;
|
||||
private String text;
|
||||
private String related;
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package com.htfp.weather.web.pojo.request;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @Author : shiyi
|
||||
* @Date : 2024/4/21 18:34
|
||||
* @Description :
|
||||
*/
|
||||
@Data
|
||||
public class ConfigUpdate {
|
||||
String secret;
|
||||
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package com.htfp.weather.web.pojo.request;
|
||||
|
||||
import javax.validation.constraints.Max;
|
||||
import javax.validation.constraints.Min;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* @Author : shiyi
|
||||
* @Date : 2024/1/24 16:11
|
||||
* @Description : 地面位置参数
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class Position3D extends Position2D {
|
||||
@NotNull(message = "高度层次 (level) 不能为空")
|
||||
Integer level;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue