Skip to content

index() crashes with RecursionError on plain ibis backends #275

Description

@espenjutte

I encountered the following error when using BSL with plain ibis backend (in this case BigQuery). When trying to use .index it raises a RecursionError. Which is a shame since this would be very usefull when using with Bigquery as well.

Here is a Claude generated reproduction of this issue:

To reproduce

# model.yaml
orders:
  profile:
    type: bigquery
  table: orders
  database:
    - bigquery-public-data
    - thelook_ecommerce
  dimensions:
    order_status: _.status
  measures:
    order_count: _.count()
from boring_semantic_layer import from_yaml

models = from_yaml("model.yaml")
orders = models["orders"]
orders.index("order_status").execute()  # crashes

Traceback (abridged — full depth is ~3000 frames):

File ".../boring_semantic_layer/ops.py", line 4763, in execute
    return _rebind_to_canonical_backend(self.to_untagged()).execute()
File ".../boring_semantic_layer/ops.py", line 4744, in to_untagged
    fragments = [build_fragment(f) for f in fields_to_index]
File ".../boring_semantic_layer/ops.py", line 4725, in build_fragment
    _build_string_index_fragment(...)
File ".../boring_semantic_layer/ops.py", line 4532, in _build_string_index_fragment
    .aggregate(weight=weight_expr)
  [xorq deferred resolver repeated ~3000 more times]
  ...
RecursionError: maximum recursion depth exceeded

Root cause

_get_weight_expr in ops.py constructs the weight expression using
xo._.count() — xorq's vendored _ (Deferred). When this is passed as
weight_expr to .aggregate() on a plain ibis grouped table, ibis tries to
resolve the xorq Deferred, which creates another Deferred, which tries to
resolve... infinite recursion.

# ops.py:4511-4512 — weight_expr always built with xorq's _
def _get_weight_expr(base_tbl, by_measure, all_roots, is_string):
    if not by_measure:
        return xo._.count()   # <-- xorq Deferred, incompatible with plain ibis tables

The same problem appears in _build_string_index_fragment (lines 4537-4538)
and _build_numeric_index_fragment (lines 4555-4559) which also use
xo._["value"] — another xorq Deferred — when building the fragment selects
and filters.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions