Skip to main content
Version: Next

Getting Started

This page assumes the bundle is installed and the Generic Data Index is running on OpenSearch or Elasticsearch. Embeddings are off by default: they add fields to your search index and send content to an external inference service, so nothing happens until you opt in.

1. Pick a model

The bundle ships no model and has no built-in default endpoint — you choose the model and where it runs. Two decisions matter:

  • Modality. A text model covers semantic search and duplicate detection over data objects (and the text of assets). Image search needs an image model, paired with a text model that embeds the incoming query into the same latent space — see the cross-modal section of Inference Service.
  • Language coverage. If your audience searches in more than the default language, pick a multilingual text model. Retrofitting this later means re-embedding everything. Localized fields are currently embedded using Pimcore's system default language. Because the locale determines the composed text, changing the system default language changes every object's identity key, so the affected vectors re-embed on the next indexing pass.

If you want a starting point rather than an evaluation: the models the bundle's own benchmarks use, and the measurements behind that choice, are in Defaults and Benchmarks. Treat them as a reasonable default, not a recommendation for your data — the Evaluation Tool exists to compare candidates on your content, and it works before you enable the feature.

2. Serve the model over HTTP

The bundle never loads or downloads a model. It only makes HTTP requests to an inference service that you run or subscribe to — self-hosted or a third-party API, whichever you prefer. Out of the box it speaks the OpenAI-compatible embeddings shape, which most embedding servers and hosted APIs already expose.

Inference Service covers your hosting options, how to get the model weights, and the exact contract an endpoint must fulfil. Two points decide whether your first run succeeds:

  • Vectors must be L2-normalized (unit length). Unnormalized vectors do not error — they silently rank partly by vector length and quietly ruin result quality.
  • The first backfill is your heaviest inference burst. Embedding a whole catalogue on CPU-only hardware can take hours, which is why the model timeout defaults to 120 seconds.

If no available service fits your model or preprocessing needs, you can implement your own provider — see Customization.

3. Configure the bundle

A minimal working text-only setup:

pimcore_backend_power_tools:
embeddings:
enabled: true # required — the feature is off by default
objects:
classes: ['Product'] # required — ONLY these classes are embedded
models:
my-text-model:
modality: 'text'
# Shared dev/testing Space — NOT for production; see "Inference Service" docs
endpoint: 'https://pimcore-local-inference-service.hf.space/text-embedding'
model: 'nomic-ai/nomic-embed-text-v2-moe'
dimension: 768 # required — sizes the mapping, validates responses
usages:
semantic_text_search: my-text-model
object_dedup: my-text-model

Three things are required together: enabled: true, at least one model assigned to a usage, and an element scope. The scope is deny-by-default on both sides, so nothing is embedded until you say what to embed:

To embedSet
Data objects of a classobjects.classes: ['Product', 'Category'] — empty means no object at all, and there is no wildcard
Assets (images)assets.enabled: true, plus a thumbnail on the image model
Images onlyassets.enabled: true, leave objects.classes empty

A class you add later is never embedded until you name it, which is what stops a new class from quietly running up an inference bill. Note that only image assets can produce input — other asset types are skipped even with assets enabled.

To add image search, opt assets in and configure the two towers of a cross-modal model, paired in the usage:

        assets:
enabled: true
models:
my-vision-model:
modality: 'image'
# Shared dev/testing Space — NOT for production; see "Inference Service" docs
endpoint: 'https://pimcore-local-inference-service.hf.space/image-embedding'
model: 'google/siglip2-base-patch16-256'
dimension: 768
thumbnail: 'embeddings_siglip2' # REQUIRED for image models — see Configuration
shared_space: 'siglip2-base' # both towers must declare the SAME space
my-vision-text-model:
modality: 'text'
endpoint: 'https://pimcore-local-inference-service.hf.space/text-embedding'
model: 'google/siglip2-base-patch16-256'
dimension: 768
shared_space: 'siglip2-base'
usages:
image_search:
model: my-vision-model # embeds the indexed images
query_model: my-vision-text-model # embeds the incoming text query
image_dedup: my-vision-model

Every option is documented in the Configuration reference. If your endpoint needs authentication, use auth_token sourced from an environment variable — never a literal token in config.

4. Recreate the search indices

The vector fields are part of the index mapping, so the indices must be rebuilt once after enabling. On OpenSearch the required index.knn setting is added automatically while embeddings are enabled.

bin/console generic-data-index:update:index -r

5. Run the workers

Embedding generation is asynchronous. Two transports must be consumed — the index queue and the embedding queue:

bin/console messenger:consume pimcore_generic_data_index_queue
bin/console messenger:consume pimcore_backend_power_tools_embedding_queue

Run the embedding queue in its own worker (or several): embedding batches are slow compared to structural indexing, and sharing a worker lets them starve normal index updates. In production these belong under a process supervisor.

6. Backfill existing elements

New and edited elements are embedded automatically from now on. Existing content needs one pass:

bin/console bpt:embeddings:reindex

7. Verify

Ask the reconciler whether anything is still missing its vectors — the authoritative check:

bin/console bpt:embeddings:reindex --reconcile

missing: 0 for every field means every eligible element carries vectors. "Eligible" is the element scope plus what can actually produce input: an allowlisted data object class (Concrete objects and their variants, never folders), and image assets whose thumbnail rasterizes (which is why SVGs are skipped). Then confirm quality end-to-end with a semantic query through Studio's search, or run the Evaluation Tool against label files.

Troubleshooting the first run

SymptomLikely cause
No vectors appear at all, no errorsMost often the element scope: objects.classes is empty (no object is embedded) or assets.enabled is false. Then check enabled: true and the usages block.
Search returns results but ranking looks random, scores nearly identicalThe service returns unnormalized vectors. See serving invariant 1.
Vectors missing for some elements onlyGeneration failed for those; they are marked for backfill. Re-run bpt:embeddings:reindex and check the worker logs.
A worker starts and exits immediately without outputA stale worker-restart signal. Clear it with bin/console cache:pool:clear cache.messenger.restart_workers_signal, then consume again.
Everything re-embeds on every reindexAn identity-key input is changing — see Caching.
index.knn / unknown setting errors on Elasticsearchindex.knn is OpenSearch-only; the bundle omits it on Elasticsearch. Recreate the index after switching engines.

Turning it off again

pimcore_backend_power_tools:
embeddings:
enabled: false

This stops all embedding behaviour in one place — mapping, generation, indexing, and kNN querying — regardless of the configured models and usages. Already-stored vectors stay in the index until it is recreated; the commands refuse to run, and the kNN search modifier becomes a no-op instead of calling the inference service.