add FLEA (#15773)
diff --git a/client-cpp/src/main/Session.h b/client-cpp/src/main/Session.h
index 7d10356..c2de083 100644
--- a/client-cpp/src/main/Session.h
+++ b/client-cpp/src/main/Session.h
@@ -217,7 +217,7 @@
GORILLA = (char)8,
ZIGZAG = (char)9,
FREQ = (char)10,
- PERIOD = (char)14
+ FLEA = (char)14
};
}
diff --git a/client-py/iotdb/utils/IoTDBConstants.py b/client-py/iotdb/utils/IoTDBConstants.py
index eda947e..00c4d8b 100644
--- a/client-py/iotdb/utils/IoTDBConstants.py
+++ b/client-py/iotdb/utils/IoTDBConstants.py
@@ -61,7 +61,7 @@
GORILLA = 8
ZIGZAG = 9
FREQ = 10
- PERIOD = 14
+ FLEA = 14
# this method is implemented to avoid the issue reported by:
# https://bugs.python.org/issue30545
diff --git a/docs/UserGuide/Data-Concept/Encoding.md b/docs/UserGuide/Data-Concept/Encoding.md
index 6fe412f..4771b1c 100644
--- a/docs/UserGuide/Data-Concept/Encoding.md
+++ b/docs/UserGuide/Data-Concept/Encoding.md
@@ -64,11 +64,9 @@
ZIGZAG encoding maps signed integers to unsigned integers so that numbers with a small absolute value (for instance, -1) have a small variant encoded value too. It does this in a way that "zig-zags" back and forth through the positive and negative integers.
-* PERIOD
+* FLEA
-PERIOD encoding is suitable for encoding data that is periodic in nature. By calculating the periodicity of the data, it is possible to use lossy frequency-domain data to preserve the periodic character of the data, thus applying a smaller space for storing the residual data.
-
-For the residual data, since most of the residual data is small and a small portion of the residual data is large, PERIOD encoding employs a separate storage method, storing the high and low bits of the residual data separately.
+FLEA (Frequency-based Lossless Encoding Algorithm) is a novel lossless compression algorithm designed specifically for patterned time series. It uniquely leverages frequency-domain analysis within a rate-optimal framework, decomposing data into frequency and residual components whose encoding costs are jointly minimized by adaptively selecting a quantization parameter. By further employing a bi-regional encoding strategy with specialized coders for dense and sparse frequency data, alongside a hybrid residual encoder, FLEA achieves state-of-the-art compression ratios, particularly on data exhibiting periodic or cyclical structures.
## Correspondence between data type and encoding
diff --git a/iotdb-client/client-cpp/src/main/Session.h b/iotdb-client/client-cpp/src/main/Session.h
index 24b2622..6ab03d8 100644
--- a/iotdb-client/client-cpp/src/main/Session.h
+++ b/iotdb-client/client-cpp/src/main/Session.h
@@ -231,7 +231,7 @@
CHIMP = (char)11,
SPRINTZ = (char)12,
RLBE = (char)13,
- PERIOD = (char)14
+ FLEA = (char)14
};
}
diff --git a/iotdb-client/client-py/iotdb/utils/IoTDBConstants.py b/iotdb-client/client-py/iotdb/utils/IoTDBConstants.py
index 3dfbe3c..85ceeed 100644
--- a/iotdb-client/client-py/iotdb/utils/IoTDBConstants.py
+++ b/iotdb-client/client-py/iotdb/utils/IoTDBConstants.py
@@ -54,7 +54,7 @@
CHIMP = 11
SPRINTZ = 12
RLBE = 13
- PERIOD = 14
+ FLEA = 14
@unique
diff --git a/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBDatabaseMetadata.java b/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBDatabaseMetadata.java
index 6f35f51..5aa715a 100644
--- a/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBDatabaseMetadata.java
+++ b/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBDatabaseMetadata.java
@@ -238,7 +238,7 @@
"ON",
"OFF",
"OF",
- "PERIOD",
+ "FLEA",
"PROCESSLIST",
"PREVIOUS",
"PREVIOUSUNTILLAST",
diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/SchemaUtils.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/SchemaUtils.java
index 714689a..26a2a03 100644
--- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/SchemaUtils.java
+++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/SchemaUtils.java
@@ -59,7 +59,7 @@
intSet.add(TSEncoding.CHIMP);
intSet.add(TSEncoding.SPRINTZ);
intSet.add(TSEncoding.RLBE);
- intSet.add(TSEncoding.PERIOD);
+ intSet.add(TSEncoding.FLEA);
schemaChecker.put(TSDataType.INT32, intSet);
schemaChecker.put(TSDataType.INT64, intSet);
diff --git a/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBDatabaseMetadata.java b/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBDatabaseMetadata.java
index 3df1318..c4044a3 100644
--- a/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBDatabaseMetadata.java
+++ b/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBDatabaseMetadata.java
@@ -66,8 +66,8 @@
private static final String METHOD_NOT_SUPPORTED_STRING = "Method not supported";
// when running the program in IDE, we can not get the version info using
// getImplementationVersion()
- private static final String DATABASE_VERSION =
- IoTDBDatabaseMetadata.class.getPackage().getImplementationVersion() != null
+ private static final String DATABASE_VERSION = IoTDBDatabaseMetadata.class.getPackage()
+ .getImplementationVersion() != null
? IoTDBDatabaseMetadata.class.getPackage().getImplementationVersion()
: "UNKNOWN";
private long sessionId;
@@ -84,382 +84,382 @@
static {
String[] allIotdbSQLKeywords = {
- "ALTER",
- "ADD",
- "ALIAS",
- "ALL",
- "AVG",
- "ALIGN",
- "ATTRIBUTES",
- "AS",
- "ASC",
- "BY",
- "BOOLEAN",
- "BITMAP",
- "CREATE",
- "CONFIGURATION",
- "COMPRESSOR",
- "CHILD",
- "COUNT",
- "COMPRESSION",
- "CLEAR",
- "CACHE",
- "CONTAIN",
- "CONCAT",
- "DELETE",
- "DEVICE",
- "DESCRIBE",
- "DATATYPE",
- "DOUBLE",
- "DIFF",
- "DROP",
- "DEVICES",
- "DISABLE",
- "DESC",
- "ENCODING",
- "FROM",
- "FILL",
- "FLOAT",
- "FLUSH",
- "FIRST_VALUE",
- "FULL",
- "FALSE",
- "FOR",
- "FUNCTION",
- "FUNCTIONS",
- "GRANT",
- "GROUP",
- "GORILLA",
- "GLOBAL",
- "GZIP",
- "INSERT",
- "INTO",
- "INT32",
- "INT64",
- "INDEX",
- "INFO",
- "KILL",
- "LIMIT",
- "LINEAR",
- "LABEL",
- "LINK",
- "LIST",
- "LOAD",
- "LEVEL",
- "LAST_VALUE",
- "LAST",
- "LZO",
- "LZ4",
- "LATEST",
- "LIKE",
- "METADATA",
- "MERGE",
- "MOVE",
- "MIN_TIME",
- "MAX_TIME",
- "MIN_VALUE",
- "MAX_VALUE",
- "NOW",
- "NODES",
- "ORDER",
- "OFFSET",
- "ON",
- "OFF",
- "OF",
- "PERIOD",
- "PROCESSLIST",
- "PREVIOUS",
- "PREVIOUSUNTILLAST",
- "PROPERTY",
- "PLAIN",
- "PLAIN_DICTIONARY",
- "PRIVILEGES",
- "PASSWORD",
- "PATHS",
- "PAA",
- "PLA",
- "PARTITION",
- "QUERY",
- "ROOT",
- "RLE",
- "REGULAR",
- "ROLE",
- "REVOKE",
- "REMOVE",
- "RENAME",
- "SELECT",
- "SHOW",
- "SET",
- "SLIMIT",
- "SOFFSET",
- "STORAGE",
- "SUM",
- "SNAPPY",
- "SNAPSHOT",
- "SCHEMA",
- "TO",
- "TIMESERIES",
- "TIMESTAMP",
- "TEXT",
- "TS_2DIFF",
- "TRACING",
- "TTL",
- "TASK",
- "TIME",
- "TAGS",
- "TRUE",
- "TEMPORARY",
- "TOP",
- "TOLERANCE",
- "UPDATE",
- "UNLINK",
- "UPSERT",
- "USING",
- "USER",
- "UNSET",
- "UNCOMPRESSED",
- "VALUES",
- "VERSION",
- "WHERE",
- "WITH",
- "WATERMARK_EMBEDDING"
+ "ALTER",
+ "ADD",
+ "ALIAS",
+ "ALL",
+ "AVG",
+ "ALIGN",
+ "ATTRIBUTES",
+ "AS",
+ "ASC",
+ "BY",
+ "BOOLEAN",
+ "BITMAP",
+ "CREATE",
+ "CONFIGURATION",
+ "COMPRESSOR",
+ "CHILD",
+ "COUNT",
+ "COMPRESSION",
+ "CLEAR",
+ "CACHE",
+ "CONTAIN",
+ "CONCAT",
+ "DELETE",
+ "DEVICE",
+ "DESCRIBE",
+ "DATATYPE",
+ "DOUBLE",
+ "DIFF",
+ "DROP",
+ "DEVICES",
+ "DISABLE",
+ "DESC",
+ "ENCODING",
+ "FROM",
+ "FILL",
+ "FLOAT",
+ "FLUSH",
+ "FIRST_VALUE",
+ "FULL",
+ "FALSE",
+ "FOR",
+ "FUNCTION",
+ "FUNCTIONS",
+ "GRANT",
+ "GROUP",
+ "GORILLA",
+ "GLOBAL",
+ "GZIP",
+ "INSERT",
+ "INTO",
+ "INT32",
+ "INT64",
+ "INDEX",
+ "INFO",
+ "KILL",
+ "LIMIT",
+ "LINEAR",
+ "LABEL",
+ "LINK",
+ "LIST",
+ "LOAD",
+ "LEVEL",
+ "LAST_VALUE",
+ "LAST",
+ "LZO",
+ "LZ4",
+ "LATEST",
+ "LIKE",
+ "METADATA",
+ "MERGE",
+ "MOVE",
+ "MIN_TIME",
+ "MAX_TIME",
+ "MIN_VALUE",
+ "MAX_VALUE",
+ "NOW",
+ "NODES",
+ "ORDER",
+ "OFFSET",
+ "ON",
+ "OFF",
+ "OF",
+ "FLEA",
+ "PROCESSLIST",
+ "PREVIOUS",
+ "PREVIOUSUNTILLAST",
+ "PROPERTY",
+ "PLAIN",
+ "PLAIN_DICTIONARY",
+ "PRIVILEGES",
+ "PASSWORD",
+ "PATHS",
+ "PAA",
+ "PLA",
+ "PARTITION",
+ "QUERY",
+ "ROOT",
+ "RLE",
+ "REGULAR",
+ "ROLE",
+ "REVOKE",
+ "REMOVE",
+ "RENAME",
+ "SELECT",
+ "SHOW",
+ "SET",
+ "SLIMIT",
+ "SOFFSET",
+ "STORAGE",
+ "SUM",
+ "SNAPPY",
+ "SNAPSHOT",
+ "SCHEMA",
+ "TO",
+ "TIMESERIES",
+ "TIMESTAMP",
+ "TEXT",
+ "TS_2DIFF",
+ "TRACING",
+ "TTL",
+ "TASK",
+ "TIME",
+ "TAGS",
+ "TRUE",
+ "TEMPORARY",
+ "TOP",
+ "TOLERANCE",
+ "UPDATE",
+ "UNLINK",
+ "UPSERT",
+ "USING",
+ "USER",
+ "UNSET",
+ "UNCOMPRESSED",
+ "VALUES",
+ "VERSION",
+ "WHERE",
+ "WITH",
+ "WATERMARK_EMBEDDING"
};
String[] sql92Keywords = {
- "ABSOLUTE",
- "EXEC",
- "OVERLAPS",
- "ACTION",
- "EXECUTE",
- "PAD",
- "ADA",
- "EXISTS",
- "PARTIAL",
- "ADD",
- "EXTERNAL",
- "PASCAL",
- "ALL",
- "EXTRACT",
- "POSITION",
- "ALLOCATE",
- "FALSE",
- "PRECISION",
- "ALTER",
- "FETCH",
- "PREPARE",
- "AND",
- "FIRST",
- "PRESERVE",
- "ANY",
- "FLOAT",
- "PRIMARY",
- "ARE",
- "FOR",
- "PRIOR",
- "AS",
- "FOREIGN",
- "PRIVILEGES",
- "ASC",
- "FORTRAN",
- "PROCEDURE",
- "ASSERTION",
- "FOUND",
- "PUBLIC",
- "AT",
- "FROM",
- "READ",
- "AUTHORIZATION",
- "FULL",
- "REAL",
- "AVG",
- "GET",
- "REFERENCES",
- "BEGIN",
- "GLOBAL",
- "RELATIVE",
- "BETWEEN",
- "GO",
- "RESTRICT",
- "BIT",
- "GOTO",
- "REVOKE",
- "BIT_LENGTH",
- "GRANT",
- "RIGHT",
- "BOTH",
- "GROUP",
- "ROLLBACK",
- "BY",
- "HAVING",
- "ROWS",
- "CASCADE",
- "HOUR",
- "SCHEMA",
- "CASCADED",
- "IDENTITY",
- "SCROLL",
- "CASE",
- "IMMEDIATE",
- "SECOND",
- "CAST",
- "IN",
- "SECTION",
- "CATALOG",
- "INCLUDE",
- "SELECT",
- "CHAR",
- "INDEX",
- "SESSION",
- "CHAR_LENGTH",
- "INDICATOR",
- "SESSION_USER",
- "CHARACTER",
- "INITIALLY",
- "SET",
- "CHARACTER_LENGTH",
- "INNER",
- "SIZE",
- "CHECK",
- "INPUT",
- "SMALLINT",
- "CLOSE",
- "INSENSITIVE",
- "SOME",
- "COALESCE",
- "INSERT",
- "SPACE",
- "COLLATE",
- "INT",
- "SQL",
- "COLLATION",
- "INTEGER",
- "SQLCA",
- "COLUMN",
- "INTERSECT",
- "SQLCODE",
- "COMMIT",
- "INTERVAL",
- "SQLERROR",
- "CONNECT",
- "INTO",
- "SQLSTATE",
- "CONNECTION",
- "IS",
- "SQLWARNING",
- "CONSTRAINT",
- "ISOLATION",
- "SUBSTRING",
- "CONSTRAINTS",
- "JOIN",
- "SUM",
- "CONTINUE",
- "KEY",
- "SYSTEM_USER",
- "CONVERT",
- "LANGUAGE",
- "TABLE",
- "CORRESPONDING",
- "LAST",
- "TEMPORARY",
- "COUNT",
- "LEADING",
- "THEN",
- "CREATE",
- "LEFT",
- "TIME",
- "CROSS",
- "LEVEL",
- "TIMESTAMP",
- "CURRENT",
- "LIKE",
- "TIMEZONE_HOUR",
- "CURRENT_DATE",
- "LOCAL",
- "TIMEZONE_MINUTE",
- "CURRENT_TIME",
- "LOWER",
- "TO",
- "CURRENT_TIMESTAMP",
- "MATCH",
- "TRAILING",
- "CURRENT_USER",
- "MAX",
- "TRANSACTION",
- "CURSOR",
- "MIN",
- "TRANSLATE",
- "DATE",
- "MINUTE",
- "TRANSLATION",
- "DAY",
- "MODULE",
- "TRIM",
- "DEALLOCATE",
- "MONTH",
- "TRUE",
- "DEC",
- "NAMES",
- "UNION",
- "DECIMAL",
- "NATIONAL",
- "UNIQUE",
- "DECLARE",
- "NATURAL",
- "UNKNOWN",
- "DEFAULT",
- "NCHAR",
- "UPDATE",
- "DEFERRABLE",
- "NEXT",
- "UPPER",
- "DEFERRED",
- "NO",
- "USAGE",
- "DELETE",
- "NONE",
- "USER",
- "DESC",
- "NOT",
- "USING",
- "DESCRIBE",
- "NULL",
- "VALUE",
- "DESCRIPTOR",
- "NULLIF",
- "VALUES",
- "DIAGNOSTICS",
- "NUMERIC",
- "VARCHAR",
- "DISCONNECT",
- "OCTET_LENGTH",
- "VARYING",
- "DISTINCT",
- "OF",
- "VIEW",
- "DOMAIN",
- "ON",
- "WHEN",
- "DOUBLE",
- "ONLY",
- "WHENEVER",
- "DROP",
- "OPEN",
- "WHERE",
- "ELSE",
- "OPTION",
- "WITH",
- "END",
- "OR",
- "WORK",
- "END-EXEC",
- "ORDER",
- "WRITE",
- "ESCAPE",
- "OUTER",
- "YEAR",
- "EXCEPT",
- "OUTPUT",
- "ZONE",
- "EXCEPTION"
+ "ABSOLUTE",
+ "EXEC",
+ "OVERLAPS",
+ "ACTION",
+ "EXECUTE",
+ "PAD",
+ "ADA",
+ "EXISTS",
+ "PARTIAL",
+ "ADD",
+ "EXTERNAL",
+ "PASCAL",
+ "ALL",
+ "EXTRACT",
+ "POSITION",
+ "ALLOCATE",
+ "FALSE",
+ "PRECISION",
+ "ALTER",
+ "FETCH",
+ "PREPARE",
+ "AND",
+ "FIRST",
+ "PRESERVE",
+ "ANY",
+ "FLOAT",
+ "PRIMARY",
+ "ARE",
+ "FOR",
+ "PRIOR",
+ "AS",
+ "FOREIGN",
+ "PRIVILEGES",
+ "ASC",
+ "FORTRAN",
+ "PROCEDURE",
+ "ASSERTION",
+ "FOUND",
+ "PUBLIC",
+ "AT",
+ "FROM",
+ "READ",
+ "AUTHORIZATION",
+ "FULL",
+ "REAL",
+ "AVG",
+ "GET",
+ "REFERENCES",
+ "BEGIN",
+ "GLOBAL",
+ "RELATIVE",
+ "BETWEEN",
+ "GO",
+ "RESTRICT",
+ "BIT",
+ "GOTO",
+ "REVOKE",
+ "BIT_LENGTH",
+ "GRANT",
+ "RIGHT",
+ "BOTH",
+ "GROUP",
+ "ROLLBACK",
+ "BY",
+ "HAVING",
+ "ROWS",
+ "CASCADE",
+ "HOUR",
+ "SCHEMA",
+ "CASCADED",
+ "IDENTITY",
+ "SCROLL",
+ "CASE",
+ "IMMEDIATE",
+ "SECOND",
+ "CAST",
+ "IN",
+ "SECTION",
+ "CATALOG",
+ "INCLUDE",
+ "SELECT",
+ "CHAR",
+ "INDEX",
+ "SESSION",
+ "CHAR_LENGTH",
+ "INDICATOR",
+ "SESSION_USER",
+ "CHARACTER",
+ "INITIALLY",
+ "SET",
+ "CHARACTER_LENGTH",
+ "INNER",
+ "SIZE",
+ "CHECK",
+ "INPUT",
+ "SMALLINT",
+ "CLOSE",
+ "INSENSITIVE",
+ "SOME",
+ "COALESCE",
+ "INSERT",
+ "SPACE",
+ "COLLATE",
+ "INT",
+ "SQL",
+ "COLLATION",
+ "INTEGER",
+ "SQLCA",
+ "COLUMN",
+ "INTERSECT",
+ "SQLCODE",
+ "COMMIT",
+ "INTERVAL",
+ "SQLERROR",
+ "CONNECT",
+ "INTO",
+ "SQLSTATE",
+ "CONNECTION",
+ "IS",
+ "SQLWARNING",
+ "CONSTRAINT",
+ "ISOLATION",
+ "SUBSTRING",
+ "CONSTRAINTS",
+ "JOIN",
+ "SUM",
+ "CONTINUE",
+ "KEY",
+ "SYSTEM_USER",
+ "CONVERT",
+ "LANGUAGE",
+ "TABLE",
+ "CORRESPONDING",
+ "LAST",
+ "TEMPORARY",
+ "COUNT",
+ "LEADING",
+ "THEN",
+ "CREATE",
+ "LEFT",
+ "TIME",
+ "CROSS",
+ "LEVEL",
+ "TIMESTAMP",
+ "CURRENT",
+ "LIKE",
+ "TIMEZONE_HOUR",
+ "CURRENT_DATE",
+ "LOCAL",
+ "TIMEZONE_MINUTE",
+ "CURRENT_TIME",
+ "LOWER",
+ "TO",
+ "CURRENT_TIMESTAMP",
+ "MATCH",
+ "TRAILING",
+ "CURRENT_USER",
+ "MAX",
+ "TRANSACTION",
+ "CURSOR",
+ "MIN",
+ "TRANSLATE",
+ "DATE",
+ "MINUTE",
+ "TRANSLATION",
+ "DAY",
+ "MODULE",
+ "TRIM",
+ "DEALLOCATE",
+ "MONTH",
+ "TRUE",
+ "DEC",
+ "NAMES",
+ "UNION",
+ "DECIMAL",
+ "NATIONAL",
+ "UNIQUE",
+ "DECLARE",
+ "NATURAL",
+ "UNKNOWN",
+ "DEFAULT",
+ "NCHAR",
+ "UPDATE",
+ "DEFERRABLE",
+ "NEXT",
+ "UPPER",
+ "DEFERRED",
+ "NO",
+ "USAGE",
+ "DELETE",
+ "NONE",
+ "USER",
+ "DESC",
+ "NOT",
+ "USING",
+ "DESCRIBE",
+ "NULL",
+ "VALUE",
+ "DESCRIPTOR",
+ "NULLIF",
+ "VALUES",
+ "DIAGNOSTICS",
+ "NUMERIC",
+ "VARCHAR",
+ "DISCONNECT",
+ "OCTET_LENGTH",
+ "VARYING",
+ "DISTINCT",
+ "OF",
+ "VIEW",
+ "DOMAIN",
+ "ON",
+ "WHEN",
+ "DOUBLE",
+ "ONLY",
+ "WHENEVER",
+ "DROP",
+ "OPEN",
+ "WHERE",
+ "ELSE",
+ "OPTION",
+ "WITH",
+ "END",
+ "OR",
+ "WORK",
+ "END-EXEC",
+ "ORDER",
+ "WRITE",
+ "ESCAPE",
+ "OUTER",
+ "YEAR",
+ "EXCEPT",
+ "OUTPUT",
+ "ZONE",
+ "EXCEPTION"
};
TreeMap myKeywordMap = new TreeMap();
for (int i = 0; i < allIotdbSQLKeywords.length; i++) {
@@ -487,12 +487,11 @@
private WatermarkEncoder getWatermarkEncoder() {
try {
- groupedLSBWatermarkEncoder =
- new GroupedLSBWatermarkEncoder(
- client.getProperties().getWatermarkSecretKey(),
- client.getProperties().getWatermarkBitString(),
- client.getProperties().getWatermarkParamMarkRate(),
- client.getProperties().getWatermarkParamMaxRightBit());
+ groupedLSBWatermarkEncoder = new GroupedLSBWatermarkEncoder(
+ client.getProperties().getWatermarkSecretKey(),
+ client.getProperties().getWatermarkBitString(),
+ client.getProperties().getWatermarkParamMarkRate(),
+ client.getProperties().getWatermarkParamMaxRightBit());
} catch (TException e) {
e.printStackTrace();
}
@@ -878,8 +877,7 @@
for (Map<String, Object> map : listPaths) {
TSDataType columnType = (TSDataType) map.get("type");
Object val = map.get("val");
- org.apache.iotdb.tsfile.read.common.Field field =
- new org.apache.iotdb.tsfile.read.common.Field(columnType);
+ org.apache.iotdb.tsfile.read.common.Field field = new org.apache.iotdb.tsfile.read.common.Field(columnType);
switch (columnType) {
case TEXT:
field.setBinaryV(new Binary(val.toString()));
@@ -922,8 +920,8 @@
fields[1] = new Field("", "MAX_LEN", "INT32");
fields[2] = new Field("", "DEFAULT_VALUE", "INT32");
fields[3] = new Field("", "DESCRIPTION", "TEXT");
- List<TSDataType> tsDataTypeList =
- Arrays.asList(TSDataType.TEXT, TSDataType.INT32, TSDataType.INT32, TSDataType.TEXT);
+ List<TSDataType> tsDataTypeList = Arrays.asList(TSDataType.TEXT, TSDataType.INT32, TSDataType.INT32,
+ TSDataType.TEXT);
List<Object> values = Arrays.asList("fetch_size", 10, 10, "");
List<String> columnNameList = new ArrayList<>();
@@ -981,7 +979,7 @@
sql = sql + " " + schemaPattern;
}
if (((catalog != null && catalog.length() > 0)
- || schemaPattern != null && schemaPattern.length() > 0)
+ || schemaPattern != null && schemaPattern.length() > 0)
&& tableNamePattern != null
&& tableNamePattern.length() > 0) {
if (tableNamePattern.contains("%")) {
@@ -991,7 +989,7 @@
}
if (((catalog != null && catalog.length() > 0)
- || schemaPattern != null && schemaPattern.length() > 0)
+ || schemaPattern != null && schemaPattern.length() > 0)
&& tableNamePattern != null
&& tableNamePattern.length() > 0
&& columnNamePattern != null
@@ -1008,16 +1006,15 @@
fields[5] = new Field("", "GRANTEE", "TEXT");
fields[6] = new Field("", "PRIVILEGE", "TEXT");
fields[7] = new Field("", "IS_GRANTABLE", "TEXT");
- List<TSDataType> tsDataTypeList =
- Arrays.asList(
- TSDataType.TEXT,
- TSDataType.TEXT,
- TSDataType.TEXT,
- TSDataType.TEXT,
- TSDataType.TEXT,
- TSDataType.TEXT,
- TSDataType.TEXT,
- TSDataType.TEXT);
+ List<TSDataType> tsDataTypeList = Arrays.asList(
+ TSDataType.TEXT,
+ TSDataType.TEXT,
+ TSDataType.TEXT,
+ TSDataType.TEXT,
+ TSDataType.TEXT,
+ TSDataType.TEXT,
+ TSDataType.TEXT,
+ TSDataType.TEXT);
List<String> columnNameList = new ArrayList<>();
List<String> columnTypeList = new ArrayList<>();
@@ -1272,25 +1269,24 @@
fields[14] = new Field("", "ORDINAL_POSITION", "INT32");
fields[15] = new Field("", "IS_NULLABLE", "TEXT");
fields[16] = new Field("", "SPECIFIC_NAME", "TEXT");
- List<TSDataType> tsDataTypeList =
- Arrays.asList(
- TSDataType.TEXT,
- TSDataType.TEXT,
- TSDataType.TEXT,
- TSDataType.TEXT,
- TSDataType.INT32,
- TSDataType.INT32,
- TSDataType.TEXT,
- TSDataType.INT32,
- TSDataType.INT32,
- TSDataType.INT32,
- TSDataType.INT32,
- TSDataType.INT32,
- TSDataType.TEXT,
- TSDataType.INT32,
- TSDataType.INT32,
- TSDataType.TEXT,
- TSDataType.TEXT);
+ List<TSDataType> tsDataTypeList = Arrays.asList(
+ TSDataType.TEXT,
+ TSDataType.TEXT,
+ TSDataType.TEXT,
+ TSDataType.TEXT,
+ TSDataType.INT32,
+ TSDataType.INT32,
+ TSDataType.TEXT,
+ TSDataType.INT32,
+ TSDataType.INT32,
+ TSDataType.INT32,
+ TSDataType.INT32,
+ TSDataType.INT32,
+ TSDataType.TEXT,
+ TSDataType.INT32,
+ TSDataType.INT32,
+ TSDataType.TEXT,
+ TSDataType.TEXT);
List<String> columnNameList = new ArrayList<>();
List<String> columnTypeList = new ArrayList<>();
@@ -1352,14 +1348,13 @@
fields[3] = new Field("", "REMARKS", "TEXT");
fields[4] = new Field("", "FUNCTION_TYPE", "INT32");
fields[5] = new Field("", "SPECIFIC_NAME", "TEXT");
- List<TSDataType> tsDataTypeList =
- Arrays.asList(
- TSDataType.TEXT,
- TSDataType.TEXT,
- TSDataType.TEXT,
- TSDataType.TEXT,
- TSDataType.INT32,
- TSDataType.TEXT);
+ List<TSDataType> tsDataTypeList = Arrays.asList(
+ TSDataType.TEXT,
+ TSDataType.TEXT,
+ TSDataType.TEXT,
+ TSDataType.TEXT,
+ TSDataType.INT32,
+ TSDataType.TEXT);
List<String> columnNameList = new ArrayList<>();
List<String> columnTypeList = new ArrayList<>();
@@ -1673,14 +1668,13 @@
List<String> columnNameList = new ArrayList<>();
List<String> columnTypeList = new ArrayList<>();
Map<String, Integer> columnNameIndex = new HashMap<>();
- List<TSDataType> tsDataTypeList =
- Arrays.asList(
- TSDataType.TEXT,
- TSDataType.TEXT,
- TSDataType.TEXT,
- TSDataType.TEXT,
- TSDataType.INT32,
- TSDataType.TEXT);
+ List<TSDataType> tsDataTypeList = Arrays.asList(
+ TSDataType.TEXT,
+ TSDataType.TEXT,
+ TSDataType.TEXT,
+ TSDataType.TEXT,
+ TSDataType.INT32,
+ TSDataType.TEXT);
Field[] fields = new Field[6];
fields[0] = new Field("", "TABLE_CAT", "TEXT");
fields[1] = new Field("", "TABLE_SCHEM", "TEXT");
@@ -1841,24 +1835,22 @@
fields[9] = new Field("", "REMARKS", "TEXT");
fields[10] = new Field("", "CHAR_OCTET_LENGTH", "INT32");
fields[11] = new Field("", "IS_NULLABLE", "TEXT");
- List<TSDataType> tsDataTypeList =
- Arrays.asList(
- TSDataType.TEXT,
- TSDataType.TEXT,
- TSDataType.TEXT,
- TSDataType.TEXT,
- TSDataType.INT32,
- TSDataType.INT32,
- TSDataType.INT32,
- TSDataType.INT32,
- TSDataType.TEXT,
- TSDataType.TEXT,
- TSDataType.INT32,
- TSDataType.TEXT);
+ List<TSDataType> tsDataTypeList = Arrays.asList(
+ TSDataType.TEXT,
+ TSDataType.TEXT,
+ TSDataType.TEXT,
+ TSDataType.TEXT,
+ TSDataType.INT32,
+ TSDataType.INT32,
+ TSDataType.INT32,
+ TSDataType.INT32,
+ TSDataType.TEXT,
+ TSDataType.TEXT,
+ TSDataType.INT32,
+ TSDataType.TEXT);
- List<Object> value =
- Arrays.asList(
- catalog, catalog, tableNamePattern, "times", Types.BIGINT, 1, 0, 2, "", "", 13, "NO");
+ List<Object> value = Arrays.asList(
+ catalog, catalog, tableNamePattern, "times", Types.BIGINT, 1, 0, 2, "", "", 13, "NO");
List<String> columnNameList = new ArrayList<>();
List<String> columnTypeList = new ArrayList<>();
Map<String, Integer> columnNameIndex = new HashMap<>();
@@ -2106,7 +2098,7 @@
sql = sql + " " + schemaPattern;
}
if (((catalog != null && catalog.length() > 0)
- || schemaPattern != null && schemaPattern.length() > 0)
+ || schemaPattern != null && schemaPattern.length() > 0)
&& tableNamePattern != null
&& tableNamePattern.length() > 0) {
if (tableNamePattern.contains("%")) {
@@ -2125,16 +2117,15 @@
fields[5] = new Field("", "GRANTEE", "TEXT");
fields[6] = new Field("", "PRIVILEGE", "TEXT");
fields[7] = new Field("", "IS_GRANTABLE", "TEXT");
- List<TSDataType> tsDataTypeList =
- Arrays.asList(
- TSDataType.TEXT,
- TSDataType.TEXT,
- TSDataType.TEXT,
- TSDataType.TEXT,
- TSDataType.TEXT,
- TSDataType.TEXT,
- TSDataType.TEXT,
- TSDataType.TEXT);
+ List<TSDataType> tsDataTypeList = Arrays.asList(
+ TSDataType.TEXT,
+ TSDataType.TEXT,
+ TSDataType.TEXT,
+ TSDataType.TEXT,
+ TSDataType.TEXT,
+ TSDataType.TEXT,
+ TSDataType.TEXT,
+ TSDataType.TEXT);
List<String> columnNameList = new ArrayList<>();
List<String> columnTypeList = new ArrayList<>();
@@ -2247,7 +2238,7 @@
sql = sql + " " + schemaPattern;
}
if (((catalog != null && catalog.length() > 0)
- || schemaPattern != null && schemaPattern.length() > 0)
+ || schemaPattern != null && schemaPattern.length() > 0)
&& tableNamePattern != null
&& tableNamePattern.length() > 0) {
if (tableNamePattern.contains("%")) {
@@ -2257,7 +2248,7 @@
}
if (((catalog != null && catalog.length() > 0)
- || schemaPattern != null && schemaPattern.length() > 0)
+ || schemaPattern != null && schemaPattern.length() > 0)
&& tableNamePattern != null
&& tableNamePattern.length() > 0
&& columnNamePattern != null
@@ -2291,32 +2282,31 @@
fields[22] = new Field("", "IS_AUTOINCREMENT", "TEXT");
fields[23] = new Field("", "IS_GENERATEDCOLUMN", "TEXT");
- List<TSDataType> tsDataTypeList =
- Arrays.asList(
- TSDataType.TEXT,
- TSDataType.TEXT,
- TSDataType.TEXT,
- TSDataType.TEXT,
- TSDataType.INT32,
- TSDataType.TEXT,
- TSDataType.INT32,
- TSDataType.INT32,
- TSDataType.INT32,
- TSDataType.INT32,
- TSDataType.INT32,
- TSDataType.TEXT,
- TSDataType.TEXT,
- TSDataType.INT32,
- TSDataType.INT32,
- TSDataType.INT32,
- TSDataType.INT32,
- TSDataType.TEXT,
- TSDataType.TEXT,
- TSDataType.TEXT,
- TSDataType.TEXT,
- TSDataType.INT32,
- TSDataType.TEXT,
- TSDataType.TEXT);
+ List<TSDataType> tsDataTypeList = Arrays.asList(
+ TSDataType.TEXT,
+ TSDataType.TEXT,
+ TSDataType.TEXT,
+ TSDataType.TEXT,
+ TSDataType.INT32,
+ TSDataType.TEXT,
+ TSDataType.INT32,
+ TSDataType.INT32,
+ TSDataType.INT32,
+ TSDataType.INT32,
+ TSDataType.INT32,
+ TSDataType.TEXT,
+ TSDataType.TEXT,
+ TSDataType.INT32,
+ TSDataType.INT32,
+ TSDataType.INT32,
+ TSDataType.INT32,
+ TSDataType.TEXT,
+ TSDataType.TEXT,
+ TSDataType.TEXT,
+ TSDataType.TEXT,
+ TSDataType.INT32,
+ TSDataType.TEXT,
+ TSDataType.TEXT);
List<String> columnNameList = new ArrayList<>();
List<String> columnTypeList = new ArrayList<>();
Map<String, Integer> columnNameIndex = new HashMap<>();
@@ -2495,7 +2485,7 @@
sql = sql + " " + schemaPattern;
}
if (((catalog != null && catalog.length() > 0)
- || schemaPattern != null && schemaPattern.length() > 0)
+ || schemaPattern != null && schemaPattern.length() > 0)
&& tableNamePattern != null
&& tableNamePattern.length() > 0) {
if (tableNamePattern.contains("%")) {
@@ -2516,18 +2506,17 @@
fields[8] = new Field("", "SELF_REFERENCING_COL_NAME", "TEXT");
fields[9] = new Field("", "REF_GENERATION", "TEXT");
- List<TSDataType> tsDataTypeList =
- Arrays.asList(
- TSDataType.TEXT,
- TSDataType.TEXT,
- TSDataType.TEXT,
- TSDataType.TEXT,
- TSDataType.TEXT,
- TSDataType.TEXT,
- TSDataType.TEXT,
- TSDataType.TEXT,
- TSDataType.TEXT,
- TSDataType.TEXT);
+ List<TSDataType> tsDataTypeList = Arrays.asList(
+ TSDataType.TEXT,
+ TSDataType.TEXT,
+ TSDataType.TEXT,
+ TSDataType.TEXT,
+ TSDataType.TEXT,
+ TSDataType.TEXT,
+ TSDataType.TEXT,
+ TSDataType.TEXT,
+ TSDataType.TEXT,
+ TSDataType.TEXT);
List<String> columnNameList = new ArrayList<>();
List<String> columnTypeList = new ArrayList<>();
@@ -2604,149 +2593,141 @@
fields[15] = new Field("", "SQL_DATA_TYPE", "INT32");
fields[16] = new Field("", "SQL_DATETIME_SUB", "INT32");
fields[17] = new Field("", "NUM_PREC_RADIX", "INT32");
- List<TSDataType> tsDataTypeList =
- Arrays.asList(
- TSDataType.TEXT,
- TSDataType.INT32,
- TSDataType.INT32,
- TSDataType.TEXT,
- TSDataType.TEXT,
- TSDataType.TEXT,
- TSDataType.INT32,
- TSDataType.BOOLEAN,
- TSDataType.TEXT,
- TSDataType.BOOLEAN,
- TSDataType.BOOLEAN,
- TSDataType.BOOLEAN,
- TSDataType.TEXT,
- TSDataType.INT32,
- TSDataType.INT32,
- TSDataType.INT32,
- TSDataType.INT32,
- TSDataType.INT32);
- List<Object> listValSub_1 =
- Arrays.asList(
- "INT32",
- Types.INTEGER,
- 10,
- "",
- "",
- "",
- 1,
- true,
- "",
- false,
- true,
- false,
- "",
- 0,
- 10,
- 0,
- 0,
- 10);
- List<Object> listValSub_2 =
- Arrays.asList(
- "INT64",
- Types.BIGINT,
- 19,
- "",
- "",
- "",
- 1,
- true,
- "",
- false,
- true,
- false,
- "",
- 0,
- 10,
- 0,
- 0,
- 10);
- List<Object> listValSub_3 =
- Arrays.asList(
- "BOOLEAN",
- Types.BOOLEAN,
- 1,
- "",
- "",
- "",
- 1,
- true,
- "",
- false,
- true,
- false,
- "",
- 0,
- 10,
- 0,
- 0,
- 10);
- List<Object> listValSub_4 =
- Arrays.asList(
- "FLOAT",
- Types.FLOAT,
- 38,
- "",
- "",
- "",
- 1,
- true,
- "",
- false,
- true,
- false,
- "",
- 0,
- 10,
- 0,
- 0,
- 10);
- List<Object> listValSub_5 =
- Arrays.asList(
- "DOUBLE",
- Types.DOUBLE,
- 308,
- "",
- "",
- "",
- 1,
- true,
- "",
- false,
- true,
- false,
- "",
- 0,
- 10,
- 0,
- 0,
- 10);
- List<Object> listValSub_6 =
- Arrays.asList(
- "TEXT",
- Types.LONGVARCHAR,
- 64,
- "",
- "",
- "",
- 1,
- true,
- "",
- false,
- true,
- false,
- "",
- 0,
- 10,
- 0,
- 0,
- 10);
- List<List<Object>> valuesList =
- Arrays.asList(
- listValSub_1, listValSub_2, listValSub_3, listValSub_4, listValSub_5, listValSub_6);
+ List<TSDataType> tsDataTypeList = Arrays.asList(
+ TSDataType.TEXT,
+ TSDataType.INT32,
+ TSDataType.INT32,
+ TSDataType.TEXT,
+ TSDataType.TEXT,
+ TSDataType.TEXT,
+ TSDataType.INT32,
+ TSDataType.BOOLEAN,
+ TSDataType.TEXT,
+ TSDataType.BOOLEAN,
+ TSDataType.BOOLEAN,
+ TSDataType.BOOLEAN,
+ TSDataType.TEXT,
+ TSDataType.INT32,
+ TSDataType.INT32,
+ TSDataType.INT32,
+ TSDataType.INT32,
+ TSDataType.INT32);
+ List<Object> listValSub_1 = Arrays.asList(
+ "INT32",
+ Types.INTEGER,
+ 10,
+ "",
+ "",
+ "",
+ 1,
+ true,
+ "",
+ false,
+ true,
+ false,
+ "",
+ 0,
+ 10,
+ 0,
+ 0,
+ 10);
+ List<Object> listValSub_2 = Arrays.asList(
+ "INT64",
+ Types.BIGINT,
+ 19,
+ "",
+ "",
+ "",
+ 1,
+ true,
+ "",
+ false,
+ true,
+ false,
+ "",
+ 0,
+ 10,
+ 0,
+ 0,
+ 10);
+ List<Object> listValSub_3 = Arrays.asList(
+ "BOOLEAN",
+ Types.BOOLEAN,
+ 1,
+ "",
+ "",
+ "",
+ 1,
+ true,
+ "",
+ false,
+ true,
+ false,
+ "",
+ 0,
+ 10,
+ 0,
+ 0,
+ 10);
+ List<Object> listValSub_4 = Arrays.asList(
+ "FLOAT",
+ Types.FLOAT,
+ 38,
+ "",
+ "",
+ "",
+ 1,
+ true,
+ "",
+ false,
+ true,
+ false,
+ "",
+ 0,
+ 10,
+ 0,
+ 0,
+ 10);
+ List<Object> listValSub_5 = Arrays.asList(
+ "DOUBLE",
+ Types.DOUBLE,
+ 308,
+ "",
+ "",
+ "",
+ 1,
+ true,
+ "",
+ false,
+ true,
+ false,
+ "",
+ 0,
+ 10,
+ 0,
+ 0,
+ 10);
+ List<Object> listValSub_6 = Arrays.asList(
+ "TEXT",
+ Types.LONGVARCHAR,
+ 64,
+ "",
+ "",
+ "",
+ 1,
+ true,
+ "",
+ false,
+ true,
+ false,
+ "",
+ 0,
+ 10,
+ 0,
+ 0,
+ 10);
+ List<List<Object>> valuesList = Arrays.asList(
+ listValSub_1, listValSub_2, listValSub_3, listValSub_4, listValSub_5, listValSub_6);
List<String> columnNameList = new ArrayList<>();
List<String> columnTypeList = new ArrayList<>();
Map<String, Integer> columnNameIndex = new HashMap<>();
diff --git a/server/src/main/java/org/apache/iotdb/db/utils/SchemaUtils.java b/server/src/main/java/org/apache/iotdb/db/utils/SchemaUtils.java
index 7b303e3..a9c25f5 100644
--- a/server/src/main/java/org/apache/iotdb/db/utils/SchemaUtils.java
+++ b/server/src/main/java/org/apache/iotdb/db/utils/SchemaUtils.java
@@ -50,10 +50,10 @@
public class SchemaUtils {
- private SchemaUtils() {}
+ private SchemaUtils() {
+ }
- private static final Map<TSDataType, Set<TSEncoding>> schemaChecker =
- new EnumMap<>(TSDataType.class);
+ private static final Map<TSDataType, Set<TSEncoding>> schemaChecker = new EnumMap<>(TSDataType.class);
static {
Set<TSEncoding> booleanSet = new HashSet<>();
@@ -68,7 +68,7 @@
intSet.add(TSEncoding.GORILLA);
intSet.add(TSEncoding.ZIGZAG);
intSet.add(TSEncoding.FREQ);
- intSet.add(TSEncoding.PERIOD);
+ intSet.add(TSEncoding.FLEA);
schemaChecker.put(TSDataType.INT32, intSet);
schemaChecker.put(TSDataType.INT64, intSet);
@@ -118,8 +118,10 @@
}
/**
- * If the datatype of 'aggregation' depends on 'measurementDataType' (min_value, max_value),
- * return 'measurementDataType' directly, or return a list whose elements are all the datatype of
+ * If the datatype of 'aggregation' depends on 'measurementDataType' (min_value,
+ * max_value),
+ * return 'measurementDataType' directly, or return a list whose elements are
+ * all the datatype of
* 'aggregation' and its length is the same as 'measurementDataType'.
*
* @param measurementDataType
@@ -186,7 +188,8 @@
}
/**
- * judge whether the order of aggregation calculation is consistent with the order of traversing
+ * judge whether the order of aggregation calculation is consistent with the
+ * order of traversing
* data
*/
public static boolean isConsistentWithScanOrder(
@@ -213,7 +216,8 @@
}
/**
- * If e or one of its recursive causes is a PathNotExistException or StorageGroupNotSetException,
+ * If e or one of its recursive causes is a PathNotExistException or
+ * StorageGroupNotSetException,
* return such an exception or null if it cannot be found.
*
* @param currEx
diff --git a/tsfile/src/main/java/org/apache/iotdb/tsfile/encoding/decoder/Decoder.java b/tsfile/src/main/java/org/apache/iotdb/tsfile/encoding/decoder/Decoder.java
index a459f98..69d4f12 100644
--- a/tsfile/src/main/java/org/apache/iotdb/tsfile/encoding/decoder/Decoder.java
+++ b/tsfile/src/main/java/org/apache/iotdb/tsfile/encoding/decoder/Decoder.java
@@ -123,11 +123,11 @@
}
case FREQ:
return new FreqDecoder();
- case PERIOD:
+ case FLEA:
switch (dataType) {
case INT32:
// Spade TODO: replace plain with period parameter
- return new PeriodDecoder();
+ return new FLEADecoder();
default:
throw new TsFileDecodingException(String.format(ERROR_MSG, encoding, dataType));
}
diff --git a/tsfile/src/main/java/org/apache/iotdb/tsfile/encoding/decoder/FLEADecoder.java b/tsfile/src/main/java/org/apache/iotdb/tsfile/encoding/decoder/FLEADecoder.java
new file mode 100644
index 0000000..d98132b
--- /dev/null
+++ b/tsfile/src/main/java/org/apache/iotdb/tsfile/encoding/decoder/FLEADecoder.java
@@ -0,0 +1,434 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.tsfile.encoding.decoder;
+
+import org.apache.iotdb.tsfile.exception.encoding.TsFileDecodingException;
+import org.apache.iotdb.tsfile.file.metadata.enums.TSEncoding;
+import org.apache.iotdb.tsfile.utils.Binary;
+
+import org.apache.commons.math3.complex.Complex;
+import org.apache.commons.math3.transform.DftNormalization;
+import org.apache.commons.math3.transform.FastFourierTransformer;
+import org.apache.commons.math3.transform.TransformType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.nio.ByteBuffer;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Queue;
+
+public class FLEADecoder extends Decoder {
+
+ private static final Logger logger = LoggerFactory.getLogger(FLEADecoder.class);
+ private Queue<Integer> decodedValues;
+
+ public FLEADecoder() {
+ super(TSEncoding.FLEA);
+ this.decodedValues = new ArrayDeque<>();
+ }
+
+ @Override
+ public int readInt(ByteBuffer buffer) {
+ if (!hasNext(buffer)) {
+ throw new TsFileDecodingException("No more values to read.");
+ }
+ return decodedValues.poll();
+ }
+
+ @Override
+ public boolean hasNext(ByteBuffer buffer) {
+ if (!decodedValues.isEmpty()) {
+ return true;
+ }
+ if (buffer.remaining() > 0) {
+ decodeNextBlock(buffer);
+ return !decodedValues.isEmpty();
+ }
+ return false;
+ }
+
+ private void decodeNextBlock(ByteBuffer buffer) {
+ if (buffer.remaining() < 4) {
+ return;
+ }
+ int blockLength = buffer.getInt();
+
+ if (buffer.remaining() < blockLength) {
+ throw new TsFileDecodingException(
+ "Error when decoding FLEA block: expected "
+ + blockLength
+ + " bytes, but only "
+ + buffer.remaining()
+ + " are available.");
+ }
+
+ byte[] blockBytes = new byte[blockLength];
+ buffer.get(blockBytes);
+
+ try {
+ int[] blockOfInts = decodeBlock(blockBytes);
+ for (int val : blockOfInts) {
+ decodedValues.add(val);
+ }
+ } catch (IOException e) {
+ throw new TsFileDecodingException("Error when decoding FLEA block.", e);
+ }
+ }
+
+ private int[] decodeBlock(byte[] blockBytes) throws IOException {
+ ByteArrayInputStream bais = new ByteArrayInputStream(blockBytes);
+
+ OptimalParams params = decodeMetadata(bais);
+ int n = params.n;
+
+ Complex[] F_hat_complex_dequant = decodeFrequencyComponent(params, bais);
+
+ int[] R_star = decodeResidualComponent(params, bais);
+
+ Complex[] F_hat_full = new Complex[n];
+ for (int j = 0; j < F_hat_complex_dequant.length; j++) {
+ F_hat_full[j] = F_hat_complex_dequant[j];
+ }
+ for (int j = 1; j < F_hat_complex_dequant.length; j++) {
+ if (n - j < n) {
+ F_hat_full[n - j] = F_hat_complex_dequant[j].conjugate();
+ }
+ }
+
+ FastFourierTransformer fft = new FastFourierTransformer(DftNormalization.STANDARD);
+ Complex[] reconstructedTimeComplex = fft.transform(F_hat_full, TransformType.INVERSE);
+
+ int[] finalValues = new int[n];
+ for (int k = 0; k < n; k++) {
+ finalValues[k] = (int) Math.round(reconstructedTimeComplex[k].getReal() + R_star[k]);
+ }
+
+ return finalValues;
+ }
+
+ private static class OptimalParams {
+ int n;
+ int betaStar;
+ int pReStar;
+ int pImStar;
+ int dResidualStar;
+ }
+
+ private OptimalParams decodeMetadata(ByteArrayInputStream bais) throws IOException {
+
+ final int METADATA_SIZE_BYTES = 20;
+ byte[] metaBytes = new byte[METADATA_SIZE_BYTES];
+
+ int bytesRead = bais.read(metaBytes);
+ if (bytesRead != METADATA_SIZE_BYTES) {
+ throw new IOException(
+ "Failed to read complete metadata block. Expected "
+ + METADATA_SIZE_BYTES
+ + " bytes, but got "
+ + bytesRead);
+ }
+
+ ByteBuffer metaBuffer = ByteBuffer.wrap(metaBytes);
+
+ OptimalParams params = new OptimalParams();
+ params.n = metaBuffer.getInt();
+ params.betaStar = metaBuffer.getInt();
+ params.pReStar = metaBuffer.getInt();
+ params.pImStar = metaBuffer.getInt();
+ params.dResidualStar = metaBuffer.getInt();
+
+ logger.debug(
+ "Decoded metadata: n={}, beta={}, p_re={}, p_im={}, d_res={}",
+ params.n,
+ params.betaStar,
+ params.pReStar,
+ params.pImStar,
+ params.dResidualStar);
+
+ if (params.n <= 0
+ || params.betaStar < 0
+ || params.pReStar < 0
+ || params.pImStar < 0
+ || params.dResidualStar < 0) {
+ throw new TsFileDecodingException("Invalid metadata decoded: " + params);
+ }
+
+ return params;
+ }
+
+ private Complex[] decodeFrequencyComponent(OptimalParams params, ByteArrayInputStream bais)
+ throws IOException {
+ BitInputStream bitIn = new BitInputStream(bais);
+
+ int n_half = params.n / 2 + 1;
+
+ int[] F_re_desc = decodeGVLE(params.pReStar, bitIn);
+ int[] F_re_sparse = decodeDBP(n_half - params.pReStar, bitIn);
+
+ int[] F_im_desc = decodeGVLE(params.pImStar, bitIn);
+ int[] F_im_sparse = decodeDBP(n_half - params.pImStar, bitIn);
+
+ bitIn.close();
+
+ int[] F_hat_re = new int[n_half];
+ System.arraycopy(F_re_desc, 0, F_hat_re, 0, F_re_desc.length);
+ if (F_re_sparse.length > 0)
+ System.arraycopy(F_re_sparse, 0, F_hat_re, F_re_desc.length, F_re_sparse.length);
+ int[] F_hat_im = new int[n_half];
+ System.arraycopy(F_im_desc, 0, F_hat_im, 0, F_im_desc.length);
+ if (F_im_sparse.length > 0)
+ System.arraycopy(F_im_sparse, 0, F_hat_im, F_im_desc.length, F_im_sparse.length);
+
+ double quantizationFactor = Math.pow(2, params.betaStar);
+ Complex[] dequantizedFreq = new Complex[n_half];
+ for (int j = 0; j < n_half; j++) {
+ dequantizedFreq[j] =
+ new Complex(
+ (double) F_hat_re[j] * quantizationFactor, (double) F_hat_im[j] * quantizationFactor);
+ }
+ return dequantizedFreq;
+ }
+
+ private int[] decodeGVLE(int totalValuesToRead, BitInputStream bitIn) throws IOException {
+ if (totalValuesToRead == 0) {
+ return new int[0];
+ }
+
+ List<Integer> decodedList = new ArrayList<>(totalValuesToRead);
+ int valuesRead = 0;
+
+ while (valuesRead < totalValuesToRead) {
+ int sharedWidth = bitIn.read(5);
+ int groupLength = bitIn.read(11);
+
+ if (valuesRead + groupLength > totalValuesToRead) {
+ throw new TsFileDecodingException(
+ "GVLE decoding error: group length "
+ + groupLength
+ + " exceeds remaining values to read "
+ + (totalValuesToRead - valuesRead));
+ }
+
+ for (int i = 0; i < groupLength; i++) {
+ int sign = bitIn.read(1);
+
+ int magnitude = 0;
+ if (sharedWidth > 0) {
+ magnitude = bitIn.read(sharedWidth);
+ }
+
+ int value = (sign == 1) ? -magnitude : magnitude;
+ decodedList.add(value);
+ }
+
+ valuesRead += groupLength;
+ }
+
+ return decodedList.stream().mapToInt(i -> i).toArray();
+ }
+
+ private static class DBPValue {
+ int value;
+ int position;
+
+ DBPValue(int value, int position) {
+ this.value = value;
+ this.position = position;
+ }
+ }
+
+ private int[] decodeDBP(int segmentLength, BitInputStream bitIn) throws IOException {
+ int nonZeroCount = bitIn.read(16);
+
+ if (nonZeroCount == 0) {
+ return new int[segmentLength];
+ }
+
+ List<Integer> positions = new ArrayList<>(nonZeroCount);
+ int posWidth = (segmentLength == 0) ? 0 : 32 - Integer.numberOfLeadingZeros(segmentLength - 1);
+ if (posWidth == 0) posWidth = 1;
+
+ for (int i = 0; i < nonZeroCount; i++) {
+ positions.add(bitIn.read(posWidth));
+ }
+
+ List<Integer> values = new ArrayList<>(nonZeroCount);
+
+ int prevValWidth = bitIn.read(5);
+
+ int sign = bitIn.read(1);
+ int magnitude = bitIn.read(prevValWidth);
+ int firstVal = (sign == 1) ? -magnitude : magnitude;
+ values.add(firstVal);
+
+ for (int i = 1; i < nonZeroCount; i++) {
+ int currentSign = bitIn.read(1);
+ int currentMagnitude = bitIn.read(prevValWidth);
+ int currentVal = (currentSign == 1) ? -currentMagnitude : currentMagnitude;
+ values.add(currentVal);
+
+ int currentAbsVal = Math.abs(currentVal);
+ prevValWidth = (currentAbsVal == 0) ? 1 : 32 - Integer.numberOfLeadingZeros(currentAbsVal);
+ }
+
+ int[] sequence = new int[segmentLength];
+ for (int i = 0; i < nonZeroCount; i++) {
+ int pos = positions.get(i);
+ int val = values.get(i);
+ if (pos < segmentLength) {
+ sequence[pos] = val;
+ } else {
+ throw new TsFileDecodingException(
+ "Decoded position " + pos + " is out of bounds for segment length " + segmentLength);
+ }
+ }
+
+ return sequence;
+ }
+
+ private int[] decodeResidualComponent(OptimalParams params, ByteArrayInputStream bais)
+ throws IOException {
+ BitInputStream bitIn = new BitInputStream(bais);
+ int[] residuals = decodeHybridResiduals(params.n, params.dResidualStar, bitIn);
+ return residuals;
+ }
+
+ private int[] decodeHybridResiduals(int n, int optimalD, BitInputStream bitIn)
+ throws IOException {
+ if (n == 0) {
+ return new int[0];
+ }
+
+ int[] residuals = new int[n];
+ int lowBitMask = (1 << optimalD) - 1;
+
+ for (int i = 0; i < n; i++) {
+ int sign = bitIn.read(1);
+
+ int lowMagnitude = 0;
+ if (optimalD > 0) {
+ lowMagnitude = bitIn.read(optimalD);
+ }
+
+ residuals[i] = (sign == 1) ? -lowMagnitude : lowMagnitude;
+ }
+
+ int[] highBitSequence = decodeDBP(n, bitIn);
+
+ for (int i = 0; i < n; i++) {
+ if (highBitSequence[i] != 0) {
+ int signedHighPart = highBitSequence[i];
+ int absHighPart = Math.abs(signedHighPart);
+
+ int absLowPart = Math.abs(residuals[i]);
+ int fullMagnitude = (absHighPart << optimalD) | absLowPart;
+
+ residuals[i] = (signedHighPart < 0) ? -fullMagnitude : fullMagnitude;
+ }
+ }
+
+ return residuals;
+ }
+
+ private static class BitInputStream {
+
+ private final ByteArrayInputStream byteInput;
+ private int bitBuffer;
+ private int bitsAvailable;
+
+ public BitInputStream(ByteArrayInputStream byteInput) {
+ this.byteInput = byteInput;
+ this.bitBuffer = 0;
+ this.bitsAvailable = 0;
+ }
+
+ public int read(int numBits) throws IOException {
+ if (numBits <= 0 || numBits > 32) {
+ throw new IllegalArgumentException("Number of bits must be between 1 and 32.");
+ }
+
+ while (bitsAvailable < numBits) {
+ int nextByte = byteInput.read();
+ if (nextByte == -1) {
+ throw new IOException(
+ "Unexpected end of stream while trying to read " + numBits + " bits.");
+ }
+ bitBuffer = (bitBuffer << 8) | (nextByte & 0xFF);
+ bitsAvailable += 8;
+ }
+
+ int value = (bitBuffer >> (bitsAvailable - numBits));
+
+ bitsAvailable -= numBits;
+
+ int mask = (1 << bitsAvailable) - 1;
+ bitBuffer &= mask;
+
+ return value;
+ }
+
+ public void close() {}
+ }
+
+ @Override
+ public boolean readBoolean(ByteBuffer buffer) {
+ throw new UnsupportedOperationException("FLEA only supports INT32.");
+ }
+
+ @Override
+ public short readShort(ByteBuffer buffer) {
+ throw new UnsupportedOperationException("FLEA only supports INT32.");
+ }
+
+ @Override
+ public long readLong(ByteBuffer buffer) {
+ throw new UnsupportedOperationException("FLEA only supports INT32.");
+ }
+
+ @Override
+ public float readFloat(ByteBuffer buffer) {
+ throw new UnsupportedOperationException("FLEA only supports INT32.");
+ }
+
+ @Override
+ public double readDouble(ByteBuffer buffer) {
+ throw new UnsupportedOperationException("FLEA only supports INT32.");
+ }
+
+ @Override
+ public Binary readBinary(ByteBuffer buffer) {
+ throw new UnsupportedOperationException("FLEA only supports INT32.");
+ }
+
+ @Override
+ public BigDecimal readBigDecimal(ByteBuffer buffer) {
+ throw new UnsupportedOperationException("FLEA only supports INT32.");
+ }
+
+ @Override
+ public void reset() {
+ decodedValues.clear();
+ }
+}
diff --git a/tsfile/src/main/java/org/apache/iotdb/tsfile/encoding/decoder/PeriodDecoder.java b/tsfile/src/main/java/org/apache/iotdb/tsfile/encoding/decoder/PeriodDecoder.java
deleted file mode 100644
index e45a2b7..0000000
--- a/tsfile/src/main/java/org/apache/iotdb/tsfile/encoding/decoder/PeriodDecoder.java
+++ /dev/null
@@ -1,255 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.iotdb.tsfile.encoding.decoder;
-
-import org.apache.iotdb.tsfile.file.metadata.enums.TSEncoding;
-
-import org.apache.commons.math3.complex.Complex;
-import org.apache.commons.math3.transform.DftNormalization;
-import org.apache.commons.math3.transform.FastFourierTransformer;
-import org.apache.commons.math3.transform.TransformType;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.stream.Collectors;
-import java.util.stream.IntStream;
-
-public class PeriodDecoder extends Decoder {
-
- private static final int MAX_SIZE = 0x7FFFFFFF;
- private static final int MAX_VALUE = 0x7FFFFFFF;
- private static final int GROUP_SIZE = 8;
-
- private static final FastFourierTransformer transformer =
- new FastFourierTransformer(DftNormalization.STANDARD);
-
- private static double[] irfft(Complex[] input, int n) {
- Complex[] conjugates = new Complex[n];
-
- // 构造逆FFT所需的复数数组
- for (int i = 0; i < input.length; i++) {
- if (i == 0 || (i == input.length - 1 && n % 2 == 0)) {
- conjugates[i] = input[i];
- } else {
- conjugates[i] = input[i];
- conjugates[n - i] = input[i].conjugate();
- }
- }
-
- // 进行逆FFT,并除以长度进行归一化
- Complex[] inverse = transformer.transform(conjugates, TransformType.INVERSE);
- double[] result = new double[n];
- for (int i = 0; i < n; i++) {
- result[i] = inverse[i].getReal() / n;
- }
-
- return result;
- }
-
- private static Complex[] compRoundInverse(int[] ret, int beta) {
- Complex[] result = new Complex[ret.length / 2];
-
- for (int i = 0; i < ret.length; i += 2) {
- double real = ret[i] * Math.pow(2, beta);
- double imag = ret[i + 1] * Math.pow(2, beta);
- result[i / 2] = new Complex(real, imag);
- }
-
- return result;
- }
-
- private static int bitLength(int value) {
- return Integer.SIZE - Integer.numberOfLeadingZeros(value);
- }
-
- private int decode(ByteBuffer buffer, int bits) {
- int value = 0;
- for (int i = 0; i < bits; i++) {
- value = (value << 1) | (buffer.get() & 1);
- }
- return value;
- }
-
- private List<Integer> descendingBitPackingDecode(ByteBuffer buffer) {
- boolean sgn = decode(buffer, 1) == 1;
- int dataLength = decode(buffer, bitLength(MAX_SIZE));
- List<Integer> data = new ArrayList<>(dataLength);
- for (int i = 0; i < dataLength; i++) {
- data.add(0);
- }
- int indexLength = decode(buffer, bitLength(MAX_SIZE));
- List<Integer> index = new ArrayList<>(indexLength);
- for (int i = 0; i < indexLength; i++) {
- index.add(0);
- }
- if (indexLength == 0) {
- return data;
- }
- for (int i = 0; i < indexLength; i += GROUP_SIZE) {
- int maxLen = decode(buffer, bitLength(bitLength(MAX_SIZE)));
- for (int j = i; j < Math.min(i + GROUP_SIZE, indexLength); j++) {
- index.set(j, decode(buffer, maxLen));
- }
- }
- int firstLen = decode(buffer, bitLength(bitLength(MAX_VALUE)));
- int currentLen = firstLen;
- for (int i = 0; i < indexLength; i++) {
- boolean currentSgn = sgn && decode(buffer, 1) == 1;
- int value = decode(buffer, currentLen);
- data.set(index.get(i), currentSgn ? -value : value);
- currentLen = bitLength(value);
- }
- return data;
- }
-
- private List<Integer> separateStorageDecode(ByteBuffer buffer) {
- int dataLength = decode(buffer, bitLength(MAX_SIZE));
- List<Integer> sgn = new ArrayList<>(dataLength);
- List<Integer> data = new ArrayList<>(dataLength);
- for (int i = 0; i < dataLength; i++) {
- sgn.add(0);
- data.add(0);
- }
- int D = decode(buffer, bitLength(bitLength(MAX_VALUE)));
- for (int i = 0; i < dataLength; i++) {
- sgn.set(i, decode(buffer, 1));
- data.set(i, decode(buffer, D));
- }
- List<Integer> high = descendingBitPackingDecode(buffer);
- for (int i = 0; i < dataLength; i++) {
- data.set(i, (sgn.get(i) == 0 ? 1 : -1) * ((high.get(i) << D) | data.get(i)));
- }
- return data;
- }
-
- public List<Integer> periodDecode(ByteBuffer buffer) throws IOException {
- int p = decode(buffer, bitLength(MAX_SIZE));
- if (p == 0) {
- return separateStorageDecode(buffer);
- }
- boolean betaSgn = decode(buffer, 1) == 1;
- int beta = decode(buffer, bitLength(bitLength(MAX_VALUE)));
- if (betaSgn) {
- beta *= -1;
- }
- Complex[] dataf =
- compRoundInverse(
- descendingBitPackingDecode(buffer).stream().mapToInt(i -> i).toArray(), beta);
- List<Integer> res = cumulativeSum(separateStorageDecode(buffer));
- int k = (res.size() + p - 1) / p;
- double[] tmp = irfft(dataf, p);
- List<Integer> tiledList = new ArrayList<>();
- for (int j = 0; j < k; j++) for (int i = 0; i < tmp.length; i++) tiledList.add((int) tmp[i]);
- return IntStream.range(0, res.size())
- .map(i -> tiledList.get(i) - res.get(i))
- .boxed()
- .collect(Collectors.toList());
- }
-
- // 辅助方法: 累积求和
- private List<Integer> cumulativeSum(List<Integer> list) {
- int sum = 0;
- for (int i = 0; i < list.size(); i++) {
- sum += list.get(i);
- list.set(i, sum);
- }
- return list;
- }
-
- List<Integer> data;
- int curPos;
- boolean isRead;
-
- public PeriodDecoder() {
- super(TSEncoding.PERIOD);
- reset();
- }
-
- // @Override
- // public boolean readBoolean(ByteBuffer buffer) {
- // return buffer.get() != 0;
- // }
-
- // @Override
- // public short readShort(ByteBuffer buffer) {
- // return buffer.getShort();
- // }
-
- @Override
- public int readInt(ByteBuffer buffer) {
- try {
- if (isRead == false) {
- data = periodDecode(buffer);
- isRead = true;
- curPos = 0;
- }
- curPos++;
- return data.get(curPos - 1);
- } catch (Exception e) {
- return -1;
- }
- }
-
- // @Override
- // public long readLong(ByteBuffer buffer) {
- // return buffer.getLong();
- // }
-
- // @Override
- // public float readFloat(ByteBuffer buffer) {
- // return buffer.getFloat();
- // }
-
- // @Override
- // public double readDouble(ByteBuffer buffer) {
- // return buffer.getDouble();
- // }
-
- // @Override
- // public Binary readBinary(ByteBuffer buffer) {
- // int length = readInt(buffer);
- // byte[] buf = new byte[length];
- // buffer.get(buf, 0, buf.length);
- // return new Binary(buf);
- // }
-
- @Override
- public boolean hasNext(ByteBuffer buffer) throws IOException {
- if (isRead == false) {
- data = periodDecode(buffer);
- isRead = true;
- curPos = 0;
- }
- return curPos < data.size();
- }
-
- // @Override
- // public BigDecimal readBigDecimal(ByteBuffer buffer) {
- // throw new TsFileDecodingException("Method readBigDecimal is not supported by
- // PeriodDecoder");
- // }
-
- @Override
- public void reset() {
- isRead = false;
- }
-}
diff --git a/tsfile/src/main/java/org/apache/iotdb/tsfile/encoding/encoder/FLEAEncoder.java b/tsfile/src/main/java/org/apache/iotdb/tsfile/encoding/encoder/FLEAEncoder.java
new file mode 100644
index 0000000..95b44f9
--- /dev/null
+++ b/tsfile/src/main/java/org/apache/iotdb/tsfile/encoding/encoder/FLEAEncoder.java
@@ -0,0 +1,681 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.tsfile.encoding.encoder;
+
+import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
+import org.apache.iotdb.tsfile.file.metadata.enums.TSEncoding;
+import org.apache.iotdb.tsfile.utils.Binary;
+
+import org.apache.commons.math3.complex.Complex;
+import org.apache.commons.math3.transform.DftNormalization;
+import org.apache.commons.math3.transform.FastFourierTransformer;
+import org.apache.commons.math3.transform.TransformType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class FLEAEncoder extends Encoder {
+
+ private static final Logger logger = LoggerFactory.getLogger(FLEAEncoder.class);
+ private final TSDataType dataType;
+
+ private final List<Integer> valuesBuffer;
+ private final int blockSize;
+
+ private static final int DEFAULT_BLOCK_SIZE = 256;
+ private static final int MAX_BETA_CANDIDATES = 10;
+
+ public FLEAEncoder() {
+ this(TSDataType.INT32, DEFAULT_BLOCK_SIZE);
+ }
+
+ public FLEAEncoder(TSDataType dataType, int blockSize) {
+ super(TSEncoding.FLEA);
+ if (dataType != TSDataType.INT32) {
+ throw new UnsupportedOperationException(
+ "FLEAEncoder currently only supports INT32 data type.");
+ }
+ this.dataType = dataType;
+ this.valuesBuffer = new ArrayList<>();
+ this.blockSize = blockSize;
+ logger.info("FLEAEncoder initialized for INT32 with block size: {}", this.blockSize);
+ }
+
+ @Override
+ public void encode(int value, ByteArrayOutputStream out) {
+ valuesBuffer.add(value);
+ if (valuesBuffer.size() >= blockSize) {
+ try {
+ flush(out);
+ } catch (IOException e) {
+ logger.error("FLEAEncoder: IOException during flush operation for INT32.", e);
+ }
+ }
+ }
+
+ @Override
+ public void flush(ByteArrayOutputStream out) throws IOException {
+ if (valuesBuffer.isEmpty()) {
+ return;
+ }
+
+ logger.debug("FLEAEncoder: Flushing {} INT32 values.", valuesBuffer.size());
+
+ double[] blockData = valuesBuffer.stream().mapToDouble(Integer::doubleValue).toArray();
+ int n = blockData.length;
+
+ OptimalParams optimalParams = findOptimalBetaAndSplitPoints(blockData);
+
+ byte[] encodedData = performActualEncoding(blockData, optimalParams, n);
+
+ out.write(ByteBuffer.allocate(4).putInt(encodedData.length).array());
+ out.write(encodedData);
+
+ valuesBuffer.clear();
+ }
+
+ private static class OptimalParams {
+ int betaStar;
+ int pReStar;
+ int pImStar;
+ int dResidualStar;
+
+ OptimalParams(int beta, int pRe, int pIm) {
+ this.betaStar = beta;
+ this.pReStar = pRe;
+ this.pImStar = pIm;
+ this.dResidualStar = 0;
+ }
+ }
+
+ private OptimalParams findOptimalBetaAndSplitPoints(double[] blockData) {
+ logger.debug("Finding optimal beta and split points for block of size {}", blockData.length);
+
+ final int n = blockData.length;
+ if (n == 0) {
+ return new OptimalParams(0, 0, 0);
+ }
+ final FastFourierTransformer fft = new FastFourierTransformer(DftNormalization.STANDARD);
+ final Complex[] originalFreqComplex = fft.transform(blockData, TransformType.FORWARD);
+
+ final int n_half = (n / 2) + 1;
+
+ double minTotalCost = Double.MAX_VALUE;
+ OptimalParams bestParams = new OptimalParams(0, 0, 0);
+
+ for (int betaCandidate = 8; betaCandidate < 24; betaCandidate += 2) {
+
+ int[] quantizedFreqRe = new int[n_half];
+ int[] quantizedFreqIm = new int[n_half];
+ double quantizationFactor = Math.pow(2, betaCandidate);
+
+ for (int j = 0; j < n_half; j++) {
+ quantizedFreqRe[j] =
+ (int) Math.round(originalFreqComplex[j].getReal() / quantizationFactor);
+ quantizedFreqIm[j] =
+ (int) Math.round(originalFreqComplex[j].getImaginary() / quantizationFactor);
+ }
+
+ double costResidual =
+ estimateResidualCost(
+ n, originalFreqComplex, quantizedFreqRe, quantizedFreqIm, betaCandidate);
+
+ CostAndSplits freqCostResult = estimateFrequencyCost(quantizedFreqRe, quantizedFreqIm);
+
+ double currentTotalCost = costResidual + freqCostResult.cost;
+ logger.trace(
+ "For beta={}: FreqCost={}, ResidCost={}, TotalCost={}",
+ betaCandidate,
+ freqCostResult.cost,
+ costResidual,
+ currentTotalCost);
+
+ if (currentTotalCost < minTotalCost) {
+ minTotalCost = currentTotalCost;
+ bestParams.betaStar = betaCandidate;
+ bestParams.pReStar = freqCostResult.pRe;
+ bestParams.pImStar = freqCostResult.pIm;
+ }
+ }
+
+ logger.info(
+ "Found optimal parameters: beta={}, p_re={}, p_im={}",
+ bestParams.betaStar,
+ bestParams.pReStar,
+ bestParams.pImStar);
+
+ return bestParams;
+ }
+
+ private static class CostAndSplits {
+ double cost;
+ int pRe;
+ int pIm;
+
+ CostAndSplits(double c, int pr, int pi) {
+ this.cost = c;
+ this.pRe = pr;
+ this.pIm = pi;
+ }
+ }
+
+ private CostAndSplits estimateFrequencyCost(int[] quantizedFreqRe, int[] quantizedFreqIm) {
+ logger.debug("Estimating frequency cost...");
+
+ SplitResult reResult = findOptimalSplitForSequence(quantizedFreqRe);
+ SplitResult imResult = findOptimalSplitForSequence(quantizedFreqIm);
+
+ double totalCost = reResult.minCost + imResult.minCost;
+ return new CostAndSplits(totalCost, reResult.pStar, imResult.pStar);
+ }
+
+ private static class SplitResult {
+ double minCost;
+ int pStar;
+
+ SplitResult(double mc, int ps) {
+ this.minCost = mc;
+ this.pStar = ps;
+ }
+ }
+
+ private SplitResult findOptimalSplitForSequence(int[] sequence) {
+ logger.debug("Finding optimal split for sequence of length {}", sequence.length);
+ final int n = sequence.length;
+ if (n == 0) {
+ return new SplitResult(0, 0);
+ }
+
+ double[] costPrefixGVLE = new double[n + 1];
+ costPrefixGVLE[0] = 0;
+ for (int p = 1; p <= n; p++) {
+ costPrefixGVLE[p] = costGVLE(Arrays.copyOfRange(sequence, 0, p));
+ }
+
+ double[] costSuffixDBP = new double[n + 1];
+ costSuffixDBP[n] = 0;
+ for (int p = n - 1; p >= 0; p--) {
+ costSuffixDBP[p] = costDBP(Arrays.copyOfRange(sequence, p, n));
+ }
+
+ double minTotalCost = Double.MAX_VALUE;
+ int bestP = 0;
+ for (int p = 0; p <= n; p++) {
+ double currentTotalCost = costPrefixGVLE[p] + costSuffixDBP[p];
+ if (currentTotalCost < minTotalCost) {
+ minTotalCost = currentTotalCost;
+ bestP = p;
+ }
+ }
+
+ logger.trace("Found best split point p*={} with cost={}", bestP, minTotalCost);
+ return new SplitResult(minTotalCost, bestP);
+ }
+
+ private double estimateResidualCost(
+ int n, Complex[] originalFreq, int[] quantizedFreqRe, int[] quantizedFreqIm, int beta) {
+ logger.debug("Estimating residual cost for beta={}", beta);
+ double quantizationFactor = Math.pow(2, beta);
+ double eFreq = 0;
+
+ for (int j = 0; j < quantizedFreqRe.length; j++) {
+ double dequantReal = (double) quantizedFreqRe[j] * quantizationFactor;
+ double dequantImag = (double) quantizedFreqIm[j] * quantizationFactor;
+ double errorReal = dequantReal - originalFreq[j].getReal();
+ double errorImag = dequantImag - originalFreq[j].getImaginary();
+
+ double errorMagnitudeSq = errorReal * errorReal + errorImag * errorImag;
+
+ if (j > 0 && j < (n / 2)) {
+ eFreq += 2 * errorMagnitudeSq;
+ } else {
+ eFreq += errorMagnitudeSq;
+ }
+ }
+
+ if (n == 0 || eFreq < 1e-9) return 0;
+
+ double eR = (1.0 / n) * Math.sqrt(eFreq);
+ if (eR < 1e-9) eR = 1e-9;
+
+ int de = (int) Math.ceil(Math.log(eR) / Math.log(2));
+ int ds = de + 1;
+
+ return (double) n * (ds + 1);
+ }
+
+ private double costGVLE(int[] sequence) {
+ final int m = sequence.length;
+ if (m == 0) {
+ return 0;
+ }
+
+ int[] wSuffix = new int[m];
+ wSuffix[m - 1] =
+ (sequence[m - 1] == 0) ? 0 : (32 - Integer.numberOfLeadingZeros(Math.abs(sequence[m - 1])));
+ for (int i = m - 2; i >= 0; i--) {
+ int currentWidth =
+ (sequence[i] == 0) ? 0 : (32 - Integer.numberOfLeadingZeros(Math.abs(sequence[i])));
+ wSuffix[i] = Math.max(currentWidth, wSuffix[i + 1]);
+ }
+
+ double totalCost = 0;
+ final int HEADER_COST = 16;
+
+ int currentIdx = 0;
+ while (currentIdx < m) {
+ int sharedWidth = wSuffix[currentIdx];
+ int groupStartIdx = currentIdx;
+
+ while (currentIdx < m && wSuffix[currentIdx] == sharedWidth) {
+ currentIdx++;
+ }
+ int groupLength = currentIdx - groupStartIdx;
+
+ totalCost += HEADER_COST;
+ totalCost += (double) groupLength * (sharedWidth + 1);
+ }
+
+ return totalCost;
+ }
+
+ private double costDBP(int[] sequence) {
+ final int m_prime = sequence.length;
+ if (m_prime == 0) {
+ return 0;
+ }
+
+ final int pos_cost = (m_prime == 0) ? 0 : (32 - Integer.numberOfLeadingZeros(m_prime));
+ double totalCost = 0;
+
+ for (int val : sequence) {
+ if (val != 0) {
+ int absVal = Math.abs(val);
+ int val_cost = (absVal == 0) ? 0 : (32 - Integer.numberOfLeadingZeros(absVal));
+
+ totalCost += pos_cost + val_cost + 1;
+ }
+ }
+
+ return totalCost;
+ }
+
+ private byte[] performActualEncoding(double[] blockData, OptimalParams params, int n)
+ throws IOException {
+ logger.info(
+ "Performing actual encoding with beta={}, p_re={}, p_im={}",
+ params.betaStar,
+ params.pReStar,
+ params.pImStar);
+
+ final FastFourierTransformer fft = new FastFourierTransformer(DftNormalization.STANDARD);
+ final Complex[] freqComplex = fft.transform(blockData, TransformType.FORWARD);
+ final int n_half = (n / 2) + 1;
+ final double quantizationFactor = Math.pow(2, params.betaStar);
+
+ int[] F_hat_re = new int[n_half];
+ int[] F_hat_im = new int[n_half];
+ Complex[] F_hat_complex_dequant = new Complex[n];
+
+ for (int j = 0; j < n_half; j++) {
+ F_hat_re[j] = (int) Math.round(freqComplex[j].getReal() / quantizationFactor);
+ F_hat_im[j] = (int) Math.round(freqComplex[j].getImaginary() / quantizationFactor);
+
+ F_hat_complex_dequant[j] =
+ new Complex(
+ (double) F_hat_re[j] * quantizationFactor, (double) F_hat_im[j] * quantizationFactor);
+ }
+
+ for (int j = 1; j < n_half; j++) {
+ if (n - j < n) {
+ F_hat_complex_dequant[n - j] = F_hat_complex_dequant[j].conjugate();
+ }
+ }
+
+ final Complex[] reconstructedTimeComplex =
+ fft.transform(F_hat_complex_dequant, TransformType.INVERSE);
+ final int[] R_star = new int[n];
+ for (int k = 0; k < n; k++) {
+ R_star[k] = (int) Math.round(blockData[k] - reconstructedTimeComplex[k].getReal());
+ }
+
+ params.dResidualStar = findOptimalDForResiduals(R_star);
+ logger.debug("Found optimal D* for residuals: {}", params.dResidualStar);
+
+ ByteArrayOutputStream metadataBaos = new ByteArrayOutputStream();
+ ByteArrayOutputStream freqBaos = new ByteArrayOutputStream();
+ ByteArrayOutputStream residBaos = new ByteArrayOutputStream();
+
+ encodeMetadata(params, n, metadataBaos);
+ encodeFrequencyComponent(F_hat_re, F_hat_im, params.pReStar, params.pImStar, freqBaos);
+ encodeResidualComponent(R_star, params.dResidualStar, residBaos);
+
+ ByteArrayOutputStream finalBaos = new ByteArrayOutputStream();
+ finalBaos.write(metadataBaos.toByteArray());
+ finalBaos.write(freqBaos.toByteArray());
+ finalBaos.write(residBaos.toByteArray());
+
+ return finalBaos.toByteArray();
+ }
+
+ private void encodeMetadata(OptimalParams params, int n, ByteArrayOutputStream out)
+ throws IOException {
+ // IMPORTANT: 'n' must be encoded for the decoder.
+
+ // 5 integers * 4 bytes/int = 20 bytes
+ ByteBuffer metaBuffer = ByteBuffer.allocate(20);
+ metaBuffer.putInt(n); // Add 'n' to the metadata
+ metaBuffer.putInt(params.betaStar);
+ metaBuffer.putInt(params.pReStar);
+ metaBuffer.putInt(params.pImStar);
+ metaBuffer.putInt(params.dResidualStar);
+ out.write(metaBuffer.array());
+ logger.debug(
+ "Encoded metadata: n={}, beta={}, p_re={}, p_im={}, d_res={}",
+ n,
+ params.betaStar,
+ params.pReStar,
+ params.pImStar,
+ params.dResidualStar);
+ }
+
+ private int findOptimalDForResiduals(int[] residuals) {
+ int bestD = 0;
+ double minCost = Double.MAX_VALUE;
+
+ for (int d = 0; d < 16; d++) {
+ double currentCost = 0;
+ currentCost += (double) residuals.length * (d + 1);
+
+ List<Integer> highBitValues = new ArrayList<>();
+ int threshold = 1 << d;
+ for (int r : residuals) {
+ if (Math.abs(r) >= threshold) {
+ highBitValues.add(r >> d);
+ }
+ }
+
+ currentCost += costDBP(highBitValues.stream().mapToInt(i -> i).toArray());
+
+ if (currentCost < minCost) {
+ minCost = currentCost;
+ bestD = d;
+ }
+ }
+ return bestD;
+ }
+
+ private void encodeFrequencyComponent(
+ int[] F_re, int[] F_im, int p_re, int p_im, ByteArrayOutputStream out) throws IOException {
+ logger.debug("Encoding frequency components: p_re={}, p_im={}", p_re, p_im);
+
+ encodeGVLE(Arrays.copyOfRange(F_re, 0, p_re), out);
+ encodeDBP(Arrays.copyOfRange(F_re, p_re, F_re.length), out);
+
+ encodeGVLE(Arrays.copyOfRange(F_im, 0, p_im), out);
+ encodeDBP(Arrays.copyOfRange(F_im, p_im, F_im.length), out);
+ }
+
+ private void encodeGVLE(int[] sequence, ByteArrayOutputStream out) throws IOException {
+ final int m = sequence.length;
+ if (m == 0) {
+ return;
+ }
+ logger.trace("Actual GVLE encoding for seq length {}", m);
+
+ BitOutputStream bitOut = new BitOutputStream(out);
+
+ int[] wSuffix = new int[m];
+ wSuffix[m - 1] =
+ (sequence[m - 1] == 0) ? 0 : 32 - Integer.numberOfLeadingZeros(Math.abs(sequence[m - 1]));
+ for (int i = m - 2; i >= 0; i--) {
+ int currentWidth =
+ (sequence[i] == 0) ? 0 : 32 - Integer.numberOfLeadingZeros(Math.abs(sequence[i]));
+ wSuffix[i] = Math.max(currentWidth, wSuffix[i + 1]);
+ }
+
+ int currentIdx = 0;
+ while (currentIdx < m) {
+ int sharedWidth = wSuffix[currentIdx];
+ int groupStartIdx = currentIdx;
+ while (currentIdx < m && wSuffix[currentIdx] == sharedWidth) {
+ currentIdx++;
+ }
+ int groupLength = currentIdx - groupStartIdx;
+
+ bitOut.write(sharedWidth, 5);
+ bitOut.write(groupLength, 11);
+
+ if (sharedWidth > 0) {
+ for (int i = groupStartIdx; i < currentIdx; i++) {
+ int val = sequence[i];
+ bitOut.write(val >= 0 ? 0 : 1, 1);
+ bitOut.write(Math.abs(val), sharedWidth);
+ }
+ }
+ }
+
+ bitOut.flush();
+ }
+
+ private static class DBPValue {
+ int value;
+ int position;
+
+ DBPValue(int value, int position) {
+ this.value = value;
+ this.position = position;
+ }
+ }
+
+ private void encodeDBP(int[] sequence, ByteArrayOutputStream out) throws IOException {
+ final int m = sequence.length;
+ if (m == 0) {
+ return;
+ }
+ logger.trace("Actual DBP encoding for seq length {}", m);
+
+ List<DBPValue> nonZeros = new ArrayList<>();
+ for (int i = 0; i < m; i++) {
+ if (sequence[i] != 0) {
+ nonZeros.add(new DBPValue(sequence[i], i));
+ }
+ }
+
+ if (nonZeros.isEmpty()) {
+ return;
+ }
+
+ nonZeros.sort((a, b) -> Integer.compare(Math.abs(b.value), Math.abs(a.value)));
+
+ BitOutputStream bitOut = new BitOutputStream(out);
+
+ int countWidth = (m == 0) ? 0 : 32 - Integer.numberOfLeadingZeros(m);
+ bitOut.write(nonZeros.size(), 16);
+
+ int posWidth = (m == 0) ? 0 : 32 - Integer.numberOfLeadingZeros(m - 1);
+ if (posWidth == 0) posWidth = 1;
+
+ for (DBPValue dbpVal : nonZeros) {
+ bitOut.write(dbpVal.position, posWidth);
+ }
+
+ int firstVal = nonZeros.get(0).value;
+ int firstValAbs = Math.abs(firstVal);
+ int prevValWidth = (firstValAbs == 0) ? 1 : 32 - Integer.numberOfLeadingZeros(firstValAbs);
+
+ bitOut.write(prevValWidth, 5);
+
+ bitOut.write(firstVal >= 0 ? 0 : 1, 1);
+ bitOut.write(firstValAbs, prevValWidth);
+
+ for (int i = 1; i < nonZeros.size(); i++) {
+ int currentVal = nonZeros.get(i).value;
+ int currentValAbs = Math.abs(currentVal);
+
+ bitOut.write(currentVal >= 0 ? 0 : 1, 1);
+ bitOut.write(currentValAbs, prevValWidth);
+
+ prevValWidth = (currentValAbs == 0) ? 1 : 32 - Integer.numberOfLeadingZeros(currentValAbs);
+ }
+
+ bitOut.flush();
+ }
+
+ private void encodeResidualComponent(int[] residuals, int optimalD, ByteArrayOutputStream out)
+ throws IOException {
+ final int n = residuals.length;
+ if (n == 0) {
+ return;
+ }
+ logger.debug("Actual Hybrid Residual Encoding for {} residuals with optimalD={}", n, optimalD);
+
+ BitOutputStream bitOut = new BitOutputStream(out);
+
+ List<DBPValue> highBitNonZeros = new ArrayList<>();
+ int lowBitMask = (1 << optimalD) - 1;
+
+ for (int i = 0; i < n; i++) {
+ int r = residuals[i];
+ int absR = Math.abs(r);
+
+ bitOut.write(r >= 0 ? 0 : 1, 1);
+
+ if (optimalD > 0) {
+ bitOut.write(absR & lowBitMask, optimalD);
+ }
+
+ if (absR >= (1 << optimalD)) {
+ int highBitValue = absR >> optimalD;
+ int signedHighBitValue = (r < 0) ? -highBitValue : highBitValue;
+
+ highBitNonZeros.add(new DBPValue(signedHighBitValue, i));
+ }
+ }
+
+ bitOut.flush();
+
+ ByteArrayOutputStream dbpBaos = new ByteArrayOutputStream();
+
+ int[] highBitSequence = new int[n];
+ for (DBPValue dbpVal : highBitNonZeros) {
+ highBitSequence[dbpVal.position] = dbpVal.value;
+ }
+
+ encodeDBP(highBitSequence, dbpBaos);
+
+ out.write(dbpBaos.toByteArray());
+ }
+
+ @Override
+ public void encode(boolean value, ByteArrayOutputStream out) {
+ throw new UnsupportedOperationException("FLEA only supports INT32.");
+ }
+
+ @Override
+ public void encode(short value, ByteArrayOutputStream out) {
+ throw new UnsupportedOperationException("FLEA only supports INT32.");
+ }
+
+ @Override
+ public void encode(long value, ByteArrayOutputStream out) {
+ throw new UnsupportedOperationException("FLEA only supports INT32.");
+ }
+
+ @Override
+ public void encode(float value, ByteArrayOutputStream out) {
+ throw new UnsupportedOperationException("FLEA only supports INT32.");
+ }
+
+ @Override
+ public void encode(double value, ByteArrayOutputStream out) {
+ throw new UnsupportedOperationException("FLEA only supports INT32.");
+ }
+
+ @Override
+ public void encode(Binary value, ByteArrayOutputStream out) {
+ throw new UnsupportedOperationException("FLEA only supports INT32.");
+ }
+
+ @Override
+ public void encode(BigDecimal value, ByteArrayOutputStream out) {
+ throw new UnsupportedOperationException("FLEA only supports INT32.");
+ }
+
+ @Override
+ public int getOneItemMaxSize() {
+ if (dataType == TSDataType.INT32) {
+ return 4 + 1;
+ }
+ throw new UnsupportedOperationException(dataType.toString());
+ }
+
+ @Override
+ public long getMaxByteSize() {
+ return (long) blockSize * 4 + 64;
+ }
+
+ private static class BitOutputStream {
+
+ private final ByteArrayOutputStream byteOutput;
+ private int bitBuffer;
+ private int bitsInBuffer;
+
+ public BitOutputStream(ByteArrayOutputStream byteOutput) {
+ this.byteOutput = byteOutput;
+ this.bitBuffer = 0;
+ this.bitsInBuffer = 0;
+ }
+
+ public void write(int value, int numBits) throws IOException {
+ if (numBits <= 0 || numBits > 32) {
+ throw new IllegalArgumentException("Number of bits must be between 1 and 32.");
+ }
+
+ long mask = (1L << numBits) - 1;
+ bitBuffer = (bitBuffer << numBits) | ((int) value & (int) mask);
+ bitsInBuffer += numBits;
+
+ while (bitsInBuffer >= 8) {
+ int byteToWrite = (bitBuffer >> (bitsInBuffer - 8));
+ byteOutput.write(byteToWrite);
+
+ bitsInBuffer -= 8;
+ }
+ }
+
+ public void flush() throws IOException {
+ if (bitsInBuffer > 0) {
+ int byteToWrite = (bitBuffer << (8 - bitsInBuffer));
+ byteOutput.write(byteToWrite);
+
+ bitsInBuffer = 0;
+ bitBuffer = 0;
+ }
+ }
+ }
+}
diff --git a/tsfile/src/main/java/org/apache/iotdb/tsfile/encoding/encoder/PeriodEncoder.java b/tsfile/src/main/java/org/apache/iotdb/tsfile/encoding/encoder/PeriodEncoder.java
deleted file mode 100644
index 10b094d..0000000
--- a/tsfile/src/main/java/org/apache/iotdb/tsfile/encoding/encoder/PeriodEncoder.java
+++ /dev/null
@@ -1,582 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.iotdb.tsfile.encoding.encoder;
-
-import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
-import org.apache.iotdb.tsfile.file.metadata.enums.TSEncoding;
-
-import org.apache.commons.math3.complex.Complex;
-import org.apache.commons.math3.transform.DftNormalization;
-import org.apache.commons.math3.transform.FastFourierTransformer;
-import org.apache.commons.math3.transform.TransformType;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-public class PeriodEncoder extends Encoder {
-
- private static final Logger logger = LoggerFactory.getLogger(PeriodEncoder.class);
- private TSDataType dataType;
- private int maxStringLength;
-
- private static Object[] compRound(Complex[] dataf, int beta) {
- Complex[] newDataf = new Complex[dataf.length];
- int[] ret = new int[dataf.length * 2];
-
- for (int i = 0; i < dataf.length; i++) {
- int a = (int) Math.round(dataf[i].getReal() / Math.pow(2, beta));
- int b = (int) Math.round(dataf[i].getImaginary() / Math.pow(2, beta));
- ret[2 * i] = a;
- ret[2 * i + 1] = b;
-
- double newA = a * Math.pow(2, beta);
- double newB = b * Math.pow(2, beta);
- newDataf[i] = new Complex(newA, newB);
- }
- return new Object[] {newDataf, ret};
- }
-
- private static final FastFourierTransformer transformer =
- new FastFourierTransformer(DftNormalization.STANDARD);
-
- private static Complex[] fft(double[] input) {
- Complex[] transformed = transformer.transform(input, TransformType.FORWARD);
- return transformed;
- }
-
- private static double[] ifft(Complex[] input) {
-
- // 进行逆FFT,并除以长度进行归一化
- Complex[] inverse = transformer.transform(input, TransformType.INVERSE);
- double[] result = new double[input.length];
- for (int i = 0; i < input.length; i++) {
- result[i] = inverse[i].getReal() / input.length;
- }
-
- return result;
- }
-
- private static Complex[] rfft(double[] input) {
- Complex[] transformed = transformer.transform(input, TransformType.FORWARD);
-
- // 只保留一半的结果(正频率部分)
- int n = input.length;
- Complex[] rfftResult = new Complex[n / 2 + 1];
- for (int i = 0; i < n / 2 + 1; i++) {
- rfftResult[i] = transformed[i];
- }
-
- return rfftResult;
- }
-
- private static double[] irfft(Complex[] input, int n) {
- Complex[] conjugates = new Complex[n];
-
- // 构造逆FFT所需的复数数组
- for (int i = 0; i < input.length; i++) {
- if (i == 0 || (i == input.length - 1 && n % 2 == 0)) {
- conjugates[i] = input[i];
- } else {
- conjugates[i] = input[i];
- conjugates[n - i] = input[i].conjugate();
- }
- }
-
- // 进行逆FFT,并除以长度进行归一化
- Complex[] inverse = transformer.transform(conjugates, TransformType.INVERSE);
- double[] result = new double[n];
- for (int i = 0; i < n; i++) {
- result[i] = inverse[i].getReal() / n;
- }
-
- return result;
- }
-
- // 计算多项式乘法
- private static double[] polyMul(double[] p1, double[] p2) {
- int n = (int) Math.pow(2, Math.ceil(Math.log(p1.length + p2.length - 1) / Math.log(2)));
- p1 = padArray(p1, n);
- p2 = padArray(p2, n);
- Complex[] p1Transformed = fft(p1);
- Complex[] p2Transformed = fft(p2);
- Complex[] resultTransformed = new Complex[n];
- for (int i = 0; i < n; i++) {
- resultTransformed[i] = p1Transformed[i].multiply(p2Transformed[i]);
- }
- return ifft(resultTransformed);
- }
-
- // 数组填充
- private static double[] padArray(double[] array, int length) {
- double[] padded = new double[length];
- System.arraycopy(array, 0, padded, 0, array.length);
- return padded;
- }
-
- // 归一化
- private static double[] normalize(double[] x) {
- double mean = mean(x);
- double std = std(x);
- double[] normalized = new double[x.length];
- for (int i = 0; i < x.length; i++) {
- normalized[i] = (x[i] - mean) / std;
- }
- return normalized;
- }
-
- // 计算均值
- private static double mean(double[] x) {
- double sum = 0;
- for (double v : x) {
- sum += v;
- }
- return sum / x.length;
- }
-
- // 计算标准差
- private static double std(double[] x) {
- double mean = mean(x);
- double sum = 0;
- for (double v : x) {
- sum += Math.pow(v - mean, 2);
- }
- return Math.sqrt(sum / x.length);
- }
-
- // 用fft加速计算自相关函数
- private static double[] selfCorrFast(double[] x) {
- x = normalize(x);
- int N = x.length;
- double[] xSelf = polyMul(x, reverseArray(x));
- double[] result = new double[(int) (N * (2.0 / 3.0))];
- for (int i = 0; i < result.length; i++) {
- result[i] = xSelf[N - 1 - i] / (N - i);
- }
- return result;
- }
-
- // 数组反转
- private static double[] reverseArray(double[] x) {
- double[] reversed = new double[x.length];
- for (int i = 0; i < x.length; i++) {
- reversed[i] = x[x.length - 1 - i];
- }
- return reversed;
- }
-
- // 给出数组中是邻近k个内最大的数的下标数组
- private static int[] pinkLocalMax(double[] data) {
- final int k = 8; // 直接引入常数
- int[] result = new int[data.length];
- int count = 0;
- for (int i = k; i < data.length - k; i++) {
- double maxVal = data[i];
- for (int j = Math.max(0, i - k); j < Math.min(data.length, i + k); j++) {
- maxVal = Math.max(maxVal, data[j]);
- }
- if (maxVal == data[i]) {
- result[count++] = i;
- }
- }
- return Arrays.copyOf(result, count);
- }
-
- // 借助fft求出周期长度
- private static int getPeriod(double[] data) {
- final double p = 0.5; // 直接引入常数
- double[] dataCorr = selfCorrFast(data);
- int[] points = pinkLocalMax(dataCorr);
- for (int point : points) {
- if (point > 0 && dataCorr[point] > p) {
- return point;
- }
- }
- return 0;
- }
-
- static class ByteOutToys {
- private final ByteArrayOutputStream outputStream;
-
- public ByteOutToys(ByteArrayOutputStream outputStream) {
- this.outputStream = outputStream;
- }
-
- public void encode(int value, int bits) throws IOException {
- for (int i = bits - 1; i >= 0; i--) {
- outputStream.write((value >> i) & 1);
- }
- }
- }
-
- private static final int MAX_SIZE = 0x7FFFFFFF;
- private static final int MAX_VALUE = 0x7FFFFFFF;
- private static final int GROUP_SIZE = 8;
-
- private static int bitLength(int value) {
- return Integer.SIZE - Integer.numberOfLeadingZeros(value);
- }
-
- private static int[] getCnt(int[] data) {
- int[] cnt = new int[bitLength(MAX_VALUE) + 1];
- for (int i = 0; i < data.length; i++) {
- if (data[i] != 0) {
- cnt[bitLength(Math.abs(data[i]))]++;
- }
- }
- return cnt;
- }
-
- private static int[] bitLengthOrder(int[] data) {
- int[] cnt = getCnt(data);
- cnt[0] = 0;
- for (int i = cnt.length - 2; i >= 0; i--) {
- cnt[i] += cnt[i + 1];
- }
- int n = cnt[0];
- int[] result = new int[n];
- for (int i = data.length - 1; i >= 0; i--) {
- if (data[i] != 0) {
- result[cnt[bitLength(Math.abs(data[i]))] - 1] = i;
- cnt[bitLength(Math.abs(data[i]))]--;
- }
- }
- return result;
- }
-
- private static void descendingBitPacking(ByteOutToys stream, int[] data, boolean sgn)
- throws IOException {
- stream.encode(sgn ? 1 : 0, 1);
- int[] index = bitLengthOrder(data);
- stream.encode(data.length, bitLength(MAX_SIZE));
- stream.encode(index.length, bitLength(MAX_SIZE));
- if (index.length == 0) {
- return;
- }
- for (int i = 0; i < index.length; i += GROUP_SIZE) {
- int maxLen = 0;
- for (int j = i; j < Math.min(i + GROUP_SIZE, index.length); j++) {
- maxLen = Math.max(maxLen, bitLength(index[j]));
- }
- stream.encode(maxLen, bitLength(bitLength(MAX_SIZE)));
- for (int j = i; j < Math.min(i + GROUP_SIZE, index.length); j++) {
- stream.encode(index[j], maxLen);
- }
- }
- int firstLen = bitLength(Math.abs(data[index[0]]));
- int currentLen = firstLen;
- stream.encode(firstLen, bitLength(bitLength(MAX_VALUE)));
- for (int i : index) {
- if (sgn) {
- stream.encode(data[i] < 0 ? 1 : 0, 1);
- }
- stream.encode(Math.abs(data[i]), currentLen);
- currentLen = bitLength(Math.abs(data[i]));
- }
- }
-
- private static int descendingBitPackingEstimate(int[] cnt, int n, boolean sgn) {
- int sum1 = 0;
- int sum2 = 0;
- for (int i = 1; i < cnt.length; i++) {
- sum1 += cnt[i];
- sum2 += cnt[i] * (i + (sgn ? 1 : 0));
- }
- return bitLength(n) * sum1 + sum2;
- }
-
- private static int calcSeparateStorageLength(int[] cnt, int n, int D) {
- return n * (D + 1)
- + descendingBitPackingEstimate(Arrays.copyOfRange(cnt, D, cnt.length), n, false);
- }
-
- private static int[] separateStorageEstimate(int[] data) {
- int[] cnt = getCnt(data);
- int result = calcSeparateStorageLength(cnt, data.length, 0);
- int D = 0;
- for (int current_D = 1; current_D <= bitLength(MAX_VALUE); current_D++) {
- int tmp = calcSeparateStorageLength(cnt, data.length, current_D);
- if (tmp < result) {
- result = tmp;
- D = current_D;
- }
- }
- return new int[] {result, D};
- }
-
- private static void separateStorage(ByteOutToys stream, int[] data) throws IOException {
- int[] result = separateStorageEstimate(data);
- int n = data.length;
- int D = result[1];
-
- stream.encode(n, bitLength(MAX_SIZE));
- stream.encode(D, bitLength(MAX_VALUE));
-
- // low-bit part
- for (int i : data) {
- stream.encode(i < 0 ? 1 : 0, 1); // sgn bit
- stream.encode(Math.abs(i) & ((1 << D) - 1), D); // low bits
- }
-
- // high-bit part
- int[] highBits = new int[n];
- for (int i = 0; i < n; i++) {
- highBits[i] = Math.abs(data[i]) >> D;
- }
- descendingBitPacking(stream, highBits, false);
- }
-
- public static int[] getRes(int[] data, Complex[] dataf, int p, int k) {
-
- double[] irfftResult = irfft(dataf, p);
-
- // 进行四舍五入并缩放到整数
- int[] rounded = new int[irfftResult.length];
- for (int i = 0; i < irfftResult.length; i++) {
- rounded[i] = (int) Math.round(irfftResult[i] / k);
- }
-
- // 复制 k 次并截取到与原始数据相同的长度
- int[] repeated = new int[data.length];
- for (int i = 0; i < data.length; i++) {
- repeated[i] = rounded[i % rounded.length];
- }
-
- // 计算残差
- int[] res = new int[data.length];
- for (int i = 0; i < data.length; i++) {
- res[i] = repeated[i] - data[i];
- }
-
- return res;
- }
-
- private static Object[] getDatafAndRes(int[] data, Complex[] dataf, int p, int k, int beta) {
- Object[] roundResult = compRound(dataf, beta);
- Complex[] roundedDataf = (Complex[]) roundResult[0];
- int[] ret = (int[]) roundResult[1];
-
- int[] res = getRes(data, roundedDataf, p, k);
-
- return new Object[] {roundedDataf, ret, res};
- }
-
- private static void encodeWithBeta(
- ByteOutToys stream, int[] data, Complex[] dataf, int p, int k, int beta) throws IOException {
- Object[] result = getDatafAndRes(data, dataf, p, k, beta);
- Complex[] roundedDataf = (Complex[]) result[0];
- int[] ret = (int[]) result[1];
- int[] res = (int[]) result[2];
-
- descendingBitPacking(stream, ret, true);
-
- int[] diffRes = new int[res.length];
- diffRes[0] = res[0];
- for (int i = 1; i < res.length; i++) {
- diffRes[i] = res[i] - res[i - 1];
- }
-
- separateStorage(stream, diffRes);
- }
-
- private static int encodeWithBetaEstimate(int[] data, Complex[] dataf, int p, int k, int beta) {
- Object[] roundResult = compRound(dataf, beta);
- Complex[] roundedDataf = (Complex[]) roundResult[0];
- int[] ret = (int[]) roundResult[1];
-
- int maxLen = 0;
- for (int x : ret) {
- maxLen = Math.max(maxLen, bitLength(x));
- }
- if (maxLen > bitLength(MAX_VALUE)) {
- return -1;
- }
-
- int result = descendingBitPackingEstimate(getCnt(ret), ret.length, true);
-
- int[] res = getRes(data, roundedDataf, p, k);
- int[] diffRes = new int[res.length];
- diffRes[0] = res[0];
- for (int i = 1; i < res.length; i++) {
- diffRes[i] = res[i] - res[i - 1];
- }
- int[] separateResult = separateStorageEstimate(diffRes);
- result += (int) separateResult[0];
-
- return result;
- }
-
- private static int getBeta(int[] data, Complex[] dataf, int p, int k) {
- int result = encodeWithBetaEstimate(data, dataf, p, k, 0);
- int beta = 0;
- for (int currentBeta = -bitLength(MAX_VALUE) / 2;
- currentBeta <= bitLength(MAX_VALUE);
- currentBeta++) {
- if (currentBeta != 0) {
- int tmp = encodeWithBetaEstimate(data, dataf, p, k, currentBeta);
- if (result == -1 || (tmp != -1 && tmp < result)) {
- result = tmp;
- beta = currentBeta;
- }
- }
- }
- return beta;
- }
-
- private static void periodEncode(int[] data, ByteArrayOutputStream out) throws IOException {
- ByteOutToys stream = new ByteOutToys(out);
- double[] dataDouble = new double[data.length];
- for (int i = 0; i < data.length; i++) dataDouble[i] = (double) data[i];
- int p = getPeriod(dataDouble);
- if (p == 0) {
- stream.encode(p, bitLength(MAX_SIZE));
- separateStorage(stream, data);
- } else {
- int k = (data.length + p - 1) / p;
- int[] dataFull;
- if (data.length % p == 0) {
- dataFull = data;
- } else {
- dataFull = new int[p * k];
- for (int i = 0; i < data.length; i++) dataFull[i] = data[i];
- for (int i = data.length; i < p * k; i++) dataFull[i] = data[i - p];
- }
- double[] dataFullDouble = new double[dataFull.length];
- for (int i = 0; i < dataFull.length; i++) dataFullDouble[i] = (double) dataFull[i];
- Complex[] datafPre = rfft(dataFullDouble);
- Complex[] dataf = new Complex[(datafPre.length + k - 1) / k];
- for (int i = 0; i < dataf.length; i++) dataf[i] = datafPre[i * k];
- int result = encodeWithBetaEstimate(data, dataf, p, k, 0);
- int beta = getBeta(data, dataf, p, k);
- stream.encode(p, bitLength(MAX_SIZE));
- stream.encode(beta >= 0 ? 0 : 1, 1);
- stream.encode(Math.abs(beta), bitLength(bitLength(MAX_VALUE)));
- encodeWithBeta(stream, data, dataf, p, k, beta);
- }
- return;
- }
-
- List<Integer> data;
-
- public PeriodEncoder() {
- super(TSEncoding.PERIOD);
- data = new ArrayList<>();
- // this.dataType = dataType;
- // this.maxStringLength = maxStringLength;
- }
-
- // @Override
- // public void encode(boolean value, ByteArrayOutputStream out) {
- // if (value) {
- // out.write(1);
- // } else {
- // out.write(0);
- // }
- // }
-
- // @Override
- // public void encode(short value, ByteArrayOutputStream out) {
- // out.write((value >> 8) & 0xFF);
- // out.write(value & 0xFF);
- // }
-
- @Override
- public void encode(int value, ByteArrayOutputStream out) {
- data.add(value);
- // ReadWriteForEncodingUtils.writeVarInt(value, out);
- }
-
- // @Override
- // public void encode(long value, ByteArrayOutputStream out) {
- // for (int i = 7; i >= 0; i--) {
- // out.write((byte) (((value) >> (i * 8)) & 0xFF));
- // }
- // }
-
- // @Override
- // public void encode(float value, ByteArrayOutputStream out) {
- // int floatInt = Float.floatToIntBits(value);
- // out.write((floatInt >> 24) & 0xFF);
- // out.write((floatInt >> 16) & 0xFF);
- // out.write((floatInt >> 8) & 0xFF);
- // out.write(floatInt & 0xFF);
- // }
-
- // @Override
- // public void encode(double value, ByteArrayOutputStream out) {
- // encode(Double.doubleToLongBits(value), out);
- // }
-
- // @Override
- // public void encode(Binary value, ByteArrayOutputStream out) {
- // try {
- // // write the length of the bytes
- // encode(value.getLength(), out);
- // // write value
- // out.write(value.getValues());
- // } catch (IOException e) {
- // logger.error(
- // "tsfile-encoding PlainEncoder: error occurs when encode Binary value {}",
- // value, e);
- // }
- // }
-
- @Override
- public void flush(ByteArrayOutputStream out) throws IOException {
- periodEncode(data.stream().mapToInt(i -> i).toArray(), out);
- }
-
- @Override
- public int getOneItemMaxSize() {
- switch (dataType) {
- // case BOOLEAN:
- // return 1;
- case INT32:
- return 4;
- // case INT64:
- // return 8;
- // case FLOAT:
- // return 4;
- // case DOUBLE:
- // return 8;
- // case TEXT:
- // // refer to encode(Binary,ByteArrayOutputStream)
- // return 4 + TSFileConfig.BYTE_SIZE_PER_CHAR * maxStringLength;
- default:
- throw new UnsupportedOperationException(dataType.toString());
- }
- }
-
- @Override
- public long getMaxByteSize() {
- return 0;
- }
-
- // @Override
- // public void encode(BigDecimal value, ByteArrayOutputStream out) {
- // throw new TsFileEncodingException(
- // "tsfile-encoding PlainEncoder: current version does not support BigDecimal
- // value encoding");
- // }
-}
diff --git a/tsfile/src/main/java/org/apache/iotdb/tsfile/encoding/encoder/TSEncodingBuilder.java b/tsfile/src/main/java/org/apache/iotdb/tsfile/encoding/encoder/TSEncodingBuilder.java
index b4febd2..fa5c6a4 100644
--- a/tsfile/src/main/java/org/apache/iotdb/tsfile/encoding/encoder/TSEncodingBuilder.java
+++ b/tsfile/src/main/java/org/apache/iotdb/tsfile/encoding/encoder/TSEncodingBuilder.java
@@ -73,8 +73,8 @@
return new Freq();
case ZIGZAG:
return new Zigzag();
- case PERIOD:
- return new Period();
+ case FLEA:
+ return new Flea();
default:
throw new UnsupportedOperationException(type.toString());
}
@@ -403,7 +403,7 @@
}
/** for all TSDataType. */
- public static class Period extends TSEncodingBuilder {
+ public static class Flea extends TSEncodingBuilder {
// private int maxStringLength =
// TSFileDescriptor.getInstance().getConfig().getMaxStringLength();
@@ -411,9 +411,9 @@
public Encoder getEncoder(TSDataType type) {
switch (type) {
case INT32:
- return new PeriodEncoder();
+ return new FLEAEncoder();
default:
- throw new UnSupportedDataTypeException("PERIOD doesn't support data type: " + type);
+ throw new UnSupportedDataTypeException("FLEA doesn't support data type: " + type);
}
}
diff --git a/tsfile/src/main/java/org/apache/iotdb/tsfile/file/metadata/enums/TSEncoding.java b/tsfile/src/main/java/org/apache/iotdb/tsfile/file/metadata/enums/TSEncoding.java
index 4f9d29b..8658a3b 100644
--- a/tsfile/src/main/java/org/apache/iotdb/tsfile/file/metadata/enums/TSEncoding.java
+++ b/tsfile/src/main/java/org/apache/iotdb/tsfile/file/metadata/enums/TSEncoding.java
@@ -30,7 +30,7 @@
GORILLA((byte) 8),
ZIGZAG((byte) 9),
FREQ((byte) 10),
- PERIOD((byte) 14);
+ FLEA((byte) 14);
private final byte type;
@@ -73,7 +73,7 @@
case 10:
return TSEncoding.FREQ;
case 14:
- return TSEncoding.PERIOD;
+ return TSEncoding.FLEA;
default:
throw new IllegalArgumentException("Invalid input: " + encoding);
}