blob: 7d3bb97637be46054366e79975462abd939294a4 [file]
import ctypes
from ctypes import c_char_p, c_void_p
from ._ffi import (
FLUSH_FN,
WRITE_FN,
PaimonFtindexOutputFile,
check_ptr,
check_status,
lib,
)
class FullTextIndexWriter:
def __init__(self, options=None):
options = options or {}
self._closed = False
self._output_refs = None
keys = [str(k).encode("utf-8") for k in options.keys()]
values = [str(v).encode("utf-8") for v in options.values()]
key_array = (c_char_p * len(keys))(*keys) if keys else None
value_array = (c_char_p * len(values))(*values) if values else None
self._ptr = check_ptr(
lib.paimon_ftindex_writer_open(key_array, value_array, len(keys))
)
def add_document(self, row_id, text, column=None):
if self._closed:
raise RuntimeError("FullTextIndexWriter is closed")
if isinstance(text, dict):
if column is not None:
raise ValueError("column must not be set when text is a dict")
self.add_document_fields(row_id, text)
return
if column is not None:
self.add_document_fields(row_id, [(column, text)])
return
check_status(
lib.paimon_ftindex_writer_add_document(
self._ptr, int(row_id), str(text).encode("utf-8")
)
)
def add_document_fields(self, row_id, fields):
if self._closed:
raise RuntimeError("FullTextIndexWriter is closed")
items = list(fields.items()) if hasattr(fields, "items") else list(fields)
if not items:
raise ValueError("document fields must not be empty")
names = [str(name).encode("utf-8") for name, _ in items]
texts = [str(text).encode("utf-8") for _, text in items]
name_array = (c_char_p * len(names))(*names)
text_array = (c_char_p * len(texts))(*texts)
check_status(
lib.paimon_ftindex_writer_add_document_fields(
self._ptr, int(row_id), name_array, text_array, len(items)
)
)
def write(self, output):
if self._closed:
raise RuntimeError("FullTextIndexWriter is closed")
@WRITE_FN
def write_fn(ctx, buf, length):
try:
data = ctypes.string_at(buf, length)
output.write(data)
return 0
except Exception:
return -1
@FLUSH_FN
def flush_fn(ctx):
try:
flush = getattr(output, "flush", None)
if flush is not None:
flush()
return 0
except Exception:
return -1
self._output_refs = (write_fn, flush_fn)
native_output = PaimonFtindexOutputFile(
c_void_p(0),
write_fn,
flush_fn,
)
check_status(lib.paimon_ftindex_writer_write_index(self._ptr, native_output))
def close(self):
if not self._closed:
self._closed = True
if self._ptr:
lib.paimon_ftindex_writer_free(self._ptr)
self._ptr = None
def __enter__(self):
return self
def __exit__(self, exc_type, exc, tb):
self.close()
def __del__(self):
self.close()