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

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

commit 9280a837da750deae857c86dc415a35be0a8fad8
Author: JackieTien97 <[email protected]>
AuthorDate: Fri Dec 20 16:40:28 2024 +0800

    Add TreeDeviceIdColumnValueExtractor for TreeDeviceId to extract ID Column 
value
---
 .../org/apache/tsfile/file/metadata/IDeviceID.java |   9 ++
 .../idcolumn/FourOrHigherLevelDBExtractor.java     |  47 ++++++
 .../metadata/idcolumn/ThreeLevelDBExtractor.java   |  50 ++++++
 .../metadata/idcolumn/TwoLevelDBExtractor.java     |  57 +++++++
 .../TreeDeviceIdColumnValueExtractorTest.java      | 170 +++++++++++++++++++++
 5 files changed, 333 insertions(+)

diff --git 
a/java/tsfile/src/main/java/org/apache/tsfile/file/metadata/IDeviceID.java 
b/java/tsfile/src/main/java/org/apache/tsfile/file/metadata/IDeviceID.java
index 6245799f..17faa274 100644
--- a/java/tsfile/src/main/java/org/apache/tsfile/file/metadata/IDeviceID.java
+++ b/java/tsfile/src/main/java/org/apache/tsfile/file/metadata/IDeviceID.java
@@ -170,4 +170,13 @@ public interface IDeviceID extends Comparable<IDeviceID>, 
Accountable, Serializa
 
     Factory DEFAULT_FACTORY = StringArrayDeviceID.getFACTORY();
   }
+
+  interface TreeDeviceIdColumnValueExtractor {
+    /**
+     * @param treeDeviceId IDeviceId for a tree-style device
+     * @param idColumnIndex the wanted ID Column index
+     * @return the nth ID Column value for @param{treeDeviceId}
+     */
+    Object extract(IDeviceID treeDeviceId, int idColumnIndex);
+  }
 }
diff --git 
a/java/tsfile/src/main/java/org/apache/tsfile/file/metadata/idcolumn/FourOrHigherLevelDBExtractor.java
 
b/java/tsfile/src/main/java/org/apache/tsfile/file/metadata/idcolumn/FourOrHigherLevelDBExtractor.java
new file mode 100644
index 00000000..84c82895
--- /dev/null
+++ 
b/java/tsfile/src/main/java/org/apache/tsfile/file/metadata/idcolumn/FourOrHigherLevelDBExtractor.java
@@ -0,0 +1,47 @@
+/*
+ * 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.idcolumn;
+
+import org.apache.tsfile.file.metadata.IDeviceID;
+
+import static org.apache.tsfile.utils.Preconditions.checkArgument;
+
+/**
+ * used for DeviceId whose db level is 4 or higher, like root.a.b.db There 
only exist one case for
+ * four-or-higher-level-db tree-style DeviceId: 1. first segment will be the 
first three level of
+ * db, so id column index starting from db_level - 2 like root.a.b.db whose 
DeviceId is {root.a.b,
+ * db}, no id column in such case, also call say that id column starting from 
2(not existing) like
+ * root.a.b.db.d1 whose DeviceId is {root.a.b, db, d1}, id column starting 
from 2 like
+ * root.a.b.db.c.d1 whose DeviceId is {root.a.b, db, c, d1}, id column 
starting from 3
+ */
+public class FourOrHigherLevelDBExtractor implements 
IDeviceID.TreeDeviceIdColumnValueExtractor {
+
+  private final int idColumnStartIndex;
+
+  public FourOrHigherLevelDBExtractor(int dbLevelNumber) {
+    checkArgument(dbLevelNumber >= 4, "db level number must be >= 4");
+    this.idColumnStartIndex = dbLevelNumber - 2;
+  }
+
+  @Override
+  public Object extract(IDeviceID treeDeviceId, int idColumnIndex) {
+    return treeDeviceId.segment(idColumnStartIndex + idColumnIndex);
+  }
+}
diff --git 
a/java/tsfile/src/main/java/org/apache/tsfile/file/metadata/idcolumn/ThreeLevelDBExtractor.java
 
b/java/tsfile/src/main/java/org/apache/tsfile/file/metadata/idcolumn/ThreeLevelDBExtractor.java
new file mode 100644
index 00000000..1d4d06e0
--- /dev/null
+++ 
b/java/tsfile/src/main/java/org/apache/tsfile/file/metadata/idcolumn/ThreeLevelDBExtractor.java
@@ -0,0 +1,50 @@
+/*
+ * 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.idcolumn;
+
+import org.apache.tsfile.file.metadata.IDeviceID;
+
+/**
+ * used for DeviceId whose db level is 3, like root.a.db There exist two cases 
for three-level-db
+ * tree-style DeviceId: 1. db is DeviceId, like root.a.db whose DeviceId is 
{root.a, db}, no id
+ * column in such case 2. device has more than zero level excluding the db 
level, like root.a.db.d1
+ * whose DeviceId is {root.a.db, d1}, id column start from segment 1
+ */
+public class ThreeLevelDBExtractor implements 
IDeviceID.TreeDeviceIdColumnValueExtractor {
+
+  // like root.a.db, treeDBLength will be 9
+  private final int treeDBLength;
+
+  public ThreeLevelDBExtractor(int treeDBLength) {
+    this.treeDBLength = treeDBLength;
+  }
+
+  @Override
+  public Object extract(IDeviceID treeDeviceId, int idColumnIndex) {
+    int firstSegmentLength = ((String) treeDeviceId.segment(0)).length();
+    if (firstSegmentLength < treeDBLength) {
+      // case 1
+      return null;
+    } else {
+      // case 2
+      return treeDeviceId.segment(idColumnIndex + 1);
+    }
+  }
+}
diff --git 
a/java/tsfile/src/main/java/org/apache/tsfile/file/metadata/idcolumn/TwoLevelDBExtractor.java
 
b/java/tsfile/src/main/java/org/apache/tsfile/file/metadata/idcolumn/TwoLevelDBExtractor.java
new file mode 100644
index 00000000..cc7666f1
--- /dev/null
+++ 
b/java/tsfile/src/main/java/org/apache/tsfile/file/metadata/idcolumn/TwoLevelDBExtractor.java
@@ -0,0 +1,57 @@
+/*
+ * 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.idcolumn;
+
+import org.apache.tsfile.file.metadata.IDeviceID;
+
+/**
+ * used for DeviceId whose db level is 2, like root.db There exist three cases 
for two-level-db
+ * tree-style DeviceId: 1. db is DeviceId, like root.db whose DeviceId is 
{root, db}, no id column
+ * in such case 2. device has only one level excluding the db level, like 
root.db.d1 whose DeviceId
+ * is {root.db, d1}, only one id column in segment 1 3. device has more than 
one level excluding the
+ * db level, like root.db.a.d1 whose DeviceId is {root.db.a, d1}, id column 
start from segment 0
+ */
+public class TwoLevelDBExtractor implements 
IDeviceID.TreeDeviceIdColumnValueExtractor {
+
+  // like root.db, treeDBLength will be 7
+  private final int treeDBLength;
+
+  public TwoLevelDBExtractor(int treeDBLength) {
+    this.treeDBLength = treeDBLength;
+  }
+
+  @Override
+  public Object extract(IDeviceID treeDeviceId, int idColumnIndex) {
+    String firstSegment = (String) treeDeviceId.segment(0);
+    int firstSegmentLength = firstSegment.length();
+    if (firstSegmentLength < treeDBLength) {
+      // case 1
+      return null;
+    } else if (firstSegmentLength == treeDBLength) {
+      // case 2
+      return idColumnIndex == 0 ? treeDeviceId.segment(1) : null;
+    } else {
+      // case 3
+      return idColumnIndex == 0
+          ? firstSegment.substring(treeDBLength + 1)
+          : treeDeviceId.segment(idColumnIndex);
+    }
+  }
+}
diff --git 
a/java/tsfile/src/test/java/org/apache/tsfile/file/metadata/TreeDeviceIdColumnValueExtractorTest.java
 
b/java/tsfile/src/test/java/org/apache/tsfile/file/metadata/TreeDeviceIdColumnValueExtractorTest.java
new file mode 100644
index 00000000..6fe26ba0
--- /dev/null
+++ 
b/java/tsfile/src/test/java/org/apache/tsfile/file/metadata/TreeDeviceIdColumnValueExtractorTest.java
@@ -0,0 +1,170 @@
+/*
+ * 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;
+
+import org.apache.tsfile.file.metadata.idcolumn.FourOrHigherLevelDBExtractor;
+import org.apache.tsfile.file.metadata.idcolumn.ThreeLevelDBExtractor;
+import org.apache.tsfile.file.metadata.idcolumn.TwoLevelDBExtractor;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
+
+public class TreeDeviceIdColumnValueExtractorTest {
+
+  @Test
+  public void testTwoLevelDBExtractor() {
+    // db name is root.db whose name length is 7
+    TwoLevelDBExtractor extractor = new TwoLevelDBExtractor(7);
+    // case 1: device is root.db whose DeviceId is {root, db}
+    IDeviceID deviceID = IDeviceID.Factory.DEFAULT_FACTORY.create("root.db");
+    assertNull(extractor.extract(deviceID, 0));
+    assertNull(extractor.extract(deviceID, 1));
+    assertNull(extractor.extract(deviceID, 2));
+    assertNull(extractor.extract(deviceID, 3));
+
+    // case 2: device is root.db.d1 whose DeviceId is {root.db, d1}
+    deviceID = IDeviceID.Factory.DEFAULT_FACTORY.create("root.db.d1");
+    assertEquals("d1", extractor.extract(deviceID, 0));
+    assertNull(extractor.extract(deviceID, 1));
+    assertNull(extractor.extract(deviceID, 2));
+    assertNull(extractor.extract(deviceID, 3));
+
+    // case 3: device is root.db.a.d1 whose DeviceId is {root.db.a, d1}
+    deviceID = IDeviceID.Factory.DEFAULT_FACTORY.create("root.db.a.d1");
+    assertEquals("a", extractor.extract(deviceID, 0));
+    assertEquals("d1", extractor.extract(deviceID, 1));
+    assertNull(extractor.extract(deviceID, 2));
+    assertNull(extractor.extract(deviceID, 3));
+
+    // case 3: device is root.db.a.b.d1 whose DeviceId is {root.db.a, b, d1}
+    deviceID = IDeviceID.Factory.DEFAULT_FACTORY.create("root.db.a.b.d1");
+    assertEquals("a", extractor.extract(deviceID, 0));
+    assertEquals("b", extractor.extract(deviceID, 1));
+    assertEquals("d1", extractor.extract(deviceID, 2));
+    assertNull(extractor.extract(deviceID, 3));
+  }
+
+  @Test
+  public void testThreeLevelDBExtractor() {
+    // db name is root.a.db whose name length is 9
+    ThreeLevelDBExtractor extractor = new ThreeLevelDBExtractor(9);
+    // case 1: device is root.a.db whose DeviceId is {root.a, db}
+    IDeviceID deviceID = IDeviceID.Factory.DEFAULT_FACTORY.create("root.a.db");
+    assertNull(extractor.extract(deviceID, 0));
+    assertNull(extractor.extract(deviceID, 1));
+    assertNull(extractor.extract(deviceID, 2));
+    assertNull(extractor.extract(deviceID, 3));
+
+    // case 2: device is root.a.db.d1 whose DeviceId is {root.a.db, d1}
+    deviceID = IDeviceID.Factory.DEFAULT_FACTORY.create("root.a.db.d1");
+    assertEquals("d1", extractor.extract(deviceID, 0));
+    assertNull(extractor.extract(deviceID, 1));
+    assertNull(extractor.extract(deviceID, 2));
+    assertNull(extractor.extract(deviceID, 3));
+
+    // case 2: device is root.a.db.b.d1 whose DeviceId is {root.a.db, b, d1}
+    deviceID = IDeviceID.Factory.DEFAULT_FACTORY.create("root.a.db.b.d1");
+    assertEquals("b", extractor.extract(deviceID, 0));
+    assertEquals("d1", extractor.extract(deviceID, 1));
+    assertNull(extractor.extract(deviceID, 2));
+    assertNull(extractor.extract(deviceID, 3));
+
+    // case 2: device is root.a.db.b.c.d1 whose DeviceId is {root.a.db, b, c, 
d1}
+    deviceID = IDeviceID.Factory.DEFAULT_FACTORY.create("root.a.db.b.c.d1");
+    assertEquals("b", extractor.extract(deviceID, 0));
+    assertEquals("c", extractor.extract(deviceID, 1));
+    assertEquals("d1", extractor.extract(deviceID, 2));
+    assertNull(extractor.extract(deviceID, 3));
+  }
+
+  @Test
+  public void testFourOrHigherLevelDBExtractor() {
+    // db name is root.a.b.db whose level number is 4
+    FourOrHigherLevelDBExtractor extractor = new 
FourOrHigherLevelDBExtractor(4);
+    // device is root.a.b.db whose DeviceId is {root.a.b, db}
+    IDeviceID deviceID = 
IDeviceID.Factory.DEFAULT_FACTORY.create("root.a.b.db");
+    assertNull(extractor.extract(deviceID, 0));
+    assertNull(extractor.extract(deviceID, 1));
+    assertNull(extractor.extract(deviceID, 2));
+    assertNull(extractor.extract(deviceID, 3));
+    // device is root.a.b.db.d1 whose DeviceId is {root.a.b, db, d1}
+    deviceID = IDeviceID.Factory.DEFAULT_FACTORY.create("root.a.b.db.d1");
+    assertEquals("d1", extractor.extract(deviceID, 0));
+    assertNull(extractor.extract(deviceID, 1));
+    assertNull(extractor.extract(deviceID, 2));
+    assertNull(extractor.extract(deviceID, 3));
+    // device is root.a.b.db.b.d1 whose DeviceId is {root.a.b, db, b, d1}
+    deviceID = IDeviceID.Factory.DEFAULT_FACTORY.create("root.a.b.db.b.d1");
+    assertEquals("b", extractor.extract(deviceID, 0));
+    assertEquals("d1", extractor.extract(deviceID, 1));
+    assertNull(extractor.extract(deviceID, 2));
+    assertNull(extractor.extract(deviceID, 3));
+    // device is root.a.b.db.b.c.d1 whose DeviceId is {root.a.b, db, b, c, d1}
+    deviceID = IDeviceID.Factory.DEFAULT_FACTORY.create("root.a.b.db.b.c.d1");
+    assertEquals("b", extractor.extract(deviceID, 0));
+    assertEquals("c", extractor.extract(deviceID, 1));
+    assertEquals("d1", extractor.extract(deviceID, 2));
+    assertNull(extractor.extract(deviceID, 3));
+
+    // db name is root.a.b.c.db whose level number is 5
+    extractor = new FourOrHigherLevelDBExtractor(5);
+    // device is root.a.b.c.db whose DeviceId is {root.a.b, c, db}
+    deviceID = IDeviceID.Factory.DEFAULT_FACTORY.create("root.a.b.c.db");
+    assertNull(extractor.extract(deviceID, 0));
+    assertNull(extractor.extract(deviceID, 1));
+    assertNull(extractor.extract(deviceID, 2));
+    assertNull(extractor.extract(deviceID, 3));
+    // device is root.a.b.c.db.d1 whose DeviceId is {root.a.b, c, db, d1}
+    deviceID = IDeviceID.Factory.DEFAULT_FACTORY.create("root.a.b.c.db.d1");
+    assertEquals("d1", extractor.extract(deviceID, 0));
+    assertNull(extractor.extract(deviceID, 1));
+    assertNull(extractor.extract(deviceID, 2));
+    assertNull(extractor.extract(deviceID, 3));
+    // device is root.a.b.c.db.b.d1 whose DeviceId is {root.a.b, c, db, b, d1}
+    deviceID = IDeviceID.Factory.DEFAULT_FACTORY.create("root.a.b.c.db.b.d1");
+    assertEquals("b", extractor.extract(deviceID, 0));
+    assertEquals("d1", extractor.extract(deviceID, 1));
+    assertNull(extractor.extract(deviceID, 2));
+    assertNull(extractor.extract(deviceID, 3));
+    // device is root.a.b.c.db.b.c.d1 whose DeviceId is {root.a.b, c, db, b, 
c, d1}
+    deviceID = 
IDeviceID.Factory.DEFAULT_FACTORY.create("root.a.b.c.db.b.c.d1");
+    assertEquals("b", extractor.extract(deviceID, 0));
+    assertEquals("c", extractor.extract(deviceID, 1));
+    assertEquals("d1", extractor.extract(deviceID, 2));
+    assertNull(extractor.extract(deviceID, 3));
+
+    // db name is root.db whose level number is 2, should throw exception
+    try {
+      extractor = new FourOrHigherLevelDBExtractor(2);
+      fail("expected exception");
+    } catch (IllegalArgumentException e) {
+      assertEquals("db level number must be >= 4", e.getMessage());
+    }
+    try {
+      extractor = new FourOrHigherLevelDBExtractor(3);
+      fail("expected exception");
+    } catch (IllegalArgumentException e) {
+      assertEquals("db level number must be >= 4", e.getMessage());
+    }
+  }
+}

Reply via email to