This is an automated email from the ASF dual-hosted git repository.

jackietien pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/tsfile.git


The following commit(s) were added to refs/heads/develop by this push:
     new e807770f Support Object type (#613)
e807770f is described below

commit e807770f379470c9e82d32bb33f35c492df285d2
Author: Haonan <[email protected]>
AuthorDate: Thu Oct 30 11:58:13 2025 +0800

    Support Object type (#613)
---
 .../java/org/apache/tsfile/enums/TSDataType.java   |  31 ++++-
 .../org/apache/tsfile/utils/TsPrimitiveType.java   |   2 +
 .../apache/tsfile/common/conf/TSFileConfig.java    |   2 +
 .../tsfile/encoding/encoder/PlainEncoder.java      |   1 +
 .../tsfile/file/metadata/TimeseriesMetadata.java   |  30 +++--
 .../tsfile/file/metadata/enums/TSEncoding.java     |   2 +
 .../file/metadata/statistics/ObjectStatistics.java | 126 +++++++++++++++++++++
 .../file/metadata/statistics/Statistics.java       |   4 +
 .../apache/tsfile/read/TsFileSequenceReader.java   |  61 ++++++----
 .../org/apache/tsfile/read/common/BatchData.java   |   6 +
 .../java/org/apache/tsfile/read/common/Chunk.java  |   2 +
 .../tsfile/read/common/DescReadWriteBatchData.java |   3 +
 .../java/org/apache/tsfile/read/common/Field.java  |   8 ++
 .../apache/tsfile/read/common/block/TsBlock.java   |   1 +
 .../tsfile/read/common/block/TsBlockBuilder.java   |   2 +
 .../read/common/block/column/ColumnFactory.java    |   1 +
 .../read/common/block/column/NullColumn.java       |   1 +
 .../apache/tsfile/read/common/type/ObjectType.java |  79 +++++++++++++
 .../apache/tsfile/read/common/type/TypeEnum.java   |   3 +-
 .../tsfile/read/common/type/TypeFactory.java       |   2 +
 .../query/dataset/DataSetWithoutTimeGenerator.java |   1 +
 .../tsfile/read/reader/TsFileLastReader.java       |  16 +--
 .../apache/tsfile/read/reader/page/PageReader.java |   2 +
 .../tsfile/read/reader/page/ValuePageReader.java   |   6 +
 .../java/org/apache/tsfile/utils/BytesUtils.java   |  21 ++++
 .../write/chunk/AlignedChunkGroupWriterImpl.java   |   3 +
 .../tsfile/write/chunk/AlignedChunkWriterImpl.java |   2 +
 .../chunk/NonAlignedChunkGroupWriterImpl.java      |   1 +
 .../org/apache/tsfile/write/record/Tablet.java     |  15 +++
 .../tsfile/write/record/datapoint/DataPoint.java   |   1 +
 .../write/v4/AbstractTableModelTsFileWriter.java   |  23 +++-
 .../tsfile/write/v4/DeviceTableModelWriter.java    |   7 ++
 .../file/metadata/statistics/StatisticsTest.java   |   5 +
 .../java/org/apache/tsfile/utils/TypeCastTest.java |   4 +
 34 files changed, 428 insertions(+), 46 deletions(-)

diff --git a/java/common/src/main/java/org/apache/tsfile/enums/TSDataType.java 
b/java/common/src/main/java/org/apache/tsfile/enums/TSDataType.java
index 492d1bab..4fb01f86 100644
--- a/java/common/src/main/java/org/apache/tsfile/enums/TSDataType.java
+++ b/java/common/src/main/java/org/apache/tsfile/enums/TSDataType.java
@@ -71,7 +71,10 @@ public enum TSDataType {
   BLOB((byte) 10),
 
   /** STRING */
-  STRING((byte) 11);
+  STRING((byte) 11),
+
+  /** OBJECT */
+  OBJECT((byte) 12);
 
   private final byte type;
   private static final Map<TSDataType, Set<TSDataType>> compatibleTypes;
@@ -139,6 +142,8 @@ public enum TSDataType {
     stringCompatibleTypes.add(DATE);
     stringCompatibleTypes.add(TIMESTAMP);
     compatibleTypes.put(STRING, stringCompatibleTypes);
+
+    compatibleTypes.put(OBJECT, Collections.emptySet());
   }
 
   TSDataType(byte type) {
@@ -185,6 +190,8 @@ public enum TSDataType {
         return TSDataType.BLOB;
       case 11:
         return TSDataType.STRING;
+      case 12:
+        return TSDataType.OBJECT;
       default:
         throw new IllegalArgumentException("Invalid input: " + type);
     }
@@ -306,6 +313,12 @@ public enum TSDataType {
         } else {
           break;
         }
+      case OBJECT:
+        if (sourceType == TSDataType.OBJECT) {
+          return value;
+        } else {
+          break;
+        }
       case VECTOR:
       case UNKNOWN:
       default:
@@ -447,6 +460,12 @@ public enum TSDataType {
         } else {
           break;
         }
+      case OBJECT:
+        if (sourceType == TSDataType.OBJECT) {
+          return array;
+        } else {
+          break;
+        }
       case VECTOR:
       case UNKNOWN:
       default:
@@ -494,6 +513,7 @@ public enum TSDataType {
       case DOUBLE:
       case VECTOR:
       case BLOB:
+      case OBJECT:
       case STRING:
       case TIMESTAMP:
         return 8;
@@ -532,6 +552,7 @@ public enum TSDataType {
       case BOOLEAN:
       case TEXT:
       case VECTOR:
+      case OBJECT:
         return false;
       default:
         throw new UnSupportedDataTypeException(this.toString());
@@ -558,6 +579,7 @@ public enum TSDataType {
         return true;
       case VECTOR:
       case BLOB:
+      case OBJECT:
         return false;
       default:
         throw new UnSupportedDataTypeException(this.toString());
@@ -565,7 +587,12 @@ public enum TSDataType {
   }
 
   public boolean isBinary() {
-    return this == TEXT || this == STRING || this == BLOB;
+    return this == TEXT || this == STRING || this == BLOB || this == OBJECT;
+  }
+
+  // Indicating the statistics don't contain values, such as first, last, min, 
max...
+  public boolean hasNoValueInStatistics() {
+    return this == BLOB || this == OBJECT;
   }
 
   public static String getDateStringValue(int value) {
diff --git 
a/java/common/src/main/java/org/apache/tsfile/utils/TsPrimitiveType.java 
b/java/common/src/main/java/org/apache/tsfile/utils/TsPrimitiveType.java
index c3356fc5..4850d1ad 100644
--- a/java/common/src/main/java/org/apache/tsfile/utils/TsPrimitiveType.java
+++ b/java/common/src/main/java/org/apache/tsfile/utils/TsPrimitiveType.java
@@ -48,6 +48,7 @@ public abstract class TsPrimitiveType implements Serializable 
{
       case TEXT:
       case BLOB:
       case STRING:
+      case OBJECT:
         return new TsPrimitiveType.TsBinary();
       case VECTOR:
         return new TsPrimitiveType.TsVector();
@@ -79,6 +80,7 @@ public abstract class TsPrimitiveType implements Serializable 
{
       case TEXT:
       case BLOB:
       case STRING:
+      case OBJECT:
         return new TsPrimitiveType.TsBinary((Binary) v);
       case VECTOR:
         return new TsPrimitiveType.TsVector((TsPrimitiveType[]) v);
diff --git 
a/java/tsfile/src/main/java/org/apache/tsfile/common/conf/TSFileConfig.java 
b/java/tsfile/src/main/java/org/apache/tsfile/common/conf/TSFileConfig.java
index eb49b718..201e6f9e 100644
--- a/java/tsfile/src/main/java/org/apache/tsfile/common/conf/TSFileConfig.java
+++ b/java/tsfile/src/main/java/org/apache/tsfile/common/conf/TSFileConfig.java
@@ -385,6 +385,7 @@ public class TSFileConfig implements Serializable {
       case STRING:
       case BLOB:
       case TEXT:
+      case OBJECT:
       default:
         return textEncoding;
     }
@@ -413,6 +414,7 @@ public class TSFileConfig implements Serializable {
       case STRING:
       case BLOB:
       case TEXT:
+      case OBJECT:
         compressionName = textCompression;
         break;
       default:
diff --git 
a/java/tsfile/src/main/java/org/apache/tsfile/encoding/encoder/PlainEncoder.java
 
b/java/tsfile/src/main/java/org/apache/tsfile/encoding/encoder/PlainEncoder.java
index 09c28cbe..0b97005d 100644
--- 
a/java/tsfile/src/main/java/org/apache/tsfile/encoding/encoder/PlainEncoder.java
+++ 
b/java/tsfile/src/main/java/org/apache/tsfile/encoding/encoder/PlainEncoder.java
@@ -128,6 +128,7 @@ public class PlainEncoder extends Encoder {
       case TEXT:
       case STRING:
       case BLOB:
+      case OBJECT:
         // refer to encode(Binary,ByteArrayOutputStream)
         return 4 + TSFileConfig.BYTE_SIZE_PER_CHAR * maxStringLength;
       default:
diff --git 
a/java/tsfile/src/main/java/org/apache/tsfile/file/metadata/TimeseriesMetadata.java
 
b/java/tsfile/src/main/java/org/apache/tsfile/file/metadata/TimeseriesMetadata.java
index 25b1a127..544489ed 100644
--- 
a/java/tsfile/src/main/java/org/apache/tsfile/file/metadata/TimeseriesMetadata.java
+++ 
b/java/tsfile/src/main/java/org/apache/tsfile/file/metadata/TimeseriesMetadata.java
@@ -125,7 +125,9 @@ public class TimeseriesMetadata implements 
ITimeSeriesMetadata {
   }
 
   public static TimeseriesMetadata deserializeFrom(
-      ByteBuffer buffer, boolean needChunkMetadataForNonBlob, boolean 
needChunkMetadataForBlob) {
+      ByteBuffer buffer,
+      boolean needChunkMetadataForDataTypeWithValuesInStatistics,
+      boolean needChunkMetadataForDataTypeWithoutValuesInStatistics) {
     TimeseriesMetadata timeseriesMetaData = new TimeseriesMetadata();
     
timeseriesMetaData.setTimeSeriesMetadataType(ReadWriteIOUtils.readByte(buffer));
     
timeseriesMetaData.setMeasurementId(ReadWriteIOUtils.readVarIntString(buffer));
@@ -133,8 +135,10 @@ public class TimeseriesMetadata implements 
ITimeSeriesMetadata {
     int chunkMetaDataListDataSize = 
ReadWriteForEncodingUtils.readUnsignedVarInt(buffer);
     
timeseriesMetaData.setDataSizeOfChunkMetaDataList(chunkMetaDataListDataSize);
     timeseriesMetaData.setStatistics(Statistics.deserialize(buffer, 
timeseriesMetaData.dataType));
-    if ((timeseriesMetaData.getTsDataType() != TSDataType.BLOB && 
needChunkMetadataForNonBlob)
-        || (timeseriesMetaData.getTsDataType() == TSDataType.BLOB && 
needChunkMetadataForBlob)) {
+    if ((!timeseriesMetaData.getTsDataType().hasNoValueInStatistics()
+            && needChunkMetadataForDataTypeWithValuesInStatistics)
+        || (timeseriesMetaData.getTsDataType().hasNoValueInStatistics()
+            && needChunkMetadataForDataTypeWithoutValuesInStatistics)) {
       ByteBuffer byteBuffer = buffer.slice();
       byteBuffer.limit(chunkMetaDataListDataSize);
       timeseriesMetaData.chunkMetadataList = new ArrayList<>();
@@ -156,8 +160,8 @@ public class TimeseriesMetadata implements 
ITimeSeriesMetadata {
 
   public static TimeseriesMetadata deserializeFrom(
       TsFileInput tsFileInput,
-      boolean needChunkMetadataForNonBlob,
-      boolean needChunkMetadataForBlob)
+      boolean needChunkMetadataForDataTypeWithValuesInStatistics,
+      boolean needChunkMetadataForDataTypeWithoutValuesInStatistics)
       throws IOException {
     InputStream inputStream = tsFileInput.wrapAsInputStream();
     TimeseriesMetadata timeseriesMetaData = new TimeseriesMetadata();
@@ -169,8 +173,10 @@ public class TimeseriesMetadata implements 
ITimeSeriesMetadata {
     timeseriesMetaData.setStatistics(
         Statistics.deserialize(inputStream, timeseriesMetaData.dataType));
     long startOffset = tsFileInput.position();
-    if ((timeseriesMetaData.getTsDataType() != TSDataType.BLOB && 
needChunkMetadataForNonBlob)
-        || (timeseriesMetaData.getTsDataType() == TSDataType.BLOB && 
needChunkMetadataForBlob)) {
+    if ((!timeseriesMetaData.getTsDataType().hasNoValueInStatistics()
+            && needChunkMetadataForDataTypeWithValuesInStatistics)
+        || (timeseriesMetaData.getTsDataType().hasNoValueInStatistics()
+            && needChunkMetadataForDataTypeWithoutValuesInStatistics)) {
       timeseriesMetaData.chunkMetadataList = new ArrayList<>();
       while (tsFileInput.position() < startOffset + chunkMetaDataListDataSize) 
{
         timeseriesMetaData.chunkMetadataList.add(
@@ -196,8 +202,8 @@ public class TimeseriesMetadata implements 
ITimeSeriesMetadata {
   public static TimeseriesMetadata deserializeFrom(
       ByteBuffer buffer,
       Set<String> excludedMeasurements,
-      boolean needChunkMetadataForNonBlob,
-      boolean needChunkMetadataForBlob) {
+      boolean needChunkMetadataForDataTypeWithValuesInStatistics,
+      boolean needChunkMetadataForDataTypeWithoutValuesInStatistics) {
     byte timeseriesType = ReadWriteIOUtils.readByte(buffer);
     String measurementID = ReadWriteIOUtils.readVarIntString(buffer);
     TSDataType tsDataType = ReadWriteIOUtils.readDataType(buffer);
@@ -212,8 +218,10 @@ public class TimeseriesMetadata implements 
ITimeSeriesMetadata {
     timeseriesMetaData.setStatistics(statistics);
 
     if (!excludedMeasurements.contains(measurementID)
-        && ((tsDataType != TSDataType.BLOB && needChunkMetadataForNonBlob)
-            || (tsDataType == TSDataType.BLOB && needChunkMetadataForBlob))) {
+        && ((!tsDataType.hasNoValueInStatistics()
+                && needChunkMetadataForDataTypeWithValuesInStatistics)
+            || (tsDataType.hasNoValueInStatistics()
+                && needChunkMetadataForDataTypeWithoutValuesInStatistics))) {
       // measurement is not in the excluded set and need chunk metadata
       ByteBuffer byteBuffer = buffer.slice();
       byteBuffer.limit(chunkMetaDataListDataSize);
diff --git 
a/java/tsfile/src/main/java/org/apache/tsfile/file/metadata/enums/TSEncoding.java
 
b/java/tsfile/src/main/java/org/apache/tsfile/file/metadata/enums/TSEncoding.java
index 6c02cb1f..f85c0d5e 100644
--- 
a/java/tsfile/src/main/java/org/apache/tsfile/file/metadata/enums/TSEncoding.java
+++ 
b/java/tsfile/src/main/java/org/apache/tsfile/file/metadata/enums/TSEncoding.java
@@ -96,6 +96,8 @@ public enum TSEncoding {
     Set<TSEncoding> blobSet = new HashSet<>();
     blobSet.add(TSEncoding.PLAIN);
     TYPE_SUPPORTED_ENCODINGS.put(TSDataType.BLOB, blobSet);
+
+    TYPE_SUPPORTED_ENCODINGS.put(TSDataType.OBJECT, blobSet);
   }
 
   TSEncoding(byte type) {
diff --git 
a/java/tsfile/src/main/java/org/apache/tsfile/file/metadata/statistics/ObjectStatistics.java
 
b/java/tsfile/src/main/java/org/apache/tsfile/file/metadata/statistics/ObjectStatistics.java
new file mode 100644
index 00000000..f054a267
--- /dev/null
+++ 
b/java/tsfile/src/main/java/org/apache/tsfile/file/metadata/statistics/ObjectStatistics.java
@@ -0,0 +1,126 @@
+/*
+ * 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.tsfile.file.metadata.statistics;
+
+import org.apache.tsfile.enums.TSDataType;
+import org.apache.tsfile.exception.filter.StatisticsClassException;
+import org.apache.tsfile.utils.Binary;
+import org.apache.tsfile.utils.RamUsageEstimator;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+
+public class ObjectStatistics extends Statistics<Binary> {
+
+  public static final long INSTANCE_SIZE =
+      RamUsageEstimator.shallowSizeOfInstance(ObjectStatistics.class);
+
+  // no statistics for object data type
+
+  @Override
+  public TSDataType getType() {
+    return TSDataType.OBJECT;
+  }
+
+  /** The output of this method should be identical to the method 
"serializeStats(outputStream)". */
+  @Override
+  public int getStatsSize() {
+    return 0;
+  }
+
+  @Override
+  public long getRetainedSizeInBytes() {
+    return INSTANCE_SIZE;
+  }
+
+  @Override
+  int serializeStats(OutputStream outputStream) throws IOException {
+    return 0;
+  }
+
+  public void updateStats(Binary value) {
+    if (isEmpty) {
+      isEmpty = false;
+    }
+  }
+
+  @Override
+  public void deserialize(InputStream inputStream) throws IOException {
+    // do nothing
+  }
+
+  @Override
+  public void deserialize(ByteBuffer byteBuffer) {
+    // do nothing
+  }
+
+  @Override
+  public Binary getMinValue() {
+    throw new StatisticsClassException(
+        String.format(STATS_UNSUPPORTED_MSG, TSDataType.OBJECT, "min"));
+  }
+
+  @Override
+  public Binary getMaxValue() {
+    throw new StatisticsClassException(
+        String.format(STATS_UNSUPPORTED_MSG, TSDataType.OBJECT, "max"));
+  }
+
+  @Override
+  public Binary getFirstValue() {
+    throw new StatisticsClassException(
+        String.format(STATS_UNSUPPORTED_MSG, TSDataType.OBJECT, "first"));
+  }
+
+  @Override
+  public Binary getLastValue() {
+    throw new StatisticsClassException(
+        String.format(STATS_UNSUPPORTED_MSG, TSDataType.OBJECT, "last"));
+  }
+
+  @Override
+  public double getSumDoubleValue() {
+    throw new StatisticsClassException(
+        String.format(STATS_UNSUPPORTED_MSG, TSDataType.OBJECT, "sum"));
+  }
+
+  @Override
+  public long getSumLongValue() {
+
+    throw new StatisticsClassException(
+        String.format(STATS_UNSUPPORTED_MSG, TSDataType.OBJECT, "sum"));
+  }
+
+  @SuppressWarnings("rawtypes")
+  @Override
+  protected void mergeStatisticsValue(Statistics stats) {
+    // do nothing
+    if (isEmpty) {
+      isEmpty = false;
+    }
+  }
+
+  @Override
+  public String toString() {
+    return "ObjectStatistics{}";
+  }
+}
diff --git 
a/java/tsfile/src/main/java/org/apache/tsfile/file/metadata/statistics/Statistics.java
 
b/java/tsfile/src/main/java/org/apache/tsfile/file/metadata/statistics/Statistics.java
index b1c2c463..0378a509 100644
--- 
a/java/tsfile/src/main/java/org/apache/tsfile/file/metadata/statistics/Statistics.java
+++ 
b/java/tsfile/src/main/java/org/apache/tsfile/file/metadata/statistics/Statistics.java
@@ -126,6 +126,8 @@ public abstract class Statistics<T extends Serializable> {
         return new StringStatistics();
       case BLOB:
         return new BlobStatistics();
+      case OBJECT:
+        return new ObjectStatistics();
       default:
         throw new UnknownColumnTypeException(type.toString());
     }
@@ -155,6 +157,8 @@ public abstract class Statistics<T extends Serializable> {
         return StringStatistics.INSTANCE_SIZE;
       case BLOB:
         return BlobStatistics.INSTANCE_SIZE;
+      case OBJECT:
+        return ObjectStatistics.INSTANCE_SIZE;
       default:
         throw new UnknownColumnTypeException(type.toString());
     }
diff --git 
a/java/tsfile/src/main/java/org/apache/tsfile/read/TsFileSequenceReader.java 
b/java/tsfile/src/main/java/org/apache/tsfile/read/TsFileSequenceReader.java
index 7a572b9f..bc742dff 100644
--- a/java/tsfile/src/main/java/org/apache/tsfile/read/TsFileSequenceReader.java
+++ b/java/tsfile/src/main/java/org/apache/tsfile/read/TsFileSequenceReader.java
@@ -1455,8 +1455,8 @@ public class TsFileSequenceReader implements 
AutoCloseable {
       IDeviceID deviceId,
       MetadataIndexNodeType type,
       Map<IDeviceID, List<TimeseriesMetadata>> timeseriesMetadataMap,
-      boolean needChunkMetadataForNonBlob,
-      boolean needChunkMetadataForBlob)
+      boolean needChunkMetadataForDataTypeWithValuesInStatistics,
+      boolean needChunkMetadataForDataTypeWithoutValuesInStatistics)
       throws IOException {
     try {
       if (type.equals(MetadataIndexNodeType.LEAF_MEASUREMENT)) {
@@ -1464,7 +1464,9 @@ public class TsFileSequenceReader implements 
AutoCloseable {
         while (buffer.hasRemaining()) {
           timeseriesMetadataList.add(
               TimeseriesMetadata.deserializeFrom(
-                  buffer, needChunkMetadataForNonBlob, 
needChunkMetadataForBlob));
+                  buffer,
+                  needChunkMetadataForDataTypeWithValuesInStatistics,
+                  needChunkMetadataForDataTypeWithoutValuesInStatistics));
         }
         timeseriesMetadataMap
             .computeIfAbsent(deviceId, k -> new ArrayList<>())
@@ -1493,8 +1495,8 @@ public class TsFileSequenceReader implements 
AutoCloseable {
                 deviceId,
                 metadataIndexNode.getNodeType(),
                 timeseriesMetadataMap,
-                needChunkMetadataForNonBlob,
-                needChunkMetadataForBlob);
+                needChunkMetadataForDataTypeWithValuesInStatistics,
+                needChunkMetadataForDataTypeWithoutValuesInStatistics);
           } else {
             // when the buffer length is over than Integer.MAX_VALUE,
             // using tsFileInput to get timeseriesMetadataList
@@ -1505,8 +1507,8 @@ public class TsFileSequenceReader implements 
AutoCloseable {
                 deviceId,
                 metadataIndexNode.getNodeType(),
                 timeseriesMetadataMap,
-                needChunkMetadataForNonBlob,
-                needChunkMetadataForBlob);
+                needChunkMetadataForDataTypeWithValuesInStatistics,
+                needChunkMetadataForDataTypeWithoutValuesInStatistics);
           }
         }
       }
@@ -1545,8 +1547,8 @@ public class TsFileSequenceReader implements 
AutoCloseable {
       IDeviceID deviceId,
       MetadataIndexNodeType type,
       Map<IDeviceID, List<TimeseriesMetadata>> timeseriesMetadataMap,
-      boolean needChunkMetadataForNonBlob,
-      boolean needChunkMetadataForBlob)
+      boolean needChunkMetadataForDataTypeWithValuesInStatistics,
+      boolean needChunkMetadataForDataTypeWithoutValuesInStatistics)
       throws IOException {
     try {
       tsFileInput.position(start);
@@ -1555,7 +1557,9 @@ public class TsFileSequenceReader implements 
AutoCloseable {
         while (tsFileInput.position() < end) {
           timeseriesMetadataList.add(
               TimeseriesMetadata.deserializeFrom(
-                  tsFileInput, needChunkMetadataForNonBlob, 
needChunkMetadataForBlob));
+                  tsFileInput,
+                  needChunkMetadataForDataTypeWithValuesInStatistics,
+                  needChunkMetadataForDataTypeWithoutValuesInStatistics));
         }
         timeseriesMetadataMap
             .computeIfAbsent(deviceId, k -> new ArrayList<>())
@@ -1582,8 +1586,8 @@ public class TsFileSequenceReader implements 
AutoCloseable {
               deviceId,
               metadataIndexNode.getNodeType(),
               timeseriesMetadataMap,
-              needChunkMetadataForNonBlob,
-              needChunkMetadataForBlob);
+              needChunkMetadataForDataTypeWithValuesInStatistics,
+              needChunkMetadataForDataTypeWithoutValuesInStatistics);
         }
       }
     } catch (StopReadTsFileByInterruptException e) {
@@ -1636,8 +1640,12 @@ public class TsFileSequenceReader implements 
AutoCloseable {
   }
 
   public Iterator<Pair<IDeviceID, List<TimeseriesMetadata>>> 
iterAllTimeseriesMetadata(
-      boolean needChunkMetadataForNonBlob, boolean needChunkMetadataForBlob) 
throws IOException {
-    return new TimeseriesMetadataIterator(needChunkMetadataForNonBlob, 
needChunkMetadataForBlob);
+      boolean needChunkMetadataForDataTypeWithoutValuesInStatistics,
+      boolean needChunkMetadataForDataTypeWithValuesInStatistics)
+      throws IOException {
+    return new TimeseriesMetadataIterator(
+        needChunkMetadataForDataTypeWithoutValuesInStatistics,
+        needChunkMetadataForDataTypeWithValuesInStatistics);
   }
 
   /* This method will only deserialize the TimeseriesMetadata, not including 
chunk metadata list */
@@ -2371,6 +2379,7 @@ public class TsFileSequenceReader implements 
AutoCloseable {
                         case TEXT:
                         case BLOB:
                         case STRING:
+                        case OBJECT:
                           chunkStatistics.update(timeStamp, value.getBinary());
                           break;
                         default:
@@ -2410,6 +2419,7 @@ public class TsFileSequenceReader implements 
AutoCloseable {
                       case TEXT:
                       case BLOB:
                       case STRING:
+                      case OBJECT:
                         chunkStatistics.update(batchData.currentTime(), 
batchData.getBinary());
                         break;
                       default:
@@ -2640,6 +2650,7 @@ public class TsFileSequenceReader implements 
AutoCloseable {
           case TEXT:
           case BLOB:
           case STRING:
+          case OBJECT:
             chunkStatistics.update(batchData.currentTime(), 
batchData.getBinary());
             break;
           default:
@@ -3140,16 +3151,20 @@ public class TsFileSequenceReader implements 
AutoCloseable {
       implements Iterator<Pair<IDeviceID, List<TimeseriesMetadata>>> {
 
     private final Deque<MetadataIndexNode> nodeStack = new ArrayDeque<>();
-    private final boolean needChunkMetadataForNonBlob;
-    private final boolean needCHunkMetadataForBlob;
+    private final boolean needChunkMetadataForDataTypeWithValuesInStatistics;
+    private final boolean 
needChunkMetadataForDataTypeWithoutValuesInStatistics;
     private Pair<IDeviceID, List<TimeseriesMetadata>> nextValue;
     private MetadataIndexNode currentLeafDeviceNode;
     private int currentLeafDeviceNodeIndex;
 
     public TimeseriesMetadataIterator(
-        boolean needChunkMetadataForNonBlob, boolean needChunkMetadataForBlob) 
throws IOException {
-      this.needChunkMetadataForNonBlob = needChunkMetadataForNonBlob;
-      this.needCHunkMetadataForBlob = needChunkMetadataForBlob;
+        boolean needChunkMetadataForDataTypeWithValuesInStatistics,
+        boolean needChunkMetadataForDataTypeWithoutValuesInStatistics)
+        throws IOException {
+      this.needChunkMetadataForDataTypeWithValuesInStatistics =
+          needChunkMetadataForDataTypeWithValuesInStatistics;
+      this.needChunkMetadataForDataTypeWithoutValuesInStatistics =
+          needChunkMetadataForDataTypeWithoutValuesInStatistics;
       if (tsFileMetaData == null) {
         readFileMetadata();
       }
@@ -3245,8 +3260,8 @@ public class TsFileSequenceReader implements 
AutoCloseable {
             deviceId,
             currentLeafDeviceNode.getNodeType(),
             nextValueMap,
-            needChunkMetadataForNonBlob,
-            needCHunkMetadataForBlob);
+            needChunkMetadataForDataTypeWithValuesInStatistics,
+            needChunkMetadataForDataTypeWithoutValuesInStatistics);
       } else {
         // when the buffer length is over than Integer.MAX_VALUE,
         // using tsFileInput to get timeseriesMetadataList
@@ -3257,8 +3272,8 @@ public class TsFileSequenceReader implements 
AutoCloseable {
             deviceId,
             currentLeafDeviceNode.getNodeType(),
             nextValueMap,
-            needChunkMetadataForNonBlob,
-            needCHunkMetadataForBlob);
+            needChunkMetadataForDataTypeWithValuesInStatistics,
+            needChunkMetadataForDataTypeWithoutValuesInStatistics);
       }
       currentLeafDeviceNodeIndex++;
       Entry<IDeviceID, List<TimeseriesMetadata>> entry = 
nextValueMap.entrySet().iterator().next();
diff --git 
a/java/tsfile/src/main/java/org/apache/tsfile/read/common/BatchData.java 
b/java/tsfile/src/main/java/org/apache/tsfile/read/common/BatchData.java
index 504f7a9c..1a7e080b 100644
--- a/java/tsfile/src/main/java/org/apache/tsfile/read/common/BatchData.java
+++ b/java/tsfile/src/main/java/org/apache/tsfile/read/common/BatchData.java
@@ -144,6 +144,7 @@ public class BatchData {
       case TEXT:
       case BLOB:
       case STRING:
+      case OBJECT:
         return getBinary();
       case VECTOR:
         return getVector();
@@ -169,6 +170,7 @@ public class BatchData {
       case TEXT:
       case BLOB:
       case STRING:
+      case OBJECT:
         return new TsBinary(getBinary());
       case VECTOR:
         return new TsVector(getVector());
@@ -231,6 +233,7 @@ public class BatchData {
       case TEXT:
       case BLOB:
       case STRING:
+      case OBJECT:
         binaryRet = new ArrayList<>();
         binaryRet.add(new Binary[capacity]);
         break;
@@ -575,6 +578,7 @@ public class BatchData {
       case TEXT:
       case BLOB:
       case STRING:
+      case OBJECT:
         putBinary(t, (Binary) v);
         break;
       case VECTOR:
@@ -699,6 +703,7 @@ public class BatchData {
       case TEXT:
       case BLOB:
       case STRING:
+      case OBJECT:
         for (int i = 0; i < length(); i++) {
           outputStream.writeLong(getTimeByIndex(i));
           Binary binary = getBinaryByIndex(i);
@@ -744,6 +749,7 @@ public class BatchData {
                 case TEXT:
                 case BLOB:
                 case STRING:
+                case OBJECT:
                   Binary binary = value.getBinary();
                   outputStream.writeInt(binary.getLength());
                   outputStream.write(binary.getValues());
diff --git a/java/tsfile/src/main/java/org/apache/tsfile/read/common/Chunk.java 
b/java/tsfile/src/main/java/org/apache/tsfile/read/common/Chunk.java
index a7e2e9ea..c560050d 100644
--- a/java/tsfile/src/main/java/org/apache/tsfile/read/common/Chunk.java
+++ b/java/tsfile/src/main/java/org/apache/tsfile/read/common/Chunk.java
@@ -284,6 +284,7 @@ public class Chunk {
           case TEXT:
           case STRING:
           case BLOB:
+          case OBJECT:
             chunkWriter.write(
                 timestamp,
                 convertedValue == null ? Binary.EMPTY_VALUE : (Binary) 
convertedValue,
@@ -358,6 +359,7 @@ public class Chunk {
           case TEXT:
           case STRING:
           case BLOB:
+          case OBJECT:
             chunkWriter.write(timestamp, (Binary) convertedValue);
             break;
           default:
diff --git 
a/java/tsfile/src/main/java/org/apache/tsfile/read/common/DescReadWriteBatchData.java
 
b/java/tsfile/src/main/java/org/apache/tsfile/read/common/DescReadWriteBatchData.java
index 1fd65740..b667c537 100644
--- 
a/java/tsfile/src/main/java/org/apache/tsfile/read/common/DescReadWriteBatchData.java
+++ 
b/java/tsfile/src/main/java/org/apache/tsfile/read/common/DescReadWriteBatchData.java
@@ -75,6 +75,7 @@ public class DescReadWriteBatchData extends DescReadBatchData 
{
       case TEXT:
       case BLOB:
       case STRING:
+      case OBJECT:
         binaryRet = new LinkedList<>();
         binaryRet.add(new Binary[capacity]);
         break;
@@ -440,6 +441,7 @@ public class DescReadWriteBatchData extends 
DescReadBatchData {
       case TEXT:
       case BLOB:
       case STRING:
+      case OBJECT:
         for (int i = length() - 1; i >= 0; i--) {
           outputStream.writeLong(getTimeByIndex(i));
           Binary binary = getBinaryByIndex(i);
@@ -485,6 +487,7 @@ public class DescReadWriteBatchData extends 
DescReadBatchData {
                 case TEXT:
                 case BLOB:
                 case STRING:
+                case OBJECT:
                   Binary binary = value.getBinary();
                   outputStream.writeInt(binary.getLength());
                   outputStream.write(binary.getValues());
diff --git a/java/tsfile/src/main/java/org/apache/tsfile/read/common/Field.java 
b/java/tsfile/src/main/java/org/apache/tsfile/read/common/Field.java
index 01d4dcdb..a8de28a7 100644
--- a/java/tsfile/src/main/java/org/apache/tsfile/read/common/Field.java
+++ b/java/tsfile/src/main/java/org/apache/tsfile/read/common/Field.java
@@ -29,6 +29,8 @@ import org.apache.tsfile.write.UnSupportedDataTypeException;
 
 import java.time.LocalDate;
 
+import static org.apache.tsfile.utils.BytesUtils.parseObjectByteArrayToString;
+
 /**
  * Field is component of one {@code RowRecord} which stores a value in 
specific data type. The value
  * type of Field is primitive(int long, float, double, binary, boolean).
@@ -71,6 +73,7 @@ public class Field {
         case TEXT:
         case BLOB:
         case STRING:
+        case OBJECT:
           out.setBinaryV(field.getBinaryV());
           break;
         default:
@@ -183,6 +186,8 @@ public class Field {
       case TEXT:
       case STRING:
         return binaryV.toString();
+      case OBJECT:
+        return parseObjectByteArrayToString(binaryV.getValues());
       case BLOB:
         return BytesUtils.parseBlobByteArrayToString(binaryV.getValues());
       default:
@@ -216,6 +221,7 @@ public class Field {
       case TEXT:
       case BLOB:
       case STRING:
+      case OBJECT:
         return getBinaryV();
       default:
         throw new UnSupportedDataTypeException(dataType.toString());
@@ -248,6 +254,7 @@ public class Field {
       case TEXT:
       case BLOB:
       case STRING:
+      case OBJECT:
         field.setBinaryV((Binary) value);
         break;
       default:
@@ -278,6 +285,7 @@ public class Field {
       case TEXT:
       case BLOB:
       case STRING:
+      case OBJECT:
         field.setBinaryV(value.getBinary());
         break;
       default:
diff --git 
a/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/TsBlock.java 
b/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/TsBlock.java
index b5224580..7e31d5d4 100644
--- a/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/TsBlock.java
+++ b/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/TsBlock.java
@@ -592,6 +592,7 @@ public class TsBlock {
         case TEXT:
         case BLOB:
         case STRING:
+        case OBJECT:
           valueColumns[i].isNull()[updateIdx] = false;
           valueColumns[i].getBinaries()[updateIdx] =
               sourceTsBlock.getValueColumns()[i].getBinary(sourceIndex);
diff --git 
a/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/TsBlockBuilder.java
 
b/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/TsBlockBuilder.java
index 0e96fca5..e06f8c37 100644
--- 
a/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/TsBlockBuilder.java
+++ 
b/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/TsBlockBuilder.java
@@ -135,6 +135,7 @@ public class TsBlockBuilder {
         case TEXT:
         case BLOB:
         case STRING:
+        case OBJECT:
           valueColumnBuilders[i] =
               new BinaryColumnBuilder(
                   tsBlockBuilderStatus.createColumnBuilderStatus(), 
initialExpectedEntries);
@@ -205,6 +206,7 @@ public class TsBlockBuilder {
         case TEXT:
         case BLOB:
         case STRING:
+        case OBJECT:
           valueColumnBuilders[i] =
               new BinaryColumnBuilder(
                   tsBlockBuilderStatus.createColumnBuilderStatus(), 
initialExpectedEntries);
diff --git 
a/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/column/ColumnFactory.java
 
b/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/column/ColumnFactory.java
index 88a40113..fc9774a1 100644
--- 
a/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/column/ColumnFactory.java
+++ 
b/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/column/ColumnFactory.java
@@ -35,6 +35,7 @@ public class ColumnFactory {
       case TEXT:
       case STRING:
       case BLOB:
+      case OBJECT:
         return new BinaryColumn(initialCapacity);
       case INT32:
       case DATE:
diff --git 
a/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/column/NullColumn.java
 
b/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/column/NullColumn.java
index d91359ca..30031822 100644
--- 
a/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/column/NullColumn.java
+++ 
b/java/tsfile/src/main/java/org/apache/tsfile/read/common/block/column/NullColumn.java
@@ -154,6 +154,7 @@ public class NullColumn implements Column {
       case TEXT:
       case BLOB:
       case STRING:
+      case OBJECT:
         return new 
RunLengthEncodedColumn(BinaryColumnBuilder.NULL_VALUE_BLOCK, positionCount);
       default:
         throw new IllegalArgumentException("Unknown data type: " + dataType);
diff --git 
a/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/ObjectType.java 
b/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/ObjectType.java
new file mode 100644
index 00000000..b30b621f
--- /dev/null
+++ 
b/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/ObjectType.java
@@ -0,0 +1,79 @@
+/*
+ * 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.tsfile.read.common.type;
+
+import org.apache.tsfile.block.column.Column;
+import org.apache.tsfile.block.column.ColumnBuilder;
+import org.apache.tsfile.read.common.block.column.BinaryColumnBuilder;
+import org.apache.tsfile.utils.Binary;
+
+import java.util.Collections;
+import java.util.List;
+
+public class ObjectType extends AbstractType {
+
+  public static final ObjectType OBJECT = new ObjectType();
+
+  private ObjectType() {}
+
+  @Override
+  public Binary getBinary(Column c, int position) {
+    return c.getBinary(position);
+  }
+
+  @Override
+  public void writeBinary(ColumnBuilder builder, Binary value) {
+    builder.writeBinary(value);
+  }
+
+  @Override
+  public ColumnBuilder createColumnBuilder(int expectedEntries) {
+    return new BinaryColumnBuilder(null, expectedEntries);
+  }
+
+  @Override
+  public TypeEnum getTypeEnum() {
+    return TypeEnum.OBJECT;
+  }
+
+  @Override
+  public String getDisplayName() {
+    return "OBJECT";
+  }
+
+  @Override
+  public boolean isComparable() {
+    return false;
+  }
+
+  @Override
+  public boolean isOrderable() {
+    return false;
+  }
+
+  @Override
+  public List<Type> getTypeParameters() {
+    return Collections.emptyList();
+  }
+
+  public static ObjectType getInstance() {
+    return OBJECT;
+  }
+}
diff --git 
a/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/TypeEnum.java 
b/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/TypeEnum.java
index 184a64af..52db17a3 100644
--- a/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/TypeEnum.java
+++ b/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/TypeEnum.java
@@ -38,5 +38,6 @@ public enum TypeEnum {
   TIMESTAMP,
   DATE,
   BLOB,
-  STRING
+  STRING,
+  OBJECT
 }
diff --git 
a/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/TypeFactory.java 
b/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/TypeFactory.java
index 41474542..cf23572d 100644
--- 
a/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/TypeFactory.java
+++ 
b/java/tsfile/src/main/java/org/apache/tsfile/read/common/type/TypeFactory.java
@@ -49,6 +49,8 @@ public class TypeFactory {
         return StringType.getInstance();
       case BLOB:
         return BlobType.getInstance();
+      case OBJECT:
+        return ObjectType.getInstance();
       default:
         throw new UnsupportedOperationException(
             String.format("Invalid TSDataType for TypeFactory: %s", 
tsDataType));
diff --git 
a/java/tsfile/src/main/java/org/apache/tsfile/read/query/dataset/DataSetWithoutTimeGenerator.java
 
b/java/tsfile/src/main/java/org/apache/tsfile/read/query/dataset/DataSetWithoutTimeGenerator.java
index 02f8ffd4..20df8887 100644
--- 
a/java/tsfile/src/main/java/org/apache/tsfile/read/query/dataset/DataSetWithoutTimeGenerator.java
+++ 
b/java/tsfile/src/main/java/org/apache/tsfile/read/query/dataset/DataSetWithoutTimeGenerator.java
@@ -179,6 +179,7 @@ public class DataSetWithoutTimeGenerator extends 
QueryDataSet {
       case TEXT:
       case BLOB:
       case STRING:
+      case OBJECT:
         field.setBinaryV(col.getBinary());
         break;
       case VECTOR:
diff --git 
a/java/tsfile/src/main/java/org/apache/tsfile/read/reader/TsFileLastReader.java 
b/java/tsfile/src/main/java/org/apache/tsfile/read/reader/TsFileLastReader.java
index 312b73dd..3957083d 100644
--- 
a/java/tsfile/src/main/java/org/apache/tsfile/read/reader/TsFileLastReader.java
+++ 
b/java/tsfile/src/main/java/org/apache/tsfile/read/reader/TsFileLastReader.java
@@ -58,8 +58,8 @@ public class TsFileLastReader
 
   private final TsFileSequenceReader sequenceReader;
   private boolean asyncIO = true;
-  // when true, blob series will return a null TimeValuePair
-  private boolean ignoreBlob = false;
+  // when true, series without last value statistics will return a null 
TimeValuePair
+  private boolean ignoreTypesWithoutStatistics = false;
   private Iterator<Pair<IDeviceID, List<TimeseriesMetadata>>> 
timeseriesMetadataIter;
   private Pair<IDeviceID, List<Pair<String, TimeValuePair>>> nextValue;
 
@@ -73,13 +73,14 @@ public class TsFileLastReader
   /**
    * @param filePath path of the TsFile
    * @param asyncIO use asynchronous IO or not
-   * @param ignoreBlob whether to ignore series with blob type (the returned 
TimeValuePair will be
-   *     null)
+   * @param ignoreTypesWithoutStatistics whether to ignore series with blob 
type or object type (the
+   *     returned TimeValuePair will be null)
    */
-  public TsFileLastReader(String filePath, boolean asyncIO, boolean 
ignoreBlob) throws IOException {
+  public TsFileLastReader(String filePath, boolean asyncIO, boolean 
ignoreTypesWithoutStatistics)
+      throws IOException {
     this(filePath);
     this.asyncIO = asyncIO;
-    this.ignoreBlob = ignoreBlob;
+    this.ignoreTypesWithoutStatistics = ignoreTypesWithoutStatistics;
   }
 
   @Override
@@ -270,7 +271,8 @@ public class TsFileLastReader
   }
 
   private void init() throws IOException {
-    timeseriesMetadataIter = sequenceReader.iterAllTimeseriesMetadata(false, 
!ignoreBlob);
+    timeseriesMetadataIter =
+        sequenceReader.iterAllTimeseriesMetadata(false, 
!ignoreTypesWithoutStatistics);
     if (asyncIO) {
       int queueCapacity = 1024;
       lastValueQueue = new ArrayBlockingQueue<>(queueCapacity);
diff --git 
a/java/tsfile/src/main/java/org/apache/tsfile/read/reader/page/PageReader.java 
b/java/tsfile/src/main/java/org/apache/tsfile/read/reader/page/PageReader.java
index 7ba234cf..6d56530c 100644
--- 
a/java/tsfile/src/main/java/org/apache/tsfile/read/reader/page/PageReader.java
+++ 
b/java/tsfile/src/main/java/org/apache/tsfile/read/reader/page/PageReader.java
@@ -196,6 +196,7 @@ public class PageReader implements IPageReader {
         case TEXT:
         case BLOB:
         case STRING:
+        case OBJECT:
           Binary aBinary = valueDecoder.readBinary(valueBuffer);
           if (!isDeleted(timestamp)
               && (allSatisfy || recordFilter.satisfyBinary(timestamp, 
aBinary))) {
@@ -339,6 +340,7 @@ public class PageReader implements IPageReader {
       case TEXT:
       case BLOB:
       case STRING:
+      case OBJECT:
         while (timeDecoder.hasNext(timeBuffer)) {
           long timestamp = timeDecoder.readLong(timeBuffer);
           Binary aBinary = valueDecoder.readBinary(valueBuffer);
diff --git 
a/java/tsfile/src/main/java/org/apache/tsfile/read/reader/page/ValuePageReader.java
 
b/java/tsfile/src/main/java/org/apache/tsfile/read/reader/page/ValuePageReader.java
index 998b2117..ff34c98b 100644
--- 
a/java/tsfile/src/main/java/org/apache/tsfile/read/reader/page/ValuePageReader.java
+++ 
b/java/tsfile/src/main/java/org/apache/tsfile/read/reader/page/ValuePageReader.java
@@ -159,6 +159,7 @@ public class ValuePageReader {
         case TEXT:
         case BLOB:
         case STRING:
+        case OBJECT:
           Binary aBinary = valueDecoder.readBinary(valueBuffer);
           if (!isDeleted(timestamp)
               && (filter == null || filter.satisfyBinary(timestamp, aBinary))) 
{
@@ -214,6 +215,7 @@ public class ValuePageReader {
       case TEXT:
       case BLOB:
       case STRING:
+      case OBJECT:
         Binary aBinary = valueDecoder.readBinary(valueBuffer);
         if (!isDeleted(timestamp)) {
           resultValue = new TsPrimitiveType.TsBinary(aBinary);
@@ -276,6 +278,7 @@ public class ValuePageReader {
         case TEXT:
         case BLOB:
         case STRING:
+        case OBJECT:
           Binary aBinary = valueDecoder.readBinary(valueBuffer);
           if (!isDeleted(timeBatch[i])) {
             valueBatch[i] = new TsPrimitiveType.TsBinary(aBinary);
@@ -376,6 +379,7 @@ public class ValuePageReader {
         case TEXT:
         case BLOB:
         case STRING:
+        case OBJECT:
           Binary aBinary = valueDecoder.readBinary(valueBuffer);
           if (keepCurrentRow[i]) {
             if (isDeleted[i]) {
@@ -454,6 +458,7 @@ public class ValuePageReader {
         case TEXT:
         case BLOB:
         case STRING:
+        case OBJECT:
           Binary aBinary = valueDecoder.readBinary(valueBuffer);
           if (keepCurrentRow[i]) {
             columnBuilder.writeBinary(aBinary);
@@ -577,6 +582,7 @@ public class ValuePageReader {
       case TEXT:
       case BLOB:
       case STRING:
+      case OBJECT:
         // skip useless data
         for (int i = 0; i < readStartIndex; i++) {
           if (((bitmap[i / 8] & 0xFF) & (MASK >>> (i % 8))) == 0) {
diff --git a/java/tsfile/src/main/java/org/apache/tsfile/utils/BytesUtils.java 
b/java/tsfile/src/main/java/org/apache/tsfile/utils/BytesUtils.java
index 82acc0b4..051c259a 100644
--- a/java/tsfile/src/main/java/org/apache/tsfile/utils/BytesUtils.java
+++ b/java/tsfile/src/main/java/org/apache/tsfile/utils/BytesUtils.java
@@ -37,6 +37,14 @@ import java.util.List;
  */
 public class BytesUtils {
 
+  private static final String BYTE_OBJECT_STRING_FORMAT = "(Object) %d B";
+  private static final double KB_SIZE = 1024;
+  private static final String KB_OBJECT_STRING_FORMAT = "(Object) %.2f KB";
+  private static final double MB_SIZE = 1024.0 * 1024;
+  private static final String MB_OBJECT_STRING_FORMAT = "(Object) %.2f MB";
+  private static final double GB_SIZE = 1024.0 * 1024 * 1024;
+  private static final String GB_OBJECT_STRING_FORMAT = "(Object) %.2f GB";
+
   private BytesUtils() {}
 
   private static final Logger LOG = LoggerFactory.getLogger(BytesUtils.class);
@@ -951,4 +959,17 @@ public class BytesUtils {
     }
     return hexString.toString();
   }
+
+  public static String parseObjectByteArrayToString(byte[] input) {
+    long size = BytesUtils.bytesToLong(input, 8);
+    if (size < KB_SIZE) {
+      return String.format(BYTE_OBJECT_STRING_FORMAT, size);
+    } else if (size < MB_SIZE) {
+      return String.format(KB_OBJECT_STRING_FORMAT, size / KB_SIZE);
+    } else if (size < GB_SIZE) {
+      return String.format(MB_OBJECT_STRING_FORMAT, size / MB_SIZE);
+    } else {
+      return String.format(GB_OBJECT_STRING_FORMAT, size / GB_SIZE);
+    }
+  }
 }
diff --git 
a/java/tsfile/src/main/java/org/apache/tsfile/write/chunk/AlignedChunkGroupWriterImpl.java
 
b/java/tsfile/src/main/java/org/apache/tsfile/write/chunk/AlignedChunkGroupWriterImpl.java
index 3207c409..5fd9dde7 100644
--- 
a/java/tsfile/src/main/java/org/apache/tsfile/write/chunk/AlignedChunkGroupWriterImpl.java
+++ 
b/java/tsfile/src/main/java/org/apache/tsfile/write/chunk/AlignedChunkGroupWriterImpl.java
@@ -191,6 +191,7 @@ public class AlignedChunkGroupWriterImpl implements 
IChunkGroupWriter {
         case TEXT:
         case BLOB:
         case STRING:
+        case OBJECT:
           valueChunkWriter.write(time, (Binary) point.getValue(), isNull);
           break;
         default:
@@ -283,6 +284,7 @@ public class AlignedChunkGroupWriterImpl implements 
IChunkGroupWriter {
           case TEXT:
           case BLOB:
           case STRING:
+          case OBJECT:
             valueChunkWriter.write(time, ((Binary[]) 
tablet.getValues()[columnIndex])[row], isNull);
             break;
           default:
@@ -376,6 +378,7 @@ public class AlignedChunkGroupWriterImpl implements 
IChunkGroupWriter {
         case TEXT:
         case BLOB:
         case STRING:
+        case OBJECT:
           valueChunkWriter.write(-1, null, true);
           break;
         default:
diff --git 
a/java/tsfile/src/main/java/org/apache/tsfile/write/chunk/AlignedChunkWriterImpl.java
 
b/java/tsfile/src/main/java/org/apache/tsfile/write/chunk/AlignedChunkWriterImpl.java
index 2ec4bd8f..27761e67 100644
--- 
a/java/tsfile/src/main/java/org/apache/tsfile/write/chunk/AlignedChunkWriterImpl.java
+++ 
b/java/tsfile/src/main/java/org/apache/tsfile/write/chunk/AlignedChunkWriterImpl.java
@@ -325,6 +325,7 @@ public class AlignedChunkWriterImpl implements IChunkWriter 
{
         case TEXT:
         case BLOB:
         case STRING:
+        case OBJECT:
           writer.write(
               time,
               point != null ? point.getBinary() : new 
Binary("".getBytes(StandardCharsets.UTF_8)),
@@ -369,6 +370,7 @@ public class AlignedChunkWriterImpl implements IChunkWriter 
{
         case TEXT:
         case BLOB:
         case STRING:
+        case OBJECT:
           chunkWriter.write(times, column.getBinaries(), column.isNull(), 
batchSize, arrayOffset);
           break;
         case DOUBLE:
diff --git 
a/java/tsfile/src/main/java/org/apache/tsfile/write/chunk/NonAlignedChunkGroupWriterImpl.java
 
b/java/tsfile/src/main/java/org/apache/tsfile/write/chunk/NonAlignedChunkGroupWriterImpl.java
index 58de2ffb..10e66b9a 100644
--- 
a/java/tsfile/src/main/java/org/apache/tsfile/write/chunk/NonAlignedChunkGroupWriterImpl.java
+++ 
b/java/tsfile/src/main/java/org/apache/tsfile/write/chunk/NonAlignedChunkGroupWriterImpl.java
@@ -163,6 +163,7 @@ public class NonAlignedChunkGroupWriterImpl implements 
IChunkGroupWriter {
           case TEXT:
           case BLOB:
           case STRING:
+          case OBJECT:
             chunkWriters
                 .get(measurementId)
                 .write(time, ((Binary[]) tablet.getValues()[column])[row]);
diff --git 
a/java/tsfile/src/main/java/org/apache/tsfile/write/record/Tablet.java 
b/java/tsfile/src/main/java/org/apache/tsfile/write/record/Tablet.java
index c984b422..8336d2b7 100644
--- a/java/tsfile/src/main/java/org/apache/tsfile/write/record/Tablet.java
+++ b/java/tsfile/src/main/java/org/apache/tsfile/write/record/Tablet.java
@@ -557,6 +557,20 @@ public class Tablet {
     updateBitMap(rowIndex, columnIndex, false);
   }
 
+  public void addValue(int rowIndex, int columnIndex, boolean isEOF, long 
offset, byte[] content) {
+    if (!(values[columnIndex] instanceof Binary[])) {
+      throw new IllegalArgumentException(
+          "The data type of column index " + columnIndex + " is not OBJECT");
+    }
+    final Binary[] sensor = (Binary[]) values[columnIndex];
+    byte[] val = new byte[content.length + 9];
+    val[0] = (byte) (isEOF ? 1 : 0);
+    System.arraycopy(BytesUtils.longToBytes(offset), 0, val, 1, 8);
+    System.arraycopy(content, 0, val, 9, content.length);
+    sensor[rowIndex] = new Binary(val);
+    updateBitMap(rowIndex, columnIndex, false);
+  }
+
   private int getColumnIndexByMeasurement(String measurement) {
     if (measurement == null) {
       throw new IllegalArgumentException("measurement should be non null 
value");
@@ -660,6 +674,7 @@ public class Tablet {
       case TEXT:
       case STRING:
       case BLOB:
+      case OBJECT:
         valueColumn = new Binary[capacity];
         break;
       case DATE:
diff --git 
a/java/tsfile/src/main/java/org/apache/tsfile/write/record/datapoint/DataPoint.java
 
b/java/tsfile/src/main/java/org/apache/tsfile/write/record/datapoint/DataPoint.java
index 7bd126c5..ed0fbddc 100644
--- 
a/java/tsfile/src/main/java/org/apache/tsfile/write/record/datapoint/DataPoint.java
+++ 
b/java/tsfile/src/main/java/org/apache/tsfile/write/record/datapoint/DataPoint.java
@@ -91,6 +91,7 @@ public abstract class DataPoint {
         case TEXT:
         case BLOB:
         case STRING:
+        case OBJECT:
           dataPoint =
               new StringDataPoint(measurementId, new Binary(value, 
TSFileConfig.STRING_CHARSET));
           break;
diff --git 
a/java/tsfile/src/main/java/org/apache/tsfile/write/v4/AbstractTableModelTsFileWriter.java
 
b/java/tsfile/src/main/java/org/apache/tsfile/write/v4/AbstractTableModelTsFileWriter.java
index 260d4264..2df52df5 100644
--- 
a/java/tsfile/src/main/java/org/apache/tsfile/write/v4/AbstractTableModelTsFileWriter.java
+++ 
b/java/tsfile/src/main/java/org/apache/tsfile/write/v4/AbstractTableModelTsFileWriter.java
@@ -32,6 +32,7 @@ import 
org.apache.tsfile.write.chunk.NonAlignedChunkGroupWriterImpl;
 import org.apache.tsfile.write.chunk.TableChunkGroupWriterImpl;
 import org.apache.tsfile.write.schema.Schema;
 import org.apache.tsfile.write.writer.TsFileIOWriter;
+import org.apache.tsfile.write.writer.TsFileOutput;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -83,7 +84,7 @@ abstract class AbstractTableModelTsFileWriter implements 
ITsFileWriter {
   protected AbstractTableModelTsFileWriter(File file, long 
chunkGroupSizeThreshold)
       throws IOException {
     this(
-        file,
+        new TsFileIOWriter(file),
         chunkGroupSizeThreshold,
         new EncryptParameter(config.getEncryptType(), config.getEncryptKey()));
   }
@@ -92,9 +93,27 @@ abstract class AbstractTableModelTsFileWriter implements 
ITsFileWriter {
   protected AbstractTableModelTsFileWriter(
       File file, long chunkGroupSizeThreshold, EncryptParameter 
firstEncryptParam)
       throws IOException {
+    this(new TsFileIOWriter(file), chunkGroupSizeThreshold, firstEncryptParam);
+  }
+
+  @TsFileApi
+  protected AbstractTableModelTsFileWriter(TsFileOutput output, long 
chunkGroupSizeThreshold)
+      throws IOException {
+    this(
+        new TsFileIOWriter(output),
+        chunkGroupSizeThreshold,
+        new EncryptParameter(config.getEncryptType(), config.getEncryptKey()));
+  }
+
+  @TsFileApi
+  protected AbstractTableModelTsFileWriter(
+      TsFileIOWriter tsFileIOWriter,
+      long chunkGroupSizeThreshold,
+      EncryptParameter firstEncryptParam)
+      throws IOException {
     Schema schema = new Schema();
     TSFileConfig conf = TSFileDescriptor.getInstance().getConfig();
-    this.fileWriter = new TsFileIOWriter(file);
+    this.fileWriter = tsFileIOWriter;
     fileWriter.setSchema(schema);
 
     this.pageSize = conf.getPageSizeInByte();
diff --git 
a/java/tsfile/src/main/java/org/apache/tsfile/write/v4/DeviceTableModelWriter.java
 
b/java/tsfile/src/main/java/org/apache/tsfile/write/v4/DeviceTableModelWriter.java
index b2ae6b1f..0397b42d 100644
--- 
a/java/tsfile/src/main/java/org/apache/tsfile/write/v4/DeviceTableModelWriter.java
+++ 
b/java/tsfile/src/main/java/org/apache/tsfile/write/v4/DeviceTableModelWriter.java
@@ -34,6 +34,7 @@ import org.apache.tsfile.write.record.TSRecord;
 import org.apache.tsfile.write.record.Tablet;
 import org.apache.tsfile.write.record.datapoint.DataPoint;
 import org.apache.tsfile.write.schema.IMeasurementSchema;
+import org.apache.tsfile.write.writer.TsFileOutput;
 
 import java.io.File;
 import java.io.IOException;
@@ -52,6 +53,12 @@ public class DeviceTableModelWriter extends 
AbstractTableModelTsFileWriter {
     registerTableSchema(tableSchema);
   }
 
+  public DeviceTableModelWriter(
+      TsFileOutput tsFileOutput, TableSchema tableSchema, long 
memoryThreshold) throws IOException {
+    super(tsFileOutput, memoryThreshold);
+    registerTableSchema(tableSchema);
+  }
+
   /**
    * Write the tablet in to the TsFile with the table-view. The method will 
try to split the tablet
    * by device.
diff --git 
a/java/tsfile/src/test/java/org/apache/tsfile/file/metadata/statistics/StatisticsTest.java
 
b/java/tsfile/src/test/java/org/apache/tsfile/file/metadata/statistics/StatisticsTest.java
index 06aeca38..ba12c635 100644
--- 
a/java/tsfile/src/test/java/org/apache/tsfile/file/metadata/statistics/StatisticsTest.java
+++ 
b/java/tsfile/src/test/java/org/apache/tsfile/file/metadata/statistics/StatisticsTest.java
@@ -108,6 +108,7 @@ public class StatisticsTest {
             statistics.getLastValue());
         break;
       case BLOB:
+      case OBJECT:
         break;
       default:
         throw new IllegalArgumentException(statistics.getType().toString());
@@ -162,6 +163,10 @@ public class StatisticsTest {
         BlobStatistics blobStat = new BlobStatistics();
         result = blobStat;
         break;
+      case OBJECT:
+        ObjectStatistics objectStat = new ObjectStatistics();
+        result = objectStat;
+        break;
       case DATE:
         DateStatistics dateStat = new DateStatistics();
         dateStat.initializeStats(val, val, val, val, val);
diff --git 
a/java/tsfile/src/test/java/org/apache/tsfile/utils/TypeCastTest.java 
b/java/tsfile/src/test/java/org/apache/tsfile/utils/TypeCastTest.java
index 4d1d0006..6398eac7 100644
--- a/java/tsfile/src/test/java/org/apache/tsfile/utils/TypeCastTest.java
+++ b/java/tsfile/src/test/java/org/apache/tsfile/utils/TypeCastTest.java
@@ -42,6 +42,7 @@ public class TypeCastTest {
     Collections.addAll(dataTypes, TSDataType.values());
     dataTypes.remove(TSDataType.VECTOR);
     dataTypes.remove(TSDataType.UNKNOWN);
+    dataTypes.remove(TSDataType.OBJECT);
 
     for (TSDataType from : dataTypes) {
       for (TSDataType to : dataTypes) {
@@ -75,6 +76,7 @@ public class TypeCastTest {
     Collections.addAll(dataTypes, TSDataType.values());
     dataTypes.remove(TSDataType.VECTOR);
     dataTypes.remove(TSDataType.UNKNOWN);
+    dataTypes.remove(TSDataType.OBJECT);
 
     for (TSDataType from : dataTypes) {
       for (TSDataType to : dataTypes) {
@@ -195,6 +197,7 @@ public class TypeCastTest {
       case STRING:
       case TEXT:
       case BLOB:
+      case OBJECT:
         return new Binary(Integer.toString(i), StandardCharsets.UTF_8);
       case UNKNOWN:
       case VECTOR:
@@ -220,6 +223,7 @@ public class TypeCastTest {
       case STRING:
       case TEXT:
       case BLOB:
+      case OBJECT:
         return new Binary[] {
           new Binary(Integer.toString(1), StandardCharsets.UTF_8),
           new Binary(Integer.toString(2), StandardCharsets.UTF_8),

Reply via email to