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()); + } + } +}
