Skip to content

BE-471, BE-621: Add dedicated embedding search endpoints for entities and entity types#8910

Merged
TimDiekmann merged 4 commits into
mainfrom
t/be-621-support-pagination-for-distance-based-search-queries
Jun 29, 2026
Merged

BE-471, BE-621: Add dedicated embedding search endpoints for entities and entity types#8910
TimDiekmann merged 4 commits into
mainfrom
t/be-621-support-pagination-for-distance-based-search-queries

Conversation

@TimDiekmann

Copy link
Copy Markdown
Member

🌟 What is the purpose of this PR?

Adds dedicated embedding-similarity search endpoints for entities and entity types. Previously, semantic search was done by passing a cosineDistance filter through the generic query endpoints, rewritten client-side (rewriteSemanticFilter). That approach is replaced by first-class search endpoints that compute the embedding (from a semanticString), apply a validated maximum-distance threshold, and return results ordered by ascending cosine distance.

🔗 Related links

  • Linear: BE-621 (internal)
  • Follow-ups: BE-618 (vector-index-friendly query), BE-622 (move embedding computation into the graph), BE-624 (restore semantic search on the GPT endpoints) (internal)

🚫 Blocked by

  • none

🔍 What does this change?

  • New REST endpoints POST /entities/search and POST /entity-types/search on the graph API, with SearchEntitiesRequest / SearchEntityTypesRequest bodies converted via into_params.
  • New store-trait methods EntityStore::search_entities / EntityTypeStore::search_entity_types + Postgres impls (build a CosineDistance filter, run against current time, exclude archived entities; delegate to the existing query path).
  • SemanticDistance newtype (finite, within [0, 2]) enforcing the threshold invariant at the store layer; an invalid distance or over-limit request surfaces a typed SearchRequestError422.
  • Removed the public cosineDistance filter (#[serde(skip)] + OpenAPI), and the client-side rewriteSemanticFilter (replaced by calculateEmbedding); queryEntities / queryEntitySubgraph no longer take a temporalClient.
  • TS SDK: searchEntities / searchEntityTypes (+ serialize/deserialize helpers), GraphQL resolvers/typedefs/queries, and the frontend search bar migrated to the new endpoints.
  • GPT query-entities / query-types endpoints: semantic search is temporarily disabled — the query field is accepted but ignored (tracked in BE-624).

Pre-Merge Checklist 🚀

🚢 Has this modified a publishable library?

This PR:

  • does not modify any publishable blocks or libraries, or modifications do not need publishing

📜 Does this require a change to the docs?

The changes in this PR:

  • are internal and do not require a docs change

🕸️ Does this require a change to the Turbo Graph?

The changes in this PR:

  • do not affect the execution graph

⚠️ Known issues

  • No pagination. Results are limit-only; distance-ordered pagination over an ANN/HNSW index is non-trivial and out of scope for this PR (the ticket was refocused accordingly).
  • Unindexed scan. The query scans embeddings without a vector index (MIN(<=> ) GROUP BY shape) — tracked in BE-618.
  • Removed capabilities (BE-624): semantic search on the GPT query-entities/query-types endpoints, and on data-type / property-type queries, is removed for now (no dedicated search endpoint exists for those).

🐾 Next steps

  • BE-618: vector-index-friendly query shape (HNSW).
  • BE-622: move embedding computation into the graph so callers don't need a Temporal client.
  • BE-624: migrate the GPT endpoints to the dedicated search endpoints.

🛡 What tests cover this?

  • Rust unit tests for the SemanticDistance boundary (0, 2, out-of-range, NaN, ±inf).
  • TS serialize/deserialize round-trip for the search response.
  • HTTP tests (friendship.http) migrated to the new endpoints.
  • Gap: no dedicated Rust integration tests yet for distance ordering / scope filters (entityTypeIds / webIds / includeDrafts) / archived exclusion — the underlying query path is covered transitively, but a focused integration test is a sensible follow-up.

❓ How to test this?

  1. Start the graph + API.
  2. Call searchEntities / searchEntityTypes (SDK/GraphQL) with a semanticString, maximumSemanticDistance, and limit.
  3. Confirm results come back ordered by ascending cosine distance, and that a maximumSemanticDistance outside [0, 2] returns a 422.
  4. Use the frontend search bar (now backed by the new endpoints) and confirm entity + entity-type results.

…ity types

Add specialized `searchEntities` / `searchEntityTypes` endpoints (REST, GraphQL,
and TypeScript SDK) for cosine-distance semantic search, replacing the generic
`cosineDistance` filter path. The interface is intentionally narrow: a required
maximum semantic distance bounded to [0, 2], a capped limit, an exclusive
embedding/semanticString input, and a typed filter (entity type ids, web ids,
drafts). Results are pinned to the current time and never include archived
entities.

Make `Filter::CosineDistance` non-deserializable (`#[serde(skip)]`) so it can no
longer be injected through the generic query endpoints.

Migrate the frontend search bar and the AI worker's find-existing-entity to the
new endpoints. Semantic search in the GPT query endpoints is disabled for now
(TODO BE-624). Optimizing the query shape and indexing is deferred to BE-618.
endpoints

Follow-up to the embedding search endpoints, addressing review feedback:

- Add a `SemanticDistance` newtype (finite, within [0, 2]) in the graph
  store
  and use it on the search param types, so the invariant holds at the
  store
  layer regardless of the caller.
- Validate the distance and limit when converting the REST request
  bodies in
  `into_params`, surfacing a typed `SearchRequestError` (422) instead of
  an
  ad-hoc pre-check, and add `SearchEntityTypesRequest::into_params` for
  symmetry with the entity endpoint.
- Clarify the GPT `query` TODO: the field is currently accepted but
  ignored
  (BE-624).
- Add unit tests for the distance boundary (including NaN/±inf) and a
  serialize/deserialize round-trip for the search response.
Copilot AI review requested due to automatic review settings June 28, 2026 22:24
@vercel

vercel Bot commented Jun 28, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
hash Ready Ready Preview, Comment Jun 29, 2026 9:40am
2 Skipped Deployments
Project Deployment Actions Updated (UTC)
hashdotdesign-tokens Ignored Ignored Preview Jun 29, 2026 9:40am
petrinaut Skipped Skipped Jun 29, 2026 9:40am

@cursor

cursor Bot commented Jun 28, 2026

Copy link
Copy Markdown

PR Summary

Medium Risk
Broad surface area (REST, store, SDK, GraphQL, search UI) plus a behavioral regression where GPT semantic query is ignored; embedding search still relies on unindexed scans noted in BE-618.

Overview
Introduces first-class semantic search via POST /entities/search and POST /entity-types/search, wired through the store layer, TS SDK, GraphQL, and the frontend search bar. Callers pass an embedding or semanticString (SDK still embeds via Temporal), a validated maximumSemanticDistance, and optional scope filters; results are ordered by ascending cosine distance.

Removes public cosineDistance from generic query filters (OpenAPI + serde) and deletes client-side rewriteSemanticFilter. queryEntities / queryEntitySubgraph no longer accept a Temporal client for filter rewriting. Entity deduplication in the AI worker now uses searchEntities instead of hand-built cosine filters.

GPT query-entities / query-types: the query body field is still accepted but ignored until those routes call the new search endpoints (BE-624).

Adds SemanticDistance validation, serialize/deserialize helpers for search responses, and SearchRequestError for bad limits or distance thresholds.

Reviewed by Cursor Bugbot for commit 612b898. Bugbot is set up for automated code reviews on this repo. Configure here.

@github-actions github-actions Bot added area/apps > hash* Affects HASH (a `hash-*` app) area/apps > hash-api Affects the HASH API (app) area/libs Relates to first-party libraries/crates/packages (area) type/eng > frontend Owned by the @frontend team type/eng > backend Owned by the @backend team area/tests New or updated tests area/apps labels Jun 28, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds first-class embedding-similarity search for entities and entity types across the Graph REST API, store layer, GraphQL surface area, and TypeScript SDK/frontend, replacing the prior client-side cosineDistance filter rewriting approach.

Changes:

  • Introduces POST /entities/search and POST /entity-types/search plus corresponding store trait methods and Postgres implementations using an internal CosineDistance filter.
  • Adds a validated SemanticDistance newtype (range [0, 2]) and removes public exposure of the cosineDistance filter from OpenAPI/serde.
  • Updates GraphQL + TS SDK + frontend search bar + AI worker to use the new dedicated search endpoints; temporarily disables semantic search in GPT query endpoints.

Reviewed changes

Copilot reviewed 32 out of 33 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
tests/graph/integration/postgres/lib.rs Wires new store search methods through the integration test DB API wrapper.
libs/@local/hash-isomorphic-utils/src/graphql/type-defs/ontology/entity-type.typedef.ts Adds GraphQL scalar + query field for searchEntityTypes.
libs/@local/hash-isomorphic-utils/src/graphql/type-defs/knowledge/entity.typedef.ts Adds GraphQL scalar + query field for searchEntities.
libs/@local/hash-isomorphic-utils/src/graphql/scalar-mapping.ts Maps new GraphQL scalars to SDK request/response types.
libs/@local/hash-isomorphic-utils/src/graphql/queries/entity.queries.ts Adds searchEntities GraphQL query document.
libs/@local/hash-backend-utils/src/flows.ts Removes semantic-filter rewriting now that generic queries no longer support it.
libs/@local/graph/type-fetcher/src/store.rs Exposes new search methods through the type-fetcher store wrapper.
libs/@local/graph/store/src/filter/semantic_distance.rs Adds validated SemanticDistance and unit tests for boundaries/non-finite values.
libs/@local/graph/store/src/filter/mod.rs Exports SemanticDistance and hides CosineDistance from serde.
libs/@local/graph/store/src/entity/store.rs Adds EntityStore::search_entities params/response/filter types and trait method.
libs/@local/graph/store/src/entity/mod.rs Re-exports the new entity search types.
libs/@local/graph/store/src/entity_type/store.rs Adds EntityTypeStore::search_entity_types params/response types and trait method.
libs/@local/graph/store/src/entity_type/mod.rs Re-exports the new entity-type search types.
libs/@local/graph/sdk/typescript/tests/entity.test.ts Adds serialization round-trip test for SearchEntitiesResponse.
libs/@local/graph/sdk/typescript/src/entity.ts Adds searchEntities, request/response types, and serialize/deserialize helpers; removes semantic rewrite in query paths.
libs/@local/graph/sdk/typescript/src/entity-type.ts Adds searchEntityTypes and request/response types, with optional embedding computation via Temporal.
libs/@local/graph/sdk/typescript/src/embeddings.ts Replaces filter rewriting with calculateEmbedding(semanticString, temporalClient).
libs/@local/graph/postgres-store/src/store/postgres/ontology/entity_type.rs Implements search_entity_types via CosineDistance filter and current-time query.
libs/@local/graph/postgres-store/src/store/postgres/knowledge/entity/mod.rs Implements search_entities via CosineDistance + scope filters + archived exclusion.
libs/@local/graph/api/src/rest/mod.rs Adds SearchRequestError and removes CosineDistanceFilter from OpenAPI filter schema addon.
libs/@local/graph/api/src/rest/entity.rs Adds /entities/search REST route + handler and improves invalid-argument status attachment.
libs/@local/graph/api/src/rest/entity_type.rs Adds /entity-types/search REST route + handler and request-to-params conversion.
libs/@local/graph/api/src/rest/entity_query_request.rs Adds REST request struct for entity search and conversion to store params.
libs/@local/graph/api/openapi/openapi.json Adds OpenAPI paths/schemas for the new search endpoints and removes cosineDistance filter schema.
apps/hash-frontend/src/shared/layout/layout-with-header/search-bar.tsx Migrates the frontend search bar to the new GraphQL search queries and closed-type map usage.
apps/hash-frontend/src/graphql/queries/ontology/entity-type.queries.ts Adds searchEntityTypes GraphQL query document for the frontend.
apps/hash-api/src/graphql/resolvers/ontology/entity-type.ts Adds GraphQL resolver for searchEntityTypes calling the SDK.
apps/hash-api/src/graphql/resolvers/knowledge/entity/entity.ts Adds GraphQL resolver for searchEntities calling the SDK and serializing the response.
apps/hash-api/src/graphql/resolvers/index.ts Registers new GraphQL resolvers for entity/entity-type search.
apps/hash-api/src/ai/gpt/gpt-query-types.ts Temporarily disables semantic search on GPT type querying (accepts but ignores query).
apps/hash-api/src/ai/gpt/gpt-query-entities.ts Temporarily disables semantic search on GPT entity querying (accepts but ignores query).
apps/hash-ai-worker-ts/src/activities/shared/find-existing-entity.ts Migrates semantic matching to searchEntities instead of cosineDistance filters.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread libs/@local/graph/api/src/rest/entity_query_request.rs
Comment thread libs/@local/graph/api/src/rest/entity_type.rs
Comment thread libs/@local/graph/api/src/rest/entity_query_request.rs
Comment thread libs/@local/graph/api/src/rest/entity_type.rs
Copilot AI review requested due to automatic review settings June 28, 2026 22:31
@TimDiekmann TimDiekmann changed the title BE-621: Add dedicated embedding search endpoints for entities and entity types BE-471, BE-621: Add dedicated embedding search endpoints for entities and entity types Jun 28, 2026
@codecov

codecov Bot commented Jun 28, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 17.80822% with 120 lines in your changes missing coverage. Please review.
✅ Project coverage is 59.75%. Comparing base (b8f5e58) to head (612b898).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
libs/@local/graph/api/src/rest/entity_type.rs 0.00% 40 Missing ⚠️
libs/@local/graph/api/src/rest/entity.rs 0.00% 28 Missing ⚠️
.../@local/graph/api/src/rest/entity_query_request.rs 0.00% 14 Missing ⚠️
...ibs/@local/graph/sdk/typescript/src/entity-type.ts 11.11% 8 Missing ⚠️
...r-ts/src/activities/shared/find-existing-entity.ts 0.00% 7 Missing ⚠️
...s-store/src/store/postgres/knowledge/entity/mod.rs 0.00% 7 Missing ⚠️
...s-store/src/store/postgres/ontology/entity_type.rs 0.00% 7 Missing ⚠️
libs/@local/graph/sdk/typescript/src/embeddings.ts 20.00% 4 Missing ⚠️
...i/src/graphql/resolvers/knowledge/entity/entity.ts 0.00% 2 Missing ⚠️
...-api/src/graphql/resolvers/ontology/entity-type.ts 0.00% 2 Missing ⚠️
... and 1 more
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #8910      +/-   ##
==========================================
- Coverage   59.77%   59.75%   -0.02%     
==========================================
  Files        1348     1349       +1     
  Lines      131787   132019     +232     
  Branches     5941     5935       -6     
==========================================
+ Hits        78772    78892     +120     
- Misses      52107    52220     +113     
+ Partials      908      907       -1     
Flag Coverage Δ
apps.hash-ai-worker-ts 1.39% <0.00%> (+<0.01%) ⬆️
apps.hash-api 3.26% <0.00%> (+<0.01%) ⬆️
local.hash-backend-utils 2.82% <ø> (+<0.01%) ⬆️
local.hash-graph-sdk 10.00% <14.28%> (+0.36%) ⬆️
local.hash-isomorphic-utils 0.18% <ø> (-0.01%) ⬇️
rust.hash-graph-api 2.49% <0.00%> (-0.04%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 32 out of 33 changed files in this pull request and generated 6 comments.

Comment thread libs/@local/graph/api/src/rest/entity.rs
Comment thread libs/@local/graph/api/src/rest/entity_type.rs
Comment thread libs/@local/graph/api/openapi/openapi.json Outdated
Comment thread libs/@local/graph/api/openapi/openapi.json Outdated
Comment thread libs/@local/graph/api/src/rest/entity_type.rs
Comment thread libs/@local/graph/api/src/rest/entity_query_request.rs
@github-actions

Copy link
Copy Markdown
Contributor

Benchmark results

@rust/hash-graph-benches – Integrations

policy_resolution_large

Function Value Mean Flame graphs
resolve_policies_for_actor user: empty, selectivity: high, policies: 2002 $$26.8 \mathrm{ms} \pm 196 \mathrm{μs}\left({\color{gray}0.678 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$3.32 \mathrm{ms} \pm 20.4 \mathrm{μs}\left({\color{gray}-3.685 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 1002 $$11.9 \mathrm{ms} \pm 111 \mathrm{μs}\left({\color{gray}0.467 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: high, policies: 3314 $$41.3 \mathrm{ms} \pm 401 \mathrm{μs}\left({\color{gray}-0.854 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: low, policies: 1 $$13.4 \mathrm{ms} \pm 114 \mathrm{μs}\left({\color{lightgreen}-6.048 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: medium, policies: 1527 $$22.8 \mathrm{ms} \pm 177 \mathrm{μs}\left({\color{gray}0.344 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 2078 $$27.5 \mathrm{ms} \pm 198 \mathrm{μs}\left({\color{gray}0.364 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$3.63 \mathrm{ms} \pm 30.2 \mathrm{μs}\left({\color{gray}-2.983 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 1033 $$12.9 \mathrm{ms} \pm 123 \mathrm{μs}\left({\color{gray}0.375 \mathrm{\%}}\right) $$ Flame Graph

policy_resolution_medium

Function Value Mean Flame graphs
resolve_policies_for_actor user: empty, selectivity: high, policies: 102 $$3.68 \mathrm{ms} \pm 18.9 \mathrm{μs}\left({\color{gray}-0.394 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$2.87 \mathrm{ms} \pm 10.7 \mathrm{μs}\left({\color{gray}-0.884 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 52 $$3.24 \mathrm{ms} \pm 15.6 \mathrm{μs}\left({\color{gray}-0.782 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: high, policies: 269 $$5.04 \mathrm{ms} \pm 34.2 \mathrm{μs}\left({\color{gray}0.767 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: low, policies: 1 $$3.41 \mathrm{ms} \pm 17.8 \mathrm{μs}\left({\color{gray}-0.161 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: medium, policies: 108 $$4.00 \mathrm{ms} \pm 24.8 \mathrm{μs}\left({\color{gray}0.086 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 133 $$4.30 \mathrm{ms} \pm 29.6 \mathrm{μs}\left({\color{gray}0.679 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$3.32 \mathrm{ms} \pm 18.2 \mathrm{μs}\left({\color{gray}0.291 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 63 $$3.99 \mathrm{ms} \pm 28.6 \mathrm{μs}\left({\color{gray}1.38 \mathrm{\%}}\right) $$ Flame Graph

policy_resolution_none

Function Value Mean Flame graphs
resolve_policies_for_actor user: empty, selectivity: high, policies: 2 $$2.58 \mathrm{ms} \pm 15.1 \mathrm{μs}\left({\color{gray}3.31 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$2.44 \mathrm{ms} \pm 14.5 \mathrm{μs}\left({\color{gray}0.836 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 2 $$2.58 \mathrm{ms} \pm 19.1 \mathrm{μs}\left({\color{gray}3.42 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 8 $$2.83 \mathrm{ms} \pm 16.5 \mathrm{μs}\left({\color{gray}3.17 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$2.63 \mathrm{ms} \pm 16.9 \mathrm{μs}\left({\color{gray}2.33 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 3 $$2.80 \mathrm{ms} \pm 15.2 \mathrm{μs}\left({\color{gray}2.67 \mathrm{\%}}\right) $$ Flame Graph

policy_resolution_small

Function Value Mean Flame graphs
resolve_policies_for_actor user: empty, selectivity: high, policies: 52 $$2.93 \mathrm{ms} \pm 16.4 \mathrm{μs}\left({\color{gray}-0.763 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$2.63 \mathrm{ms} \pm 14.6 \mathrm{μs}\left({\color{gray}-0.727 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 26 $$2.87 \mathrm{ms} \pm 15.3 \mathrm{μs}\left({\color{gray}-0.661 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: high, policies: 94 $$3.34 \mathrm{ms} \pm 30.1 \mathrm{μs}\left({\color{gray}-0.253 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: low, policies: 1 $$2.89 \mathrm{ms} \pm 16.7 \mathrm{μs}\left({\color{gray}-0.084 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: medium, policies: 27 $$3.18 \mathrm{ms} \pm 19.4 \mathrm{μs}\left({\color{gray}-0.288 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 66 $$3.26 \mathrm{ms} \pm 15.5 \mathrm{μs}\left({\color{gray}-0.444 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$2.83 \mathrm{ms} \pm 14.8 \mathrm{μs}\left({\color{gray}0.078 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 29 $$3.20 \mathrm{ms} \pm 18.8 \mathrm{μs}\left({\color{gray}-0.952 \mathrm{\%}}\right) $$ Flame Graph

read_scaling_complete

Function Value Mean Flame graphs
entity_by_id;one_depth 1 entities $$40.2 \mathrm{ms} \pm 260 \mathrm{μs}\left({\color{gray}0.184 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 10 entities $$30.9 \mathrm{ms} \pm 164 \mathrm{μs}\left({\color{gray}0.246 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 25 entities $$33.8 \mathrm{ms} \pm 189 \mathrm{μs}\left({\color{gray}0.518 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 5 entities $$30.6 \mathrm{ms} \pm 241 \mathrm{μs}\left({\color{gray}2.96 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 50 entities $$39.6 \mathrm{ms} \pm 224 \mathrm{μs}\left({\color{gray}1.37 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 1 entities $$47.7 \mathrm{ms} \pm 284 \mathrm{μs}\left({\color{gray}0.759 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 10 entities $$37.8 \mathrm{ms} \pm 266 \mathrm{μs}\left({\color{gray}-0.299 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 25 entities $$88.3 \mathrm{ms} \pm 568 \mathrm{μs}\left({\color{gray}-0.411 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 5 entities $$31.6 \mathrm{ms} \pm 168 \mathrm{μs}\left({\color{lightgreen}-15.331 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 50 entities $$248 \mathrm{ms} \pm 995 \mathrm{μs}\left({\color{lightgreen}-16.028 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 1 entities $$10.00 \mathrm{ms} \pm 64.1 \mathrm{μs}\left({\color{gray}0.286 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 10 entities $$10.2 \mathrm{ms} \pm 71.1 \mathrm{μs}\left({\color{gray}0.645 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 25 entities $$10.1 \mathrm{ms} \pm 54.5 \mathrm{μs}\left({\color{gray}-0.048 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 5 entities $$10.0 \mathrm{ms} \pm 64.3 \mathrm{μs}\left({\color{gray}0.041 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 50 entities $$10.1 \mathrm{ms} \pm 62.6 \mathrm{μs}\left({\color{gray}1.42 \mathrm{\%}}\right) $$ Flame Graph

read_scaling_linkless

Function Value Mean Flame graphs
entity_by_id 1 entities $$10.00 \mathrm{ms} \pm 76.2 \mathrm{μs}\left({\color{gray}0.499 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 10 entities $$9.96 \mathrm{ms} \pm 63.8 \mathrm{μs}\left({\color{gray}-0.355 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 100 entities $$9.98 \mathrm{ms} \pm 60.6 \mathrm{μs}\left({\color{gray}-0.279 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 1000 entities $$10.1 \mathrm{ms} \pm 69.0 \mathrm{μs}\left({\color{gray}0.504 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 10000 entities $$10.2 \mathrm{ms} \pm 62.0 \mathrm{μs}\left({\color{gray}0.875 \mathrm{\%}}\right) $$ Flame Graph

representative_read_entity

Function Value Mean Flame graphs
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/block/v/1 $$10.4 \mathrm{ms} \pm 63.7 \mathrm{μs}\left({\color{gray}0.863 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/book/v/1 $$10.6 \mathrm{ms} \pm 90.8 \mathrm{μs}\left({\color{gray}2.29 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/building/v/1 $$10.4 \mathrm{ms} \pm 52.2 \mathrm{μs}\left({\color{gray}0.279 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/organization/v/1 $$10.4 \mathrm{ms} \pm 69.3 \mathrm{μs}\left({\color{gray}-0.370 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/page/v/2 $$10.4 \mathrm{ms} \pm 56.6 \mathrm{μs}\left({\color{gray}-0.343 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/person/v/1 $$10.4 \mathrm{ms} \pm 60.8 \mathrm{μs}\left({\color{gray}1.06 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/playlist/v/1 $$10.4 \mathrm{ms} \pm 58.6 \mathrm{μs}\left({\color{gray}0.754 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/song/v/1 $$10.3 \mathrm{ms} \pm 51.9 \mathrm{μs}\left({\color{gray}-0.576 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/uk-address/v/1 $$10.4 \mathrm{ms} \pm 58.6 \mathrm{μs}\left({\color{gray}1.03 \mathrm{\%}}\right) $$ Flame Graph

representative_read_entity_type

Function Value Mean Flame graphs
get_entity_type_by_id Account ID: bf5a9ef5-dc3b-43cf-a291-6210c0321eba $$8.10 \mathrm{ms} \pm 44.2 \mathrm{μs}\left({\color{gray}-1.522 \mathrm{\%}}\right) $$ Flame Graph

representative_read_multiple_entities

Function Value Mean Flame graphs
entity_by_property traversal_paths=0 0 $$54.1 \mathrm{ms} \pm 466 \mathrm{μs}\left({\color{gray}0.003 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=255 1,resolve_depths=inherit:1;values:255;properties:255;links:127;link_dests:126;type:true $$103 \mathrm{ms} \pm 463 \mathrm{μs}\left({\color{gray}-0.111 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:0;links:0;link_dests:0;type:false $$59.1 \mathrm{ms} \pm 507 \mathrm{μs}\left({\color{gray}0.560 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:0;links:1;link_dests:0;type:true $$68.1 \mathrm{ms} \pm 600 \mathrm{μs}\left({\color{gray}-0.647 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:2;links:1;link_dests:0;type:true $$76.1 \mathrm{ms} \pm 452 \mathrm{μs}\left({\color{gray}-0.524 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:2;properties:2;links:1;link_dests:0;type:true $$83.3 \mathrm{ms} \pm 509 \mathrm{μs}\left({\color{gray}0.476 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=0 0 $$41.4 \mathrm{ms} \pm 282 \mathrm{μs}\left({\color{gray}-0.169 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=255 1,resolve_depths=inherit:1;values:255;properties:255;links:127;link_dests:126;type:true $$70.1 \mathrm{ms} \pm 420 \mathrm{μs}\left({\color{gray}-0.682 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:0;links:0;link_dests:0;type:false $$47.9 \mathrm{ms} \pm 280 \mathrm{μs}\left({\color{gray}0.393 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:0;links:1;link_dests:0;type:true $$57.2 \mathrm{ms} \pm 503 \mathrm{μs}\left({\color{gray}0.575 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:2;links:1;link_dests:0;type:true $$59.1 \mathrm{ms} \pm 347 \mathrm{μs}\left({\color{gray}-0.842 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:2;properties:2;links:1;link_dests:0;type:true $$59.7 \mathrm{ms} \pm 494 \mathrm{μs}\left({\color{gray}0.287 \mathrm{\%}}\right) $$

scenarios

Function Value Mean Flame graphs
full_test query-limited $$121 \mathrm{ms} \pm 627 \mathrm{μs}\left({\color{red}6.24 \mathrm{\%}}\right) $$ Flame Graph
full_test query-unlimited $$133 \mathrm{ms} \pm 605 \mathrm{μs}\left({\color{red}6.77 \mathrm{\%}}\right) $$ Flame Graph
linked_queries query-limited $$17.7 \mathrm{ms} \pm 163 \mathrm{μs}\left({\color{gray}1.14 \mathrm{\%}}\right) $$ Flame Graph
linked_queries query-unlimited $$536 \mathrm{ms} \pm 1.09 \mathrm{ms}\left({\color{gray}2.11 \mathrm{\%}}\right) $$ Flame Graph

@TimDiekmann TimDiekmann added this pull request to the merge queue Jun 29, 2026
Merged via the queue into main with commit 7ca1abf Jun 29, 2026
92 checks passed
@TimDiekmann TimDiekmann deleted the t/be-621-support-pagination-for-distance-based-search-queries branch June 29, 2026 18:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/apps > hash* Affects HASH (a `hash-*` app) area/apps > hash-api Affects the HASH API (app) area/apps area/libs Relates to first-party libraries/crates/packages (area) area/tests New or updated tests type/eng > backend Owned by the @backend team type/eng > frontend Owned by the @frontend team

Development

Successfully merging this pull request may close these issues.

3 participants