search-engine-for-typesense 30.1.8.10 → 30.1.8.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e12c8943b56f8054dbb1cfff9c52f17f0a926664eeb77436ee711cfba06e9d0c
|
|
4
|
+
data.tar.gz: 833df3fbf7c7ff98576c29e218a15dea996230e1a1a624f63fdc896a3728d2ed
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 65dcbf97c8b91ae1f85836dcb69a955fa6cf63a52bf71063b8ebd53a8ec7c82eac0a8df211fc9e2e4fc8da0f488b5c8f3ee442dbb870d9002987c959e990f689
|
|
7
|
+
data.tar.gz: 78fbe84b31b3fa457144ce7c81466a1b074a25c4218705f19d4ce3875f0e7cd6fedfbd32f72658396eca255db0aee5554693c2df078590d65bd04765489a274f
|
|
@@ -294,6 +294,8 @@ module SearchEngine
|
|
|
294
294
|
end
|
|
295
295
|
|
|
296
296
|
def exists?(relation)
|
|
297
|
+
return count(relation).positive? if relation.send(:curation_filter_curated_hits?)
|
|
298
|
+
|
|
297
299
|
loaded = relation.instance_variable_get(:@__loaded)
|
|
298
300
|
memo = relation.instance_variable_get(:@__result_memo)
|
|
299
301
|
return memo.found.to_i.positive? if loaded && memo
|
|
@@ -303,8 +305,8 @@ module SearchEngine
|
|
|
303
305
|
|
|
304
306
|
def count(relation)
|
|
305
307
|
if relation.send(:curation_filter_curated_hits?)
|
|
306
|
-
|
|
307
|
-
return
|
|
308
|
+
result = execute(relation)
|
|
309
|
+
return curated_total_count(result)
|
|
308
310
|
end
|
|
309
311
|
|
|
310
312
|
loaded = relation.instance_variable_get(:@__loaded)
|
|
@@ -364,6 +366,21 @@ module SearchEngine
|
|
|
364
366
|
end
|
|
365
367
|
module_function :fetch_found_only
|
|
366
368
|
|
|
369
|
+
def curated_total_count(result)
|
|
370
|
+
raw = result.raw || {}
|
|
371
|
+
base_count = raw['found_docs'] || raw[:found_docs] || result.found
|
|
372
|
+
|
|
373
|
+
base_count.to_i + curated_hits_count(result)
|
|
374
|
+
end
|
|
375
|
+
module_function :curated_total_count
|
|
376
|
+
|
|
377
|
+
def curated_hits_count(result)
|
|
378
|
+
result.to_a.count do |obj|
|
|
379
|
+
obj.respond_to?(:curated_hit?) && obj.curated_hit?
|
|
380
|
+
end
|
|
381
|
+
end
|
|
382
|
+
module_function :curated_hits_count
|
|
383
|
+
|
|
367
384
|
# Detect Typesense 400 errors caused by missing infix/prefix configuration
|
|
368
385
|
# e.g., "Could not find `name` in the infix index. Make sure to enable infix search by specifying `infix: true` in the schema."
|
|
369
386
|
def infix_missing_error?(error)
|
|
@@ -27,7 +27,7 @@ module SearchEngine
|
|
|
27
27
|
targets = delivery_targets
|
|
28
28
|
return enqueue_legacy(limit: limit) if targets.empty?
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
materialize_deliveries(limit: limit)
|
|
31
31
|
targets.each { |target| enqueue_target(target, limit: limit) }
|
|
32
32
|
nil
|
|
33
33
|
end
|
|
@@ -36,6 +36,12 @@ module SearchEngine
|
|
|
36
36
|
|
|
37
37
|
attr_reader :repository, :targets_resolver
|
|
38
38
|
|
|
39
|
+
def materialize_deliveries(limit:)
|
|
40
|
+
return repository.materialize_deliveries! if limit.nil?
|
|
41
|
+
|
|
42
|
+
repository.materialize_deliveries!(limit: limit)
|
|
43
|
+
end
|
|
44
|
+
|
|
39
45
|
def enqueue_legacy(limit:)
|
|
40
46
|
return drain_job.perform_later if limit.nil?
|
|
41
47
|
|
|
@@ -111,11 +111,78 @@ module SearchEngine
|
|
|
111
111
|
|
|
112
112
|
# Create missing delivery rows for all configured delivery targets.
|
|
113
113
|
# @return [void]
|
|
114
|
-
def materialize_deliveries!
|
|
114
|
+
def materialize_deliveries!(limit: SearchEngine.config.postgres_outbox.batch_size)
|
|
115
115
|
targets = delivery_targets
|
|
116
116
|
return if targets.empty?
|
|
117
117
|
|
|
118
|
-
|
|
118
|
+
rows = []
|
|
119
|
+
connection.transaction do
|
|
120
|
+
rows = select_rows(delivery_materialization_select_sql(limit.to_i, targets))
|
|
121
|
+
next if rows.empty?
|
|
122
|
+
|
|
123
|
+
execute(materialization_supersede_older_deliveries_sql(rows, targets))
|
|
124
|
+
execute(supersede_older_pending_sql(rows))
|
|
125
|
+
execute(delivery_materialization_insert_sql(rows, targets))
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
rows
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
private
|
|
132
|
+
|
|
133
|
+
attr_reader :target_key
|
|
134
|
+
|
|
135
|
+
def connection
|
|
136
|
+
@connection ||= begin
|
|
137
|
+
require 'active_record'
|
|
138
|
+
ActiveRecord::Base.connection
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def claim_pending_deliveries(limit:, worker_id:)
|
|
143
|
+
reset_stale_delivery_processing!
|
|
144
|
+
rows = claim_pending_delivery_rows(limit: limit, worker_id: worker_id)
|
|
145
|
+
|
|
146
|
+
if rows.empty?
|
|
147
|
+
materialize_deliveries!(limit: limit)
|
|
148
|
+
rows = claim_pending_delivery_rows(limit: limit, worker_id: worker_id)
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
rows.map { |row| Event.new(row) }
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def delivery_materialization_select_sql(limit, targets)
|
|
155
|
+
<<~SQL
|
|
156
|
+
WITH target(target_key, queue_name) AS (
|
|
157
|
+
VALUES #{delivery_target_values_sql(targets)}
|
|
158
|
+
),
|
|
159
|
+
candidate_events AS (
|
|
160
|
+
SELECT outbox.*
|
|
161
|
+
FROM #{quoted_table} outbox
|
|
162
|
+
WHERE outbox.status IN ('pending', 'processing', 'failed')
|
|
163
|
+
AND (outbox.next_attempt_at IS NULL OR outbox.next_attempt_at <= CURRENT_TIMESTAMP)
|
|
164
|
+
AND EXISTS (
|
|
165
|
+
SELECT 1
|
|
166
|
+
FROM target
|
|
167
|
+
WHERE NOT EXISTS (
|
|
168
|
+
SELECT 1
|
|
169
|
+
FROM #{quoted_delivery_table} deliveries
|
|
170
|
+
WHERE deliveries.event_id = outbox.id
|
|
171
|
+
AND deliveries.target_key = target.target_key
|
|
172
|
+
)
|
|
173
|
+
)
|
|
174
|
+
ORDER BY outbox.id ASC
|
|
175
|
+
LIMIT #{limit}
|
|
176
|
+
FOR UPDATE SKIP LOCKED
|
|
177
|
+
)
|
|
178
|
+
SELECT DISTINCT ON (collection, document_id) *
|
|
179
|
+
FROM candidate_events
|
|
180
|
+
ORDER BY collection, document_id, id DESC
|
|
181
|
+
SQL
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
def delivery_materialization_insert_sql(rows, targets)
|
|
185
|
+
<<~SQL
|
|
119
186
|
INSERT INTO #{quoted_delivery_table} (
|
|
120
187
|
event_id,
|
|
121
188
|
target_key,
|
|
@@ -132,29 +199,19 @@ module SearchEngine
|
|
|
132
199
|
0,
|
|
133
200
|
CURRENT_TIMESTAMP,
|
|
134
201
|
CURRENT_TIMESTAMP
|
|
135
|
-
FROM
|
|
202
|
+
FROM (
|
|
203
|
+
VALUES #{materialization_event_values_sql(rows)}
|
|
204
|
+
) AS selected_events(event_id)
|
|
205
|
+
INNER JOIN #{quoted_table} outbox
|
|
206
|
+
ON outbox.id = selected_events.event_id
|
|
136
207
|
CROSS JOIN (
|
|
137
208
|
VALUES #{delivery_target_values_sql(targets)}
|
|
138
209
|
) AS target(target_key, queue_name)
|
|
139
|
-
WHERE outbox.status IN ('pending', 'processing', 'failed')
|
|
140
210
|
ON CONFLICT (event_id, target_key) DO NOTHING
|
|
141
211
|
SQL
|
|
142
212
|
end
|
|
143
213
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
attr_reader :target_key
|
|
147
|
-
|
|
148
|
-
def connection
|
|
149
|
-
@connection ||= begin
|
|
150
|
-
require 'active_record'
|
|
151
|
-
ActiveRecord::Base.connection
|
|
152
|
-
end
|
|
153
|
-
end
|
|
154
|
-
|
|
155
|
-
def claim_pending_deliveries(limit:, worker_id:)
|
|
156
|
-
materialize_deliveries!
|
|
157
|
-
reset_stale_delivery_processing!
|
|
214
|
+
def claim_pending_delivery_rows(limit:, worker_id:)
|
|
158
215
|
rows = []
|
|
159
216
|
|
|
160
217
|
connection.transaction do
|
|
@@ -164,7 +221,7 @@ module SearchEngine
|
|
|
164
221
|
execute(delivery_claim_update_sql(delivery_ids, worker_id)) unless delivery_ids.empty?
|
|
165
222
|
end
|
|
166
223
|
|
|
167
|
-
rows
|
|
224
|
+
rows
|
|
168
225
|
end
|
|
169
226
|
|
|
170
227
|
def reset_stale_delivery_processing!
|
|
@@ -271,6 +328,46 @@ module SearchEngine
|
|
|
271
328
|
SQL
|
|
272
329
|
end
|
|
273
330
|
|
|
331
|
+
def materialization_supersede_older_deliveries_sql(rows, targets)
|
|
332
|
+
<<~SQL
|
|
333
|
+
WITH updated_deliveries AS (
|
|
334
|
+
UPDATE #{quoted_delivery_table} older_deliveries
|
|
335
|
+
SET status = 'superseded',
|
|
336
|
+
processed_at = CURRENT_TIMESTAMP,
|
|
337
|
+
locked_at = NULL,
|
|
338
|
+
locked_by = NULL,
|
|
339
|
+
updated_at = CURRENT_TIMESTAMP
|
|
340
|
+
FROM #{quoted_table} older_events,
|
|
341
|
+
(
|
|
342
|
+
VALUES #{coalesce_values_sql(rows)}
|
|
343
|
+
) AS latest(collection, document_id, id),
|
|
344
|
+
(
|
|
345
|
+
VALUES #{delivery_target_values_sql(targets)}
|
|
346
|
+
) AS target(target_key, queue_name)
|
|
347
|
+
WHERE older_deliveries.event_id = older_events.id
|
|
348
|
+
AND older_deliveries.status = 'pending'
|
|
349
|
+
AND older_deliveries.target_key = target.target_key
|
|
350
|
+
AND older_events.collection = latest.collection
|
|
351
|
+
AND older_events.document_id = latest.document_id
|
|
352
|
+
AND older_events.id < latest.id
|
|
353
|
+
RETURNING older_deliveries.event_id
|
|
354
|
+
),
|
|
355
|
+
aggregate AS (
|
|
356
|
+
#{event_status_aggregate_sql('SELECT event_id FROM updated_deliveries')}
|
|
357
|
+
)
|
|
358
|
+
UPDATE #{quoted_table} events
|
|
359
|
+
SET status = aggregate.status,
|
|
360
|
+
processed_at = CASE
|
|
361
|
+
WHEN aggregate.status IN ('processed', 'superseded') THEN CURRENT_TIMESTAMP
|
|
362
|
+
ELSE NULL
|
|
363
|
+
END,
|
|
364
|
+
last_error = aggregate.last_error,
|
|
365
|
+
updated_at = CURRENT_TIMESTAMP
|
|
366
|
+
FROM aggregate
|
|
367
|
+
WHERE events.id = aggregate.event_id
|
|
368
|
+
SQL
|
|
369
|
+
end
|
|
370
|
+
|
|
274
371
|
def supersede_older_pending_sql(rows)
|
|
275
372
|
<<~SQL
|
|
276
373
|
UPDATE #{quoted_table} older
|
|
@@ -468,6 +565,12 @@ module SearchEngine
|
|
|
468
565
|
end.join(', ')
|
|
469
566
|
end
|
|
470
567
|
|
|
568
|
+
def materialization_event_values_sql(rows)
|
|
569
|
+
rows.map do |row|
|
|
570
|
+
"(#{quote(row_value(row, :id))})"
|
|
571
|
+
end.join(', ')
|
|
572
|
+
end
|
|
573
|
+
|
|
471
574
|
def quoted_table
|
|
472
575
|
connection.quote_table_name(SearchEngine.config.postgres_outbox.table_name)
|
|
473
576
|
end
|
|
@@ -563,12 +563,6 @@ module SearchEngine
|
|
|
563
563
|
|
|
564
564
|
# pluck helpers reside in Materializers
|
|
565
565
|
|
|
566
|
-
def curated_indices_for_current_result
|
|
567
|
-
@__result_memo.to_a.each_with_index.select do |obj, _idx|
|
|
568
|
-
obj.respond_to?(:curated_hit?) && obj.curated_hit?
|
|
569
|
-
end.map(&:last)
|
|
570
|
-
end
|
|
571
|
-
|
|
572
566
|
def curation_filter_curated_hits?
|
|
573
567
|
@state[:curation] && @state[:curation][:filter_curated_hits]
|
|
574
568
|
end
|