Class: TextUnifiedEmbeddingBackfillWorker
- Inherits:
-
Object
- Object
- TextUnifiedEmbeddingBackfillWorker
- Includes:
- Sidekiq::IterableJob, Sidekiq::Job
- Defined in:
- app/workers/text_unified_embedding_backfill_worker.rb
Overview
Backfills Gemini Embedding 2 vectors into the unified vector space for TEXT
content, so text and images become cross-modally searchable from one query.
Dual-write, no delete: for each safe source content_type='primary' text row it
upserts a content_type='unified' sibling tagged gemini-embedding-2 (via
Embedding::TextUnifier). The candidate anti-join recognizes both valid live
shapes — a single unified row or unified_chunk_N rows — and correlates
them by embeddable type, id, and locale.
The legacy set is expected to be complete, so the nightly run should normally
be a no-op. It remains a bounded safety net for a stray legacy primary row.
Chunked records are never converted here; their exact shape is validated and
repaired by EmbeddingRefreshWorker through the normal EmbeddingWorker path.
Retiring it is a judgement call, not a cleanup: dropping the schedule entry
(config/sidekiq_production_schedule.yml) removes that safety net. NOTE this
worker does not repair stale live embeddings; the population and refresh
workers own that lifecycle.
Self-throttling: Embedding::Gemini caps at 300 req/min, and each iteration is
one batchEmbedContents request (≤100 rows), so the corpus drains without any
mass enqueue. Resumable: Sidekiq::IterableJob checkpoints the PK cursor after
every batch, so a deploy or restart resumes mid-run.
Scheduled nightly; idempotent (skips rows that already have a Gemini unified
sibling), so it's safe to re-run and converges to full coverage.
Constant Summary collapse
- BATCH_SIZE =
One Gemini batchEmbedContents request per iteration.
Embedding::Gemini::MAX_BATCH_SIZE
Instance Method Summary collapse
-
#build_enumerator(options = nil, cursor:) ⇒ Enumerator
Batches of candidate records.
-
#each_iteration(batch, *_args) ⇒ Object
Each iteration.
-
#on_complete ⇒ Object
On complete.
Instance Method Details
#build_enumerator(options = nil, cursor:) ⇒ Enumerator
Returns batches of candidate records.
51 52 53 54 55 56 57 58 59 60 |
# File 'app/workers/text_unified_embedding_backfill_worker.rb', line 51 def build_enumerator( = nil, cursor:) ||= {} # sidekiq-iteration omits the arg entirely when no options were enqueued @types = Array([:types]).presence || Embedding::TextUnifier::TEXT_TYPES @counts = { processed: 0, skipped: 0, failed: 0 } scope = candidate_scope log_info "Starting: #{scope.count} primary rows need a Gemini unified sibling (types: #{@types.join(',')})" active_record_batches_enumerator(scope, cursor: cursor, batch_size: BATCH_SIZE) end |
#each_iteration(batch, *_args) ⇒ Object
Each iteration.
67 68 69 70 71 72 |
# File 'app/workers/text_unified_embedding_backfill_worker.rb', line 67 def each_iteration(batch, *_args) result = Embedding::TextUnifier.backfill(batch) @counts.each_key { |key| @counts[key] += result[key] } log_info "Progress: #{@counts.inspect}" if (@counts[:processed] % 1000).zero? && @counts[:processed].positive? end |
#on_complete ⇒ Object
On complete.
77 78 79 |
# File 'app/workers/text_unified_embedding_backfill_worker.rb', line 77 def on_complete log_info "Complete: #{@counts.inspect}" end |