ReferenceField.labelSource is a single type name (schema.ts), but a reference whose range is a union cannot name one type. schema:creator ranges over Person | Organization, so whichever is declared, the other half resolves to nothing.
Measured on a real deployment (SCHEMA-AP-NDE over the Drapo dataset, labelSource: 'Person'): of 94 IRI-backed creator links, 48 point at a schema:Person and 46 at a schema:Organization. Those 46 come back with label: null even though the name is indexed and searchable in the organizations collection:
facets { creator { value label { value } count } }
{ "value": "https://id.drapo.nl/4b683486-…", "label": null, "count": 7 }
organizations(query: "Franciscanessen") { items { id label { value } } }
{ "id": "https://id.drapo.nl/4b683486-…", "label": [{ "value": "Zusters Franciscanessen – Missionarissen van Maria" }] }
The label exists; it is looked up in the wrong collection. Roughly half a facet renders as bare IRIs.
Proposal
Let labelSource accept several type names, tried in declaration order:
{ name: 'creator', kind: 'reference', labelSource: ['Person', 'Organization'], … }
Feasible on Typesense
No engine feature is needed – Typesense performs no join here. createTypesenseSearchEngine already resolves labels itself, per label-source collection, bundling a type’s distinct sources into a single lookup, behind a process-lifetime cache keyed per collection (search-typesense/src/search.ts:159-230, distinctLabelSources, cachedLabels). A field with several sources therefore adds no round trips beyond collections the engine already queries, and reuses the same per-collection cache entries. The change is that a field maps to a list of LabelSources instead of one, and the merge takes the first collection that has the id.
Precedence must be defined
An id can legitimately appear in more than one source collection. SCHEMA-AP-NDE co-types referenced persons and organizations as DefinedTerm, so in the deployment above one creator resolves in both:
people: 1 ['Koel, Frank'] terms: 1 ['Koel, Frank'] organizations: 0
Declaration order winning is deterministic, cheap and explainable; whatever the rule, it should be stated rather than left to collection iteration order.
Alternative considered
Declaring one reference field per range class (creatorPerson, creatorOrganization) splits one profile property across several API fields and pushes the union onto every consumer. Rejected.
ReferenceField.labelSourceis a single type name (schema.ts), but a reference whose range is a union cannot name one type.schema:creatorranges overPerson | Organization, so whichever is declared, the other half resolves to nothing.Measured on a real deployment (SCHEMA-AP-NDE over the Drapo dataset,
labelSource: 'Person'): of 94 IRI-backedcreatorlinks, 48 point at aschema:Personand 46 at aschema:Organization. Those 46 come back withlabel: nulleven though the name is indexed and searchable in theorganizationscollection:{ "value": "https://id.drapo.nl/4b683486-…", "label": null, "count": 7 }{ "id": "https://id.drapo.nl/4b683486-…", "label": [{ "value": "Zusters Franciscanessen – Missionarissen van Maria" }] }The label exists; it is looked up in the wrong collection. Roughly half a facet renders as bare IRIs.
Proposal
Let
labelSourceaccept several type names, tried in declaration order:Feasible on Typesense
No engine feature is needed – Typesense performs no join here.
createTypesenseSearchEnginealready resolves labels itself, per label-source collection, bundling a type’s distinct sources into a single lookup, behind a process-lifetime cache keyed per collection (search-typesense/src/search.ts:159-230,distinctLabelSources,cachedLabels). A field with several sources therefore adds no round trips beyond collections the engine already queries, and reuses the same per-collection cache entries. The change is that a field maps to a list ofLabelSources instead of one, and the merge takes the first collection that has the id.Precedence must be defined
An id can legitimately appear in more than one source collection. SCHEMA-AP-NDE co-types referenced persons and organizations as
DefinedTerm, so in the deployment above one creator resolves in both:Declaration order winning is deterministic, cheap and explainable; whatever the rule, it should be stated rather than left to collection iteration order.
Alternative considered
Declaring one reference field per range class (
creatorPerson,creatorOrganization) splits one profile property across several API fields and pushes the union onto every consumer. Rejected.