← На главную

fenic ускорили Polars 9 Rust-плагинами: токенизация и Jinja без Python

21.07.2026 21:26 · hackernews

fenic строит AI-пайплайны поверх Polars, используя PySpark-подобный API. Чтобы обрабатывать неструктурированный текст — токенизировать, рендерить Jinja, дёргать jq, парсить Markdown и транскрипты, искать нечёткие совпадения — команде понадобились операции, которых в Polars нет. Python-UDF через map_elements отпали сразу: медленно под GIL, ломают планировщик и не дают строгой типизации. Поэтому написали девять Rust-плагинов через pyo3-polars, превратив каждую операцию в нативное выражение, неотличимое от встроенного.

Плагин регистрируется на Python-стороне через register_plugin_function и @pl.api.register_expr_namespace, а с Rust-стороны — это функция с атрибутом #[polars_expr], принимающая &[Series] и возвращающая PolarsResult<Series>. Вся работа с Arrow и FFI генерируется макросом. Например, jq-фильтр компилируется один раз, а затем построчно заполняет ListStringChunkedBuilder. Выходной тип задаётся до выполнения: статический Float64 для метрик, DataType::List(String) для jq или вычисляемый из kwargs для dtypes.cast — так fenic подключает собственную систему логических типов, не ломая ленивое разрешение схемы.

Плагины работают напрямую с Arrow-массивами, минуя AnyValue и упаковку в питоновские объекты. Универсальный трейт ArrowToValue реализован для minijinja::Value и serde_json::Value, и один обходчик обрабатывает все физические представления строк — Utf8, LargeUtf8, Utf8View, а также вложенные Struct и List. Парсер транскриптов возвращает List<Struct> с полями index, speaker, start_time и так далее — результат легко развернуть через .unnest().

Все плагины объявлены с is_elementwise=True, что разрешает стриминг и оптимизации вроде предикатного пушдауна. Сборка — один cdylib-крейт, собираемый maturin, с жёстко завязанными версиями polars, pyo3-polars и Arrow: обновлять их можно только вместе, иначе ABI разъедется.

Главный выигрыш — композиция. Извлечь блоки кода из Markdown, отфильтровать через jq, привести к типизированной структуре — всё это одно выражение, которое Polars планирует и выполняет за один проход, без единого возврата в Python.

Читать оригинал →