{"id":"ops/search-graph-provisioning","relativePath":"ops/search-graph-provisioning.md","title":"Solr 9 + GraphDB Provisioning","markdown":"# Solr 9 + GraphDB Provisioning\n\nThis runbook provisions the Era C1 search/graph stack:\n\n- Solr 9 (LUX-aligned search/faceting path)\n- GraphDB CE (Ontotext OSS path)\n\nFor local trace export wiring (Tempo / Jaeger), see `docs/ops/otel-local.md`.\n\n## Dev runtime (Docker Compose)\n\nCompose stack file: `ops/docker-compose.yml`\n\n- Postgres stays in the default profile (`pnpm db:up`).\n- Solr + GraphDB are in the `sota` profile (`pnpm infra:sota:up`).\n\nCommands:\n\n```bash\npnpm infra:sota:up\npnpm infra:sota:down\n```\n\nExposed ports:\n\n- Solr: `http://localhost:8983/solr`\n- GraphDB: `http://localhost:7200`\n\nImages:\n\n- `solr:9.6`\n- `ontotext/graphdb:10.8.14` (GraphDB CE path via license-less default runtime)\n\n## Kubernetes runtime (Helm)\n\nChart path:\n\n- `ops/helm/metamuseum-search-graph`\n\nRender manifests:\n\n```bash\npnpm infra:sota:helm:template\n```\n\nInstall:\n\n```bash\nhelm upgrade --install metamuseum-search-graph ops/helm/metamuseum-search-graph --namespace metamuseum --create-namespace\n```\n\nPort-forward for local validation:\n\n```bash\nkubectl -n metamuseum port-forward svc/metamuseum-search-graph-solr 8983:8983\nkubectl -n metamuseum port-forward svc/metamuseum-search-graph-graphdb 7200:7200\n```\n\n## Persistence defaults\n\nDefault PVC requests in `values.yaml`:\n\n- Solr: `20Gi`\n- GraphDB: `50Gi`\n\nOverride storage class and size with Helm `--set` or a values override file.\n\n## GraphDB repository + SPARQL + Lucene bootstrap\n\nAfter GraphDB is running, initialize the repository and Lucene connector:\n\n```bash\npnpm graphdb:bootstrap\n```\n\nThis script:\n\n- creates repository `metamuseum` when missing (GraphDB REST `POST /rest/repositories` with `.ttl` config),\n- enforces the runtime reasoning policy (`GRAPHDB_RULESET` must be `rdfsplus` or `rdfsplus-optimized`; OWL-family rulesets are rejected),\n- confirms SPARQL 1.1 query/update endpoints:\n  - query: `/repositories/metamuseum`\n  - update/Graph Store: `/repositories/metamuseum/statements`\n- creates Lucene connector `metamuseum_index` if missing via `luc:createConnector`,\n- configures a `graph()`-indexed field for hybrid text + graph filtering by named graph.\n\nReasoning profile policy:\n\n- Runtime inference: `RDFS` (`rdfsplus` or `rdfsplus-optimized`).\n- Constraint validation: `SHACL` via the validation service (`/api/validate`).\n- Disallowed at runtime: full OWL-family reasoning profiles.\n\n## Named-graph provenance partitioning by source institution\n\nLoad provider RDF payloads into source-specific named graphs:\n\n```bash\npnpm graphdb:load:named-graph -- --provider=met --file=./artifacts/records-met.nq\npnpm graphdb:load:named-graph -- --provider=getty --file=./artifacts/records-getty.nq\n```\n\nBy default, loads run in replace mode per named graph.\nUse `--append` to append instead of replace.\n\nNamed graph pattern:\n\n- `https://lod.metamuseum.org/graph/source/{institution-slug}`\n\nExamples:\n\n- Met: `https://lod.metamuseum.org/graph/source/metropolitan-museum-of-art`\n- Getty: `https://lod.metamuseum.org/graph/source/j-paul-getty-museum`\n\n## Hybrid text + graph query example (Lucene + named graph)\n\nAfter bootstrap and data load, a query pattern can combine full-text retrieval with\ngraph partition filtering:\n\n```sparql\nPREFIX luc: <http://www.ontotext.com/connectors/lucene#>\nPREFIX luc-index: <http://www.ontotext.com/connectors/lucene/instance#>\n\nSELECT ?entity ?score WHERE {\n  ?search a luc-index:metamuseum_index ;\n          luc:query \"label:portrait AND labelGraph:https\\\\://lod.metamuseum.org/graph/source/metropolitan-museum-of-art\" ;\n          luc:entities ?entity .\n  ?entity luc:score ?score .\n}\n```\n\nThe Lucene connector behavior and `graph()` chain semantics used here follow\nGraphDB Lucene Connector documentation.\n","sections":[{"level":2,"heading":"Dev runtime (Docker Compose)","anchor":"dev-runtime-docker-compose"},{"level":2,"heading":"Kubernetes runtime (Helm)","anchor":"kubernetes-runtime-helm"},{"level":2,"heading":"Persistence defaults","anchor":"persistence-defaults"},{"level":2,"heading":"GraphDB repository + SPARQL + Lucene bootstrap","anchor":"graphdb-repository-sparql-lucene-bootstrap"},{"level":2,"heading":"Named-graph provenance partitioning by source institution","anchor":"named-graph-provenance-partitioning-by-source-institution"},{"level":2,"heading":"Hybrid text + graph query example (Lucene + named graph)","anchor":"hybrid-text-graph-query-example-lucene-named-graph"}],"html":"<h1 id=\"solr-9-graphdb-provisioning\">Solr 9 + GraphDB Provisioning</h1>\n<p>This runbook provisions the Era C1 search/graph stack:</p>\n<ul><li>Solr 9 (LUX-aligned search/faceting path)</li><li>GraphDB CE (Ontotext OSS path)</li></ul>\n<p>For local trace export wiring (Tempo / Jaeger), see `docs/ops/otel-local.md`.</p>\n<h2 id=\"dev-runtime-docker-compose\">Dev runtime (Docker Compose)</h2>\n<p>Compose stack file: `ops/docker-compose.yml`</p>\n<ul><li>Postgres stays in the default profile (`pnpm db:up`).</li><li>Solr + GraphDB are in the `sota` profile (`pnpm infra:sota:up`).</li></ul>\n<p>Commands:</p>\n<pre><code>\npnpm infra:sota:up\npnpm infra:sota:down\n</code></pre>\n<p>Exposed ports:</p>\n<ul><li>Solr: `http://localhost:8983/solr`</li><li>GraphDB: `http://localhost:7200`</li></ul>\n<p>Images:</p>\n<ul><li>`solr:9.6`</li><li>`ontotext/graphdb:10.8.14` (GraphDB CE path via license-less default runtime)</li></ul>\n<h2 id=\"kubernetes-runtime-helm\">Kubernetes runtime (Helm)</h2>\n<p>Chart path:</p>\n<ul><li>`ops/helm/metamuseum-search-graph`</li></ul>\n<p>Render manifests:</p>\n<pre><code>\npnpm infra:sota:helm:template\n</code></pre>\n<p>Install:</p>\n<pre><code>\nhelm upgrade --install metamuseum-search-graph ops/helm/metamuseum-search-graph --namespace metamuseum --create-namespace\n</code></pre>\n<p>Port-forward for local validation:</p>\n<pre><code>\nkubectl -n metamuseum port-forward svc/metamuseum-search-graph-solr 8983:8983\nkubectl -n metamuseum port-forward svc/metamuseum-search-graph-graphdb 7200:7200\n</code></pre>\n<h2 id=\"persistence-defaults\">Persistence defaults</h2>\n<p>Default PVC requests in `values.yaml`:</p>\n<ul><li>Solr: `20Gi`</li><li>GraphDB: `50Gi`</li></ul>\n<p>Override storage class and size with Helm `--set` or a values override file.</p>\n<h2 id=\"graphdb-repository-sparql-lucene-bootstrap\">GraphDB repository + SPARQL + Lucene bootstrap</h2>\n<p>After GraphDB is running, initialize the repository and Lucene connector:</p>\n<pre><code>\npnpm graphdb:bootstrap\n</code></pre>\n<p>This script:</p>\n<ul><li>creates repository `metamuseum` when missing (GraphDB REST `POST /rest/repositories` with `.ttl` config),</li><li>enforces the runtime reasoning policy (`GRAPHDB_RULESET` must be `rdfsplus` or `rdfsplus-optimized`; OWL-family rulesets are rejected),</li><li>confirms SPARQL 1.1 query/update endpoints:</li><li>query: `/repositories/metamuseum`</li><li>update/Graph Store: `/repositories/metamuseum/statements`</li><li>creates Lucene connector `metamuseum_index` if missing via `luc:createConnector`,</li><li>configures a `graph()`-indexed field for hybrid text + graph filtering by named graph.</li></ul>\n<p>Reasoning profile policy:</p>\n<ul><li>Runtime inference: `RDFS` (`rdfsplus` or `rdfsplus-optimized`).</li><li>Constraint validation: `SHACL` via the validation service (`/api/validate`).</li><li>Disallowed at runtime: full OWL-family reasoning profiles.</li></ul>\n<h2 id=\"named-graph-provenance-partitioning-by-source-institution\">Named-graph provenance partitioning by source institution</h2>\n<p>Load provider RDF payloads into source-specific named graphs:</p>\n<pre><code>\npnpm graphdb:load:named-graph -- --provider=met --file=./artifacts/records-met.nq\npnpm graphdb:load:named-graph -- --provider=getty --file=./artifacts/records-getty.nq\n</code></pre>\n<p>By default, loads run in replace mode per named graph.</p>\n<p>Use `--append` to append instead of replace.</p>\n<p>Named graph pattern:</p>\n<ul><li>`https://lod.metamuseum.org/graph/source/{institution-slug}`</li></ul>\n<p>Examples:</p>\n<ul><li>Met: `https://lod.metamuseum.org/graph/source/metropolitan-museum-of-art`</li><li>Getty: `https://lod.metamuseum.org/graph/source/j-paul-getty-museum`</li></ul>\n<h2 id=\"hybrid-text-graph-query-example-lucene-named-graph\">Hybrid text + graph query example (Lucene + named graph)</h2>\n<p>After bootstrap and data load, a query pattern can combine full-text retrieval with</p>\n<p>graph partition filtering:</p>\n<pre><code>\nPREFIX luc: &lt;http://www.ontotext.com/connectors/lucene#&gt;\nPREFIX luc-index: &lt;http://www.ontotext.com/connectors/lucene/instance#&gt;\n\nSELECT ?entity ?score WHERE {\n  ?search a luc-index:metamuseum_index ;\n          luc:query &quot;label:portrait AND labelGraph:https\\\\://lod.metamuseum.org/graph/source/metropolitan-museum-of-art&quot; ;\n          luc:entities ?entity .\n  ?entity luc:score ?score .\n}\n</code></pre>\n<p>The Lucene connector behavior and `graph()` chain semantics used here follow</p>\n<p>GraphDB Lucene Connector documentation.</p>","updatedAt":"2018-10-20T01:46:40.000Z","checksum":"fc1b15279a8466c09fe033823683886526268407f6ce8961088b53a3cc4e75f7","checksumPrefix":"fc1b15279a84","anchorCount":6,"lineCount":132,"rawUrl":"/api/docs/content?path=ops%2Fsearch-graph-provisioning.md","htmlUrl":"/docs?doc=ops%2Fsearch-graph-provisioning.md","apiUrl":"/api/docs/content?path=ops%2Fsearch-graph-provisioning.md"}