|
| 1 | +# Arrow Flight De-identification |
| 2 | + |
| 3 | +OpenMed's Arrow Flight integration accepts a stream of Arrow record batches, |
| 4 | +de-identifies one configured string column, and returns each redacted batch as |
| 5 | +soon as it is processed. The service preserves the input schema, row count, |
| 6 | +nulls, and every non-target column. It never materializes the complete stream. |
| 7 | + |
| 8 | +Install the optional columnar dependency: |
| 9 | + |
| 10 | +```bash |
| 11 | +uv pip install -e ".[columnar]" |
| 12 | +``` |
| 13 | + |
| 14 | +## Start a Server |
| 15 | + |
| 16 | +```python |
| 17 | +from openmed.integrations.arrow_flight import ( |
| 18 | + ArrowFlightDeidentificationServer, |
| 19 | +) |
| 20 | + |
| 21 | +server = ArrowFlightDeidentificationServer( |
| 22 | + "grpc://127.0.0.1:8815", |
| 23 | + batch_size=512, |
| 24 | +) |
| 25 | +server.serve() |
| 26 | +``` |
| 27 | + |
| 28 | +`ArrowFlightDeidentificationServer` uses OpenMed's PII model and |
| 29 | +`process_batch(operation="deidentify")` by default. You can set server-wide |
| 30 | +defaults with `text_column=` and `policy=`, or select them per exchange in the |
| 31 | +Flight command descriptor. |
| 32 | + |
| 33 | +## Exchange Record Batches |
| 34 | + |
| 35 | +```python |
| 36 | +import pyarrow as pa |
| 37 | +import pyarrow.flight as flight |
| 38 | + |
| 39 | +from openmed.integrations.arrow_flight import make_deidentify_descriptor |
| 40 | + |
| 41 | +client = flight.connect("grpc://127.0.0.1:8815") |
| 42 | +descriptor = make_deidentify_descriptor( |
| 43 | + "clinical_note", |
| 44 | + policy="hipaa_safe_harbor", |
| 45 | +) |
| 46 | +writer, reader = client.do_exchange(descriptor) |
| 47 | + |
| 48 | +schema = pa.schema( |
| 49 | + [ |
| 50 | + ("record_id", pa.int64()), |
| 51 | + ("clinical_note", pa.string()), |
| 52 | + ("status", pa.string()), |
| 53 | + ] |
| 54 | +) |
| 55 | +writer.begin(schema) |
| 56 | + |
| 57 | +for input_batch in source_batches: |
| 58 | + writer.write_batch(input_batch) |
| 59 | + output_batch = reader.read_chunk().data |
| 60 | + consume(output_batch) |
| 61 | + |
| 62 | +writer.done_writing() |
| 63 | +``` |
| 64 | + |
| 65 | +The helper creates a versioned JSON `FlightDescriptor` command. For |
| 66 | +`DoExchange`, the descriptor is the request-metadata channel; its policy takes |
| 67 | +precedence over a server default. Keeping configuration in the descriptor lets |
| 68 | +one server apply different OpenMed policy profiles without mixing raw clinical |
| 69 | +cells into RPC metadata. |
| 70 | + |
| 71 | +## Privacy and Streaming Contract |
| 72 | + |
| 73 | +- Each incoming `RecordBatch` is passed to `process_batch` and returned before |
| 74 | + the server reads the entire stream. |
| 75 | +- Only the target string column is converted to Python values for redaction. |
| 76 | + All other Arrow arrays are passed through unchanged. |
| 77 | +- Response batches retain the input schema and number of rows, including null |
| 78 | + placement. |
| 79 | +- The service does not log raw or redacted cell values. Errors identify only |
| 80 | + the column and row position. |
| 81 | +- The command descriptor must not contain patient data. It is only for the |
| 82 | + text-column name, policy name, and descriptor version. |
| 83 | + |
| 84 | +## Authentication and TLS Hooks |
| 85 | + |
| 86 | +The server constructor forwards Arrow Flight's `auth_handler`, |
| 87 | +`tls_certificates`, `verify_client`, `root_certificates`, and `middleware` |
| 88 | +options. These are deployment hooks, not a complete security policy. Production |
| 89 | +operators remain responsible for certificate management, authentication design, |
| 90 | +network isolation, and authorization. |
0 commit comments