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

lzljs3620320 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/paimon.git


The following commit(s) were added to refs/heads/master by this push:
     new f6bee4e29e [python] Python BTree support between predicate (#7193)
f6bee4e29e is described below

commit f6bee4e29e0adbb5ed18f9e131317aa7568ea182
Author: Jingsong Lee <[email protected]>
AuthorDate: Tue Feb 3 19:20:56 2026 +0800

    [python] Python BTree support between predicate (#7193)
---
 .../globalindex/btree/btree_index_reader.py        | 11 +++++++++++
 .../pypaimon/globalindex/global_index_evaluator.py |  2 ++
 .../pypaimon/globalindex/global_index_reader.py    |  4 ++++
 .../pypaimon/tests/e2e/java_py_read_write_test.py  | 22 ++++++++++++++++++++++
 4 files changed, 39 insertions(+)

diff --git a/paimon-python/pypaimon/globalindex/btree/btree_index_reader.py 
b/paimon-python/pypaimon/globalindex/btree/btree_index_reader.py
index 2c64d3a4a2..034e220108 100644
--- a/paimon-python/pypaimon/globalindex/btree/btree_index_reader.py
+++ b/paimon-python/pypaimon/globalindex/btree/btree_index_reader.py
@@ -406,6 +406,17 @@ class BTreeIndexReader(GlobalIndexReader):
         
         return GlobalIndexResult.create(supplier)
 
+    def visit_between(self, field_ref: FieldRef, min_v: object, max_v: object) 
-> Optional[GlobalIndexResult]:
+        """Visit a between predicate."""
+
+        def supplier():
+            try:
+                return self._range_query(min_v, max_v, True, True)
+            except Exception as e:
+                raise RuntimeError("fail to read btree index file.", e)
+
+        return GlobalIndexResult.create(supplier)
+
     def close(self) -> None:
         """Close the reader and release resources."""
         if self.input_stream is not None:
diff --git a/paimon-python/pypaimon/globalindex/global_index_evaluator.py 
b/paimon-python/pypaimon/globalindex/global_index_evaluator.py
index 46bb5cd67d..1692113d64 100644
--- a/paimon-python/pypaimon/globalindex/global_index_evaluator.py
+++ b/paimon-python/pypaimon/globalindex/global_index_evaluator.py
@@ -186,6 +186,8 @@ class GlobalIndexEvaluator:
             return reader.visit_ends_with(field_ref, literals[0])
         elif method == 'contains':
             return reader.visit_contains(field_ref, literals[0])
+        elif method == 'between':
+            return reader.visit_between(field_ref, literals[0], literals[1])
         
         return None
 
diff --git a/paimon-python/pypaimon/globalindex/global_index_reader.py 
b/paimon-python/pypaimon/globalindex/global_index_reader.py
index a5006bddf5..ce70b5d6c1 100644
--- a/paimon-python/pypaimon/globalindex/global_index_reader.py
+++ b/paimon-python/pypaimon/globalindex/global_index_reader.py
@@ -102,6 +102,10 @@ class GlobalIndexReader(ABC):
         """Visit a like predicate."""
         return None
 
+    def visit_between(self, field_ref: FieldRef, min_v: object, max_v: object) 
-> Optional['GlobalIndexResult']:
+        """Visit a between predicate."""
+        return None
+
     @abstractmethod
     def close(self) -> None:
         """Close the reader and release resources."""
diff --git a/paimon-python/pypaimon/tests/e2e/java_py_read_write_test.py 
b/paimon-python/pypaimon/tests/e2e/java_py_read_write_test.py
index 3180d7b699..320ee6c6e2 100644
--- a/paimon-python/pypaimon/tests/e2e/java_py_read_write_test.py
+++ b/paimon-python/pypaimon/tests/e2e/java_py_read_write_test.py
@@ -363,6 +363,28 @@ class JavaPyReadWriteTest(unittest.TestCase):
         })
         self.assertEqual(expected, actual)
 
+        # read between index
+        read_builder.with_filter(predicate_builder.between('k', 'k990', 
'k995'))
+        table_read = read_builder.new_read()
+        splits = read_builder.new_scan().plan().splits()
+        actual = table_sort_by(table_read.to_arrow(splits), 'k')
+        expected = pa.Table.from_pydict({
+            'k': ["k990", "k991", "k992", "k993", "k994", "k995"],
+            'v': ["v990", "v991", "v992", "v993", "v994", "v995"]
+        })
+        self.assertEqual(expected, actual)
+
+        # read in index
+        read_builder.with_filter(predicate_builder.is_in('k', ['k990', 
'k995']))
+        table_read = read_builder.new_read()
+        splits = read_builder.new_scan().plan().splits()
+        actual = table_sort_by(table_read.to_arrow(splits), 'k')
+        expected = pa.Table.from_pydict({
+            'k': ["k990", "k995"],
+            'v': ["v990", "v995"]
+        })
+        self.assertEqual(expected, actual)
+
     def _test_read_btree_index_null(self):
         table = self.catalog.get_table('default.test_btree_index_null')
 

Reply via email to