Skip to content

A welded co-element filter hangs Typesense when the nested fields hold arrays #798

Description

@ddeboer

The co-element filter #771 was built for – this agent in this rolehangs Typesense 30.2 indefinitely whenever the nested fields hold arrays, which is every document a qualified relation produces in practice.

Reproducer

One document, typesense/typesense:30.2, no LDE code in the path:

curl -XPOST 'http://localhost:8108/collections' -H 'X-TYPESENSE-API-KEY: dev' -d '{
  "name": "weld", "enable_nested_fields": true,
  "fields": [ {"name": "credits", "type": "object[]"},
              {"name": "credits.role", "type": "string[]"},
              {"name": "credits.agent_id", "type": "string[]"} ] }'

# array-valued nested fields
curl -XPOST 'http://localhost:8108/collections/weld/documents' -H 'X-TYPESENSE-API-KEY: dev' \
  -d '{"id": "w1", "credits": [{"role": ["etser"], "agent_id": ["p1"]}]}'

curl -G 'http://localhost:8108/collections/weld/documents/search' -H 'X-TYPESENSE-API-KEY: dev' \
  --data-urlencode 'q=*' --data-urlencode 'query_by=' \
  --data-urlencode 'filter_by=credits.{role:=etser && agent_id:=p1}'

The search never returns. The identical document with scalar nested values – {"role": "etser", "agent_id": "p1"} – answers 1 hit instantly, same schema and same filter.

What we narrowed it to

  • It is a hang, not a slow scan: 0.4 % CPU throughout, inflight_searches: 0 in the log, no response in 300 s. Other queries keep being served normally.
  • The trigger is the array inside each object, not the syntax, the field types or the values. These all answer in milliseconds: one condition inside the braces (either field); the two conditions joined outside the braces (credits.role:=etser && credits.agent_id:=p1); two string[] conditions welded over scalar-valued objects; and Typesense’s own documented example, ingredients.{name:=cheese && concentration:<50}, whose objects also hold scalars.
  • IRIs, backquoting and the partial-match operator make no difference.

The docs’ example holding scalars is presumably why the design work behind #771 cleared the query side against a live 30.2 container.

Why it reaches every real document

A qualified relation declares its edge fields array: true for good reasons – a role may be stated once per language, and the endpoint is multi-valued – so the projected entries hold arrays and the welded filter is unusable across the whole collection. Measured on a real index: creator.role:=fotograaf answers 46 works in 0.0 s, creator.creator_id:=<iri> answers 22 works in 0.0 s, and creator.{role:=fotograaf && creator_id:=<iri>} never returns. Through the GraphQL API that surfaces as Unexpected error, the 5 s Typesense timeout retried once.

So the data is fine – roles, agents and the resolved lookup are all indexed and readable, and either condition alone filters – but the weld itself, the one thing a nested edge buys over two flat fields, cannot be asked. Unwelded, role: fotograaf && creator: X still matches a work where X is the publisher and somebody else is the photographer.

Suggestion

The fix looks like Typesense’s: the syntax is documented and the input valid. What seems worth doing here is a note in #771’s documentation on which value shapes the capability can serve today, and – if it is worth dodging until Typesense fixes it – deciding whether a single-valued edge field should project a scalar rather than a one-element array.

Downstream context: https://codeberg.org/limburg/lol/issues/162.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions