Skip to content

Find

The entry primitive: text in, a subgraph out. find is where a consumer that does not yet know an IRI gets a foothold, after which it traverses links like any other Linked Data client.

This chapter is new writing. It existed in the reference implementation only as a concept document, which mixes what is built with what is planned. What follows is the built half.

Status: descriptive. See ../../GOVERNANCE.md.

Error codes are index.md §5; the read downscope is lod-crud.md §3; what a caller may read is grants.md.

1. What find is

SPS-FIND-001find is a contract, not an algorithm. An implementation MUST be free to satisfy it with any engine — substring matching, a lexical index, vectors, query rewriting, or several at once — and a caller MUST NOT be required to select one.

SPS-FIND-002 — The request MUST NOT carry a mode, an engine name or a ranking strategy. A caller sends text.

The name is deliberate. search implies a ranked engine and a relevance model; find promises only to locate something and give the caller a starting point. Two implementations with entirely different engines can both satisfy this chapter, and a caller written against one works against the other.

SPS-FIND-003 — The response MUST be RDF: a subgraph the caller can merge into a working graph and traverse. An implementation MUST NOT answer with a bespoke result envelope in place of it.

The retrieval unit is a resource, not a text fragment. An event is one entity with all its properties, and every IRI-valued property is an exact traversal path — which is what lets a consumer follow the data instead of guessing at it.

2. The request

GET  {pod}/_system/find?text=…&type=…&context=…&include_contexts=…&limit=…
POST {pod}/_system/find   { "text": …, "type": […], "contexts": […], "include_contexts": …, "limit": … }

SPS-FIND-004 — An implementation MUST offer both forms, and they MUST be equivalent. The POST body mirrors the query parameters, with the context downscope named contexts.

The POST form exists for a request that no longer fits in a URL — most often a downscope naming many contexts.

SPS-FIND-005text is REQUIRED. It MAY be terms or a natural-language question, and how it is interpreted is the implementation's business.

SPS-FIND-006type is OPTIONAL, repeatable, and combines as OR. It MUST constrain the rdf:type of the returned hits.

SPS-FIND-007type MUST be matched exactly. An implementation MUST NOT apply subclass reasoning; a caller that wants subtypes lists them.

SPS-FIND-008type constrains what comes back, not where matching happens. An implementation MAY match through a linked resource and still return only the requested types.

rdf:type is the one structured facet in the core contract because every engine knows a resource's type cheaply. A general predicate filter is not part of it, and adding one would have to be fail-closed — a half-honoured filter reintroduces exactly the plausible-but-wrong result that structured retrieval exists to avoid.

SPS-FIND-009context (GET, repeatable) and contexts (POST) are the read downscope, with the semantics of SPS-CRUD-014 and SPS-CRUD-015: intersection with the readable set, unreadable entries dropped in silence.

SPS-FIND-010 — The downscope MUST apply to the whole operation, the expansion included. An implementation MUST NOT expand a hit with statements from a context outside it.

SPS-FIND-011limit is OPTIONAL. An implementation MUST apply a default and MUST enforce a maximum.

SPS-FIND-012 — There is no cursor and no pagination. An implementation MUST NOT require one to retrieve a complete answer within limit.

SPS-FIND-013 — A POST body MUST be parsed strictly. An unknown member MUST be rejected rather than ignored.

Ignoring an unknown member is how a caller's typo becomes a silently broader search. A rejected request is a bug report; an ignored filter is a data leak with a 200.

3. The sandbox

SPS-FIND-014 — The context sandbox MUST apply exactly as it does to CRUD and SPARQL. An anonymous caller sees the pod's public contexts; an authorized caller sees more. It is the same find, at a different depth.

SPS-FIND-015 — Where the caller can read nothing, or where the downscope resolves to nothing, the implementation MUST answer 200 with an empty graph. It MUST NOT answer 404 and MUST NOT answer 403.

This is where find deliberately differs from a resource read. A resource read answers 404 for an empty result, because "no such resource" and "not for you" have to be indistinguishable. A search that matched nothing is an answer, and a caller can act on it.

4. The response

SPS-FIND-016 — The response MUST contain the matched resources, and SHOULD expand each with at least its rdf:type and its label.

SPS-FIND-017 — An implementation MUST NOT return a full DESCRIBE-style expansion by default.

Expansion is a payload-size decision. Returning everything reachable turns a ten-hit answer into a transfer of most of the pod, and a caller that wants depth already holds the IRIs to ask for it.

SPS-FIND-018 — By default the response MUST be a flat graph: no ordering, no score, and no marker distinguishing a hit from an expansion. A caller MUST NOT infer rank from statement order.

SPS-FIND-019include_contexts=true MUST group the response by the context each statement came from — named-graph JSON-LD, or the fourth term in N-Quads. It MUST change only the representation, never which resources match.

SPS-FIND-020 — The response MUST be content-negotiated, with JSON-LD as the default and N-Quads available.

5. Caching

SPS-FIND-021 — A find response depends on the caller's readable contexts. An implementation MUST NOT allow a bearer-backed response to be stored in a shared cache without varying on the credential, and SHOULD mark such a response private.

A find result is a permission-shaped view of the pod. A shared cache that keys only on the URL serves one caller's depth to the next one.

6. Result metadata is reserved, not specified

The sempods vocabulary defines terms for per-hit metadata — which engine produced a hit, where it ranked, and the excerpt that matched. This chapter does not require them, because no implementation emits them.

They are recorded here so that an implementation does not mint competing terms for the same idea, and so that a later version of this chapter can specify them without a migration. Until then, SPS-FIND-018 is the contract: the response is flat.

SPS-FIND-022 — Per-hit metadata MUST NOT appear in the default response. An implementation MAY emit it only in a representation the client explicitly asked for, and this version of the specification defines no such request.

The reserved terms link a matched resource to its metadata node, and that link is a marker separating a hit from an expansion — exactly what SPS-FIND-018 forbids. A MAY that could be exercised in the default response would therefore have contradicted the flat-graph contract rather than extended it. The terms stay reserved; what has to arrive before they can be emitted is a negotiated representation to emit them in.

SPS-FIND-024 — Where such metadata is emitted, it is transient: it MUST NOT be written to the store, it MUST NOT appear in the named-graph grouping that include_contexts=true produces, and a caller MUST NOT expect to retrieve it again.

This does not weaken SPS-CTX-001, and the distinction is worth being exact about because the two look like they collide. That invariant governs statements a pod stores — every one of those belongs to exactly one context. A find response is a representation the server computes and hands over; the matched statements in it came from contexts and can be grouped by them, while a metadata node describes the response and was in no context to begin with. An implementation that stored one would be creating a statement with no context, which the invariant forbids — which is what MUST NOT be written to the store says.

SPS-FIND-023 — Authoritative facts about a hit — its types, its labels, its timestamps — MUST come from the store during expansion and MUST NOT be asserted by the metadata node.

The distinction is the same one contexts.md §6 makes for control-plane IRIs: what something is comes from whatever owns it, and what a response says about it is a claim with a narrower lifetime.