Skip to content

Ingest accepts unbounded documents and inserts one chunk per round trip #13

Description

@royalpinto007

Problem

POST /documents accepts a document of unbounded size and indexes it one round trip at a time.

DocIn in app/main.py puts no limit on text:

class DocIn(BaseModel):
    id: str
    title: str
    source: str
    text: str

Compare AskRequest.question, which is carefully bounded: Field(min_length=1, max_length=2000). The bound was clearly considered on one side of the API and not the other.

Then ingest in app/ingest.py does:

vectors = embedder.embed([c.text for c in chunks])   # every chunk in one call
...
for c, vec in zip(chunks, vectors):
    await conn.execute("INSERT INTO chunks ...", (...))   # one round trip per chunk

A 20 MB document becomes roughly 17,000 chunks. Those are embedded in a single SentenceTransformer.encode call, so the full result set is materialized in memory at once, and then inserted with 17,000 sequential round trips inside a single transaction that holds locks on the document's rows the whole time. doc_acl inserts have the same one-at-a-time pattern in a loop.

Since the endpoint currently has no authentication (#5), this is reachable by anyone who can reach the service.

Suggested approach

  1. Bound the input. Add max_length to DocIn.text and title, and a maximum chunk count in ingest, returning a 413 with a clear message rather than trying and dying. Pick numbers deliberately and put them in app/config.py next to the other settings.
  2. Batch the embedding. Feed embedder.embed in fixed-size batches instead of one call per document, so memory is bounded by batch size rather than by document size.
  3. Batch the inserts. psycopg 3 has cursor.executemany with pipeline support, and COPY for the larger case. Either turns thousands of round trips into a handful.
  4. Same treatment for the doc_acl insert loop.
  5. Add a test that ingesting a document near the limit stays within a reasonable number of database round trips. Counting round trips is a fair proxy and is stable in CI, unlike timing.

Done when

  • Oversized documents are rejected with a clear error rather than accepted.
  • Chunk and ACL inserts do not scale as one round trip per row.
  • Embedding memory is bounded by a batch size constant, not by document size.
  • The limits are configurable and documented in .env.example and the README.

If you want to take this on, comment on the issue to claim it and it will be assigned. Please keep to a maximum of 2 open claims per person at a time so other contributors get a chance.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requesthelp wantedExtra attention is needed

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions