Repository: modin-project/modin

Issue:
Poor performance of rows picking in arrow-mask queries
[`OmnisciOnRayFrame._arrow_row_slice`](https://github.com/modin-project/modin/blob/e4e330ae8759e283b2d2ec4cb973ef4048c8cce8/modin/experimental/engines/omnisci_on_ray/frame/data.py#L1215) performs pretty badly when it comes to non-continuous indices. 

For example, in the case of indices are set by this slice `slice(step=2)` the following code will produce `len(df) / 2` amount of single-element `parts` which will then be concatenated:
https://github.com/modin-project/modin/blob/e4e330ae8759e283b2d2ec4cb973ef4048c8cce8/modin/experimental/engines/omnisci_on_ray/frame/data.py#L1230-L1233
Current approach takes about 10 seconds to do simple `.iloc` and `.loc` operations on a `(10_000_000, 10)` frame.



Discussion:

Resolving patch:
diff --git a/modin/experimental/engines/omnisci_on_ray/frame/data.py b/modin/experimental/engines/omnisci_on_ray/frame/data.py
--- a/modin/experimental/engines/omnisci_on_ray/frame/data.py
+++ b/modin/experimental/engines/omnisci_on_ray/frame/data.py
@@ -18,6 +18,7 @@
 from pandas.core.index import ensure_index, Index, MultiIndex, RangeIndex
 from pandas.core.dtypes.common import get_dtype, is_list_like, is_bool_dtype
 from modin.error_message import ErrorMessage
+from modin.pandas.indexing import is_range_like
 import pandas as pd
 
 from .df_algebra import (
@@ -1214,41 +1215,28 @@ def _arrow_col_slice(self, new_columns):
 
     def _arrow_row_slice(self, row_numeric_idx):
         table = self._execute_arrow()
+
+        if not isinstance(row_numeric_idx, slice) and not is_range_like(
+            row_numeric_idx
+        ):
+            if not isinstance(row_numeric_idx, (pyarrow.Array, np.ndarray, list)):
+                row_numeric_idx = pyarrow.array(row_numeric_idx)
+            return table.take(row_numeric_idx)
+
         if isinstance(row_numeric_idx, slice):
-            start = 0 if row_numeric_idx.start is None else row_numeric_idx.start
-            if start < 0:
-                start = table.num_rows - start
-            end = (
-                table.num_rows if row_numeric_idx.stop is None else row_numeric_idx.stop
-            )
-            if end < 0:
-                end = table.num_rows - end
-            if row_numeric_idx.step is None or row_numeric_idx.step == 1:
-                length = 0 if start >= end else end - start
-                return table.slice(start, length)
-            else:
-                parts = []
-                for i in range(start, end, row_numeric_idx.step):
-                    parts.append(table.slice(i, 1))
-                return pyarrow.concat_tables(parts)
-
-        start = None
-        end = None
-        parts = []
-        for idx in row_numeric_idx:
-            if start is None:
-                start = idx
-                end = idx
-            elif idx == end + 1:
-                end = idx
-            else:
-                if start:
-                    parts.append(table.slice(start, end - start + 1))
-                start = idx
-                end = idx
-        parts.append(table.slice(start, end - start + 1))
+            row_numeric_idx = range(*row_numeric_idx.indices(table.num_rows))
+
+        start, stop, step = (
+            row_numeric_idx.start,
+            row_numeric_idx.stop,
+            row_numeric_idx.step,
+        )
 
-        return pyarrow.concat_tables(parts)
+        if step == 1:
+            return table.slice(start, len(row_numeric_idx))
+        else:
+            indices = np.arange(start, stop, step)
+            return table.take(indices)
 
     @classmethod
     def _arrow_concat(cls, frames):
diff --git a/modin/pandas/indexing.py b/modin/pandas/indexing.py
--- a/modin/pandas/indexing.py
+++ b/modin/pandas/indexing.py
@@ -153,6 +153,30 @@ def is_integer_slice(x):
     return True
 
 
+def is_range_like(obj):
+    """
+    Check if the object is range-like.
+
+    Objects that are considered range-like have information about the range (start and
+    stop positions, and step) and also have to be iterable. Examples of range-like
+    objects are: Python range, pandas.RangeIndex.
+
+    Parameters
+    ----------
+    obj : object
+
+    Returns
+    -------
+    bool
+    """
+    return (
+        hasattr(obj, "__iter__")
+        and hasattr(obj, "start")
+        and hasattr(obj, "stop")
+        and hasattr(obj, "step")
+    )
+
+
 _ILOC_INT_ONLY_ERROR = """
 Location based indexing can only have [integer, integer slice (START point is
 INCLUDED, END point is EXCLUDED), listlike of integers, boolean array] types.


Test patch: