noiseless 0.7.2 ā 0.9.0
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 +4 -4
- data/README.md +56 -2
- data/lib/noiseless/adapter.rb +29 -41
- data/lib/noiseless/adapters/elasticsearch.rb +0 -1
- data/lib/noiseless/adapters/execution_modules/elasticsearch_execution.rb +8 -6
- data/lib/noiseless/adapters/execution_modules/es_compatible_execution.rb +65 -17
- data/lib/noiseless/adapters/execution_modules/http_transport.rb +29 -18
- data/lib/noiseless/adapters/execution_modules/opensearch_execution.rb +102 -114
- data/lib/noiseless/adapters/execution_modules/pgvector_support.rb +42 -47
- data/lib/noiseless/adapters/execution_modules/postgresql_execution.rb +65 -327
- data/lib/noiseless/adapters/execution_modules/postgresql_query.rb +269 -0
- data/lib/noiseless/adapters/execution_modules/typesense_execution.rb +172 -296
- data/lib/noiseless/adapters/execution_modules/typesense_query.rb +143 -0
- data/lib/noiseless/adapters/indices_api.rb +3 -1
- data/lib/noiseless/adapters/open_search.rb +30 -88
- data/lib/noiseless/adapters/postgresql.rb +6 -16
- data/lib/noiseless/adapters/typesense.rb +1 -2
- data/lib/noiseless/ast/aggregation.rb +0 -23
- data/lib/noiseless/ast/aggregation_builder.rb +28 -0
- data/lib/noiseless/ast/hybrid.rb +4 -2
- data/lib/noiseless/ast/join.rb +4 -5
- data/lib/noiseless/ast/vector.rb +25 -4
- data/lib/noiseless/bulk_importer.rb +17 -32
- data/lib/noiseless/callbacks.rb +4 -30
- data/lib/noiseless/connection_manager.rb +9 -3
- data/lib/noiseless/controller_runtime.rb +37 -0
- data/lib/noiseless/document_manager.rb +22 -41
- data/lib/noiseless/embedding.rb +33 -0
- data/lib/noiseless/instrumentation.rb +2 -136
- data/lib/noiseless/introspection/mermaid_diagrams.rb +143 -0
- data/lib/noiseless/introspection/query_visualizer.rb +3 -228
- data/lib/noiseless/introspection.rb +1 -1
- data/lib/noiseless/log_subscriber.rb +103 -0
- data/lib/noiseless/model.rb +19 -71
- data/lib/noiseless/model_registry.rb +1 -7
- data/lib/noiseless/multi_search.rb +23 -113
- data/lib/noiseless/pagination.rb +14 -40
- data/lib/noiseless/query_builder.rb +16 -16
- data/lib/noiseless/query_delegation.rb +15 -0
- data/lib/noiseless/railtie.rb +0 -2
- data/lib/noiseless/record_class_resolver.rb +15 -0
- data/lib/noiseless/response/records.rb +9 -3
- data/lib/noiseless/runtime_reset_middleware.rb +1 -1
- data/lib/noiseless/search_index_update_job.rb +13 -14
- data/lib/noiseless/test_case.rb +0 -1
- data/lib/noiseless/version.rb +1 -1
- data/lib/noiseless.rb +1 -10
- metadata +33 -13
- data/lib/tasks/benchmark.rake +0 -35
data/lib/noiseless/pagination.rb
CHANGED
|
@@ -5,6 +5,12 @@ module Noiseless
|
|
|
5
5
|
DEFAULT_PER_PAGE = 20
|
|
6
6
|
MAX_PER_PAGE = 100
|
|
7
7
|
|
|
8
|
+
def self.query_options(paginate)
|
|
9
|
+
return { from: 0, size: DEFAULT_PER_PAGE } unless paginate
|
|
10
|
+
|
|
11
|
+
{ from: (paginate.page - 1) * paginate.per_page, size: paginate.per_page }
|
|
12
|
+
end
|
|
13
|
+
|
|
8
14
|
# Simple paginated array wrapper - no external dependencies
|
|
9
15
|
class PaginatedArray < Array
|
|
10
16
|
attr_accessor :current_page, :per_page, :total_count
|
|
@@ -75,16 +81,16 @@ module Noiseless
|
|
|
75
81
|
|
|
76
82
|
# Encode cursor for API response
|
|
77
83
|
def encode
|
|
78
|
-
|
|
84
|
+
[ActiveSupport::JSON.encode({ f: field, v: value, d: direction })].pack("m0").tr("+/", "-_")
|
|
79
85
|
end
|
|
80
86
|
|
|
81
87
|
# Decode cursor from API request
|
|
82
88
|
def self.decode(encoded)
|
|
83
89
|
return nil if encoded.blank?
|
|
84
90
|
|
|
85
|
-
data = JSON.parse(
|
|
91
|
+
data = JSON.parse(encoded.tr("-_", "+/").unpack1("m0"))
|
|
86
92
|
new(field: data["f"], value: data["v"], direction: data["d"]&.to_sym || :asc)
|
|
87
|
-
rescue
|
|
93
|
+
rescue ArgumentError, JSON::ParserError
|
|
88
94
|
nil
|
|
89
95
|
end
|
|
90
96
|
|
|
@@ -131,6 +137,10 @@ module Noiseless
|
|
|
131
137
|
# Search paginator - builds and executes paginated queries
|
|
132
138
|
class SearchPaginator
|
|
133
139
|
include Enumerable
|
|
140
|
+
extend QueryDelegation
|
|
141
|
+
|
|
142
|
+
delegate_query_methods :match, :multi_match, :filter, :sort, :aggregation, :geo_distance, :vector,
|
|
143
|
+
to: :@query_builder
|
|
134
144
|
|
|
135
145
|
def initialize(model_class, page: 1, per_page: nil)
|
|
136
146
|
@model_class = model_class
|
|
@@ -213,42 +223,6 @@ module Noiseless
|
|
|
213
223
|
@results.to_a
|
|
214
224
|
end
|
|
215
225
|
|
|
216
|
-
# Query building delegation
|
|
217
|
-
def match(field, value, **)
|
|
218
|
-
@query_builder.match(field, value, **)
|
|
219
|
-
self
|
|
220
|
-
end
|
|
221
|
-
|
|
222
|
-
def multi_match(query, fields, **)
|
|
223
|
-
@query_builder.multi_match(query, fields, **)
|
|
224
|
-
self
|
|
225
|
-
end
|
|
226
|
-
|
|
227
|
-
def filter(field, value, **)
|
|
228
|
-
@query_builder.filter(field, value, **)
|
|
229
|
-
self
|
|
230
|
-
end
|
|
231
|
-
|
|
232
|
-
def sort(field, direction = :asc, **)
|
|
233
|
-
@query_builder.sort(field, direction, **)
|
|
234
|
-
self
|
|
235
|
-
end
|
|
236
|
-
|
|
237
|
-
def aggregation(name, type, **)
|
|
238
|
-
@query_builder.aggregation(name, type, **)
|
|
239
|
-
self
|
|
240
|
-
end
|
|
241
|
-
|
|
242
|
-
def geo_distance(field, lat:, lon:, distance:, **)
|
|
243
|
-
@query_builder.geo_distance(field, lat: lat, lon: lon, distance: distance, **)
|
|
244
|
-
self
|
|
245
|
-
end
|
|
246
|
-
|
|
247
|
-
def vector(field, embedding, **)
|
|
248
|
-
@query_builder.vector(field, embedding, **)
|
|
249
|
-
self
|
|
250
|
-
end
|
|
251
|
-
|
|
252
226
|
# Response access
|
|
253
227
|
def results
|
|
254
228
|
execute_search unless @executed
|
|
@@ -312,7 +286,7 @@ module Noiseless
|
|
|
312
286
|
|
|
313
287
|
client = Noiseless.connections.client(@model_class.connection)
|
|
314
288
|
ast = @query_builder.to_ast
|
|
315
|
-
@results = client.search(ast, model_class: @model_class)
|
|
289
|
+
@results = Sync { client.search(ast, model_class: @model_class).wait }
|
|
316
290
|
@total_count = @results.total
|
|
317
291
|
@executed = true
|
|
318
292
|
end
|
|
@@ -2,9 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
module Noiseless
|
|
4
4
|
class QueryBuilder
|
|
5
|
+
def self.indexes_for(model)
|
|
6
|
+
# Multi-search starts without a model and supplies its own indexes.
|
|
7
|
+
return [] if model.nil?
|
|
8
|
+
|
|
9
|
+
return Array(model.search_index) if model.respond_to?(:search_index) && model.search_index&.any?
|
|
10
|
+
return [model.index_name] if model.respond_to?(:index_name) && model.index_name
|
|
11
|
+
|
|
12
|
+
[model.name.demodulize.underscore.pluralize]
|
|
13
|
+
end
|
|
14
|
+
|
|
5
15
|
def initialize(model)
|
|
6
16
|
@model = model
|
|
7
|
-
@indexes =
|
|
17
|
+
@indexes = self.class.indexes_for(model)
|
|
8
18
|
@nodes = []
|
|
9
19
|
@aggregations = []
|
|
10
20
|
@collapse = nil
|
|
@@ -143,12 +153,13 @@ module Noiseless
|
|
|
143
153
|
# @param text_query [String] The text query for BM25 matching
|
|
144
154
|
# @param embedding [Array<Float>] The query embedding vector
|
|
145
155
|
# @param field [Symbol] The embedding field name
|
|
156
|
+
# @param fields [Array<Symbol>] Fields the text query runs against
|
|
146
157
|
# @param text_weight [Float] Weight for text search score (default: 0.5)
|
|
147
158
|
# @param vector_weight [Float] Weight for vector search score (default: 0.5)
|
|
148
159
|
# @param k [Integer] Number of nearest neighbors (default: 10)
|
|
149
|
-
def hybrid(text_query, embedding, field:, text_weight: 0.5, vector_weight: 0.5, k: 10)
|
|
160
|
+
def hybrid(text_query, embedding, field:, fields: [], text_weight: 0.5, vector_weight: 0.5, k: 10)
|
|
150
161
|
vector_node = AST::Vector.new(field, embedding, k: k)
|
|
151
|
-
@hybrid = AST::Hybrid.new(text_query, vector_node,
|
|
162
|
+
@hybrid = AST::Hybrid.new(text_query, vector_node, fields:, text_weight:, vector_weight:)
|
|
152
163
|
self
|
|
153
164
|
end
|
|
154
165
|
|
|
@@ -188,8 +199,8 @@ module Noiseless
|
|
|
188
199
|
# @param on [Hash] Join conditions
|
|
189
200
|
# @param include_fields [Array] Fields to include from joined collection
|
|
190
201
|
# @param strategy [Symbol] Join strategy :left or :inner
|
|
191
|
-
def join(collection,
|
|
192
|
-
@joins << AST::Join.new(collection,
|
|
202
|
+
def join(collection, include_fields: [], strategy: :left)
|
|
203
|
+
@joins << AST::Join.new(collection, include_fields:, strategy:)
|
|
193
204
|
self
|
|
194
205
|
end
|
|
195
206
|
|
|
@@ -269,16 +280,5 @@ module Noiseless
|
|
|
269
280
|
raise ArgumentError, "pinned_hits must be a String, Hash, or Array of [id, position]"
|
|
270
281
|
end
|
|
271
282
|
end
|
|
272
|
-
|
|
273
|
-
def determine_indexes(model)
|
|
274
|
-
# Check for search_index (plural array) first
|
|
275
|
-
return Array(model.search_index) if model.respond_to?(:search_index) && model.search_index&.any?
|
|
276
|
-
|
|
277
|
-
# Check for index_name (singular string) next
|
|
278
|
-
return [model.index_name] if model.respond_to?(:index_name) && model.index_name
|
|
279
|
-
|
|
280
|
-
# Fallback to pluralized model name
|
|
281
|
-
[model.name.demodulize.underscore.pluralize]
|
|
282
|
-
end
|
|
283
283
|
end
|
|
284
284
|
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Noiseless
|
|
4
|
+
module QueryDelegation
|
|
5
|
+
# Unlike ordinary delegation, fluent query methods return their wrapper.
|
|
6
|
+
def delegate_query_methods(*names, to:)
|
|
7
|
+
names.each do |name|
|
|
8
|
+
define_method(name) do |*args, **options, &block|
|
|
9
|
+
instance_variable_get(to).public_send(name, *args, **options, &block)
|
|
10
|
+
self
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
data/lib/noiseless/railtie.rb
CHANGED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Noiseless
|
|
4
|
+
module RecordClassResolver
|
|
5
|
+
# Search definitions and database models are different kinds of classes.
|
|
6
|
+
# Only a Noiseless::Model uses the explicit record_class mapping.
|
|
7
|
+
def self.resolve(model_class)
|
|
8
|
+
if model_class.is_a?(Class) && model_class <= Model
|
|
9
|
+
model_class.record_class
|
|
10
|
+
else
|
|
11
|
+
model_class
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -4,7 +4,12 @@ module Noiseless
|
|
|
4
4
|
module Response
|
|
5
5
|
class Records < Base
|
|
6
6
|
def initialize(raw_response, model_class)
|
|
7
|
-
|
|
7
|
+
record_class = RecordClassResolver.resolve(model_class)
|
|
8
|
+
unless record_class.respond_to?(:where)
|
|
9
|
+
raise ArgumentError, "#{model_class || 'nil'} cannot load records; configure record_class on your Noiseless::Model search class"
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
super(raw_response, record_class)
|
|
8
13
|
@records = nil
|
|
9
14
|
@record_hit_map = nil
|
|
10
15
|
end
|
|
@@ -62,7 +67,7 @@ module Noiseless
|
|
|
62
67
|
end
|
|
63
68
|
|
|
64
69
|
def load_records
|
|
65
|
-
return [] if hits.empty?
|
|
70
|
+
return [] if hits.empty?
|
|
66
71
|
|
|
67
72
|
# Extract IDs from hits
|
|
68
73
|
ids = hits.map { |hit| hit["_id"] }
|
|
@@ -75,8 +80,9 @@ module Noiseless
|
|
|
75
80
|
|
|
76
81
|
# Sort records by the order they appear in search results
|
|
77
82
|
sorted_records = []
|
|
83
|
+
records_by_id = loaded_records.index_by { it.id.to_s }
|
|
78
84
|
hits.each_with_index do |hit, hit_index|
|
|
79
|
-
record =
|
|
85
|
+
record = records_by_id[hit["_id"].to_s]
|
|
80
86
|
if record
|
|
81
87
|
sorted_records << record
|
|
82
88
|
@record_hit_map[record] = hit_index
|
|
@@ -31,12 +31,9 @@ module Noiseless
|
|
|
31
31
|
raise ArgumentError, "Unknown operation: #{operation}"
|
|
32
32
|
end
|
|
33
33
|
rescue StandardError => e
|
|
34
|
-
if options[:raise_on_error]
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
# Log error silently
|
|
38
|
-
logger.error "Noiseless: Background job failed for #{model_class_name}##{record_id}: #{e.message}"
|
|
39
|
-
end
|
|
34
|
+
raise if options[:raise_on_error]
|
|
35
|
+
|
|
36
|
+
Rails.logger&.error "Noiseless: Background job failed for #{model_class_name}##{record_id}: #{e.message}"
|
|
40
37
|
end
|
|
41
38
|
|
|
42
39
|
# Minimal object for deleted records
|
|
@@ -58,16 +55,21 @@ module Noiseless
|
|
|
58
55
|
nil
|
|
59
56
|
end
|
|
60
57
|
end
|
|
58
|
+
|
|
59
|
+
# Queued runs raise so the job backend retries instead of recording success.
|
|
60
|
+
module Queued
|
|
61
|
+
def perform(model_class_name, record_id, operation, options = {})
|
|
62
|
+
SearchIndexUpdateJob.perform_now(model_class_name, record_id, operation, options.merge(raise_on_error: true))
|
|
63
|
+
end
|
|
64
|
+
end
|
|
61
65
|
end
|
|
62
66
|
|
|
63
67
|
# ActiveJob integration
|
|
64
68
|
if defined?(ActiveJob::Base)
|
|
65
69
|
class ActiveJobSearchIndexUpdateJob < ActiveJob::Base
|
|
66
|
-
|
|
70
|
+
include SearchIndexUpdateJob::Queued
|
|
67
71
|
|
|
68
|
-
|
|
69
|
-
SearchIndexUpdateJob.perform_now(model_class_name, record_id, operation, options)
|
|
70
|
-
end
|
|
72
|
+
queue_as :default
|
|
71
73
|
end
|
|
72
74
|
end
|
|
73
75
|
|
|
@@ -75,10 +77,7 @@ module Noiseless
|
|
|
75
77
|
if defined?(Sidekiq)
|
|
76
78
|
class SidekiqSearchIndexUpdateJob
|
|
77
79
|
include Sidekiq::Worker
|
|
78
|
-
|
|
79
|
-
def perform(model_class_name, record_id, operation, options = {})
|
|
80
|
-
SearchIndexUpdateJob.perform_now(model_class_name, record_id, operation, options)
|
|
81
|
-
end
|
|
80
|
+
include SearchIndexUpdateJob::Queued
|
|
82
81
|
end
|
|
83
82
|
end
|
|
84
83
|
end
|
data/lib/noiseless/test_case.rb
CHANGED
data/lib/noiseless/version.rb
CHANGED
data/lib/noiseless.rb
CHANGED
|
@@ -11,7 +11,6 @@ require "singleton"
|
|
|
11
11
|
require "async"
|
|
12
12
|
require "async/http/endpoint"
|
|
13
13
|
require "async/http/client"
|
|
14
|
-
require "async/pool"
|
|
15
14
|
require_relative "noiseless/version"
|
|
16
15
|
|
|
17
16
|
module Noiseless
|
|
@@ -96,11 +95,7 @@ module Noiseless
|
|
|
96
95
|
|
|
97
96
|
# Register all connections statically from YAML - no runtime registration
|
|
98
97
|
config.connections_config.each do |name, params|
|
|
99
|
-
|
|
100
|
-
hosts = params[:hosts] || []
|
|
101
|
-
register_params = { adapter: adapter_name, hosts: hosts, timeout: params[:timeout] }
|
|
102
|
-
register_params[:request_timeout] = params[:request_timeout] if params.key?(:request_timeout)
|
|
103
|
-
connections.register(name, **register_params)
|
|
98
|
+
connections.register(name, **params, hosts: params[:hosts] || [])
|
|
104
99
|
end
|
|
105
100
|
end
|
|
106
101
|
|
|
@@ -123,10 +118,6 @@ module Noiseless
|
|
|
123
118
|
loader.setup
|
|
124
119
|
loader.eager_load if defined?(Rails) && Rails.respond_to?(:env) && Rails.env.test?
|
|
125
120
|
|
|
126
|
-
# Manually require response classes since they're in a subdirectory
|
|
127
|
-
require_relative "noiseless/response"
|
|
128
|
-
require_relative "noiseless/response_factory"
|
|
129
|
-
|
|
130
121
|
# Global registry instance
|
|
131
122
|
def self.registry
|
|
132
123
|
ModelRegistry.instance
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: noiseless
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.9.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Abdelkader Boudih
|
|
@@ -16,6 +16,9 @@ dependencies:
|
|
|
16
16
|
- - "~>"
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
18
|
version: '8.1'
|
|
19
|
+
- - ">="
|
|
20
|
+
- !ruby/object:Gem::Version
|
|
21
|
+
version: 8.1.4
|
|
19
22
|
type: :runtime
|
|
20
23
|
prerelease: false
|
|
21
24
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -23,48 +26,51 @@ dependencies:
|
|
|
23
26
|
- - "~>"
|
|
24
27
|
- !ruby/object:Gem::Version
|
|
25
28
|
version: '8.1'
|
|
29
|
+
- - ">="
|
|
30
|
+
- !ruby/object:Gem::Version
|
|
31
|
+
version: 8.1.4
|
|
26
32
|
- !ruby/object:Gem::Dependency
|
|
27
33
|
name: async
|
|
28
34
|
requirement: !ruby/object:Gem::Requirement
|
|
29
35
|
requirements:
|
|
30
36
|
- - "~>"
|
|
31
37
|
- !ruby/object:Gem::Version
|
|
32
|
-
version: '2.
|
|
38
|
+
version: '2.46'
|
|
33
39
|
type: :runtime
|
|
34
40
|
prerelease: false
|
|
35
41
|
version_requirements: !ruby/object:Gem::Requirement
|
|
36
42
|
requirements:
|
|
37
43
|
- - "~>"
|
|
38
44
|
- !ruby/object:Gem::Version
|
|
39
|
-
version: '2.
|
|
45
|
+
version: '2.46'
|
|
40
46
|
- !ruby/object:Gem::Dependency
|
|
41
47
|
name: async-http
|
|
42
48
|
requirement: !ruby/object:Gem::Requirement
|
|
43
49
|
requirements:
|
|
44
50
|
- - "~>"
|
|
45
51
|
- !ruby/object:Gem::Version
|
|
46
|
-
version: '0.
|
|
52
|
+
version: '0.105'
|
|
47
53
|
type: :runtime
|
|
48
54
|
prerelease: false
|
|
49
55
|
version_requirements: !ruby/object:Gem::Requirement
|
|
50
56
|
requirements:
|
|
51
57
|
- - "~>"
|
|
52
58
|
- !ruby/object:Gem::Version
|
|
53
|
-
version: '0.
|
|
59
|
+
version: '0.105'
|
|
54
60
|
- !ruby/object:Gem::Dependency
|
|
55
|
-
name:
|
|
61
|
+
name: io-event
|
|
56
62
|
requirement: !ruby/object:Gem::Requirement
|
|
57
63
|
requirements:
|
|
58
|
-
- - "
|
|
64
|
+
- - ">="
|
|
59
65
|
- !ruby/object:Gem::Version
|
|
60
|
-
version:
|
|
66
|
+
version: 1.22.1
|
|
61
67
|
type: :runtime
|
|
62
68
|
prerelease: false
|
|
63
69
|
version_requirements: !ruby/object:Gem::Requirement
|
|
64
70
|
requirements:
|
|
65
|
-
- - "
|
|
71
|
+
- - ">="
|
|
66
72
|
- !ruby/object:Gem::Version
|
|
67
|
-
version:
|
|
73
|
+
version: 1.22.1
|
|
68
74
|
- !ruby/object:Gem::Dependency
|
|
69
75
|
name: railties
|
|
70
76
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -72,6 +78,9 @@ dependencies:
|
|
|
72
78
|
- - "~>"
|
|
73
79
|
- !ruby/object:Gem::Version
|
|
74
80
|
version: '8.1'
|
|
81
|
+
- - ">="
|
|
82
|
+
- !ruby/object:Gem::Version
|
|
83
|
+
version: 8.1.4
|
|
75
84
|
type: :runtime
|
|
76
85
|
prerelease: false
|
|
77
86
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -79,6 +88,9 @@ dependencies:
|
|
|
79
88
|
- - "~>"
|
|
80
89
|
- !ruby/object:Gem::Version
|
|
81
90
|
version: '8.1'
|
|
91
|
+
- - ">="
|
|
92
|
+
- !ruby/object:Gem::Version
|
|
93
|
+
version: 8.1.4
|
|
82
94
|
- !ruby/object:Gem::Dependency
|
|
83
95
|
name: zeitwerk
|
|
84
96
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -228,13 +240,16 @@ files:
|
|
|
228
240
|
- lib/noiseless/adapters/execution_modules/opensearch_execution.rb
|
|
229
241
|
- lib/noiseless/adapters/execution_modules/pgvector_support.rb
|
|
230
242
|
- lib/noiseless/adapters/execution_modules/postgresql_execution.rb
|
|
243
|
+
- lib/noiseless/adapters/execution_modules/postgresql_query.rb
|
|
231
244
|
- lib/noiseless/adapters/execution_modules/typesense_execution.rb
|
|
245
|
+
- lib/noiseless/adapters/execution_modules/typesense_query.rb
|
|
232
246
|
- lib/noiseless/adapters/indices_api.rb
|
|
233
247
|
- lib/noiseless/adapters/open_search.rb
|
|
234
248
|
- lib/noiseless/adapters/postgresql.rb
|
|
235
249
|
- lib/noiseless/adapters/typesense.rb
|
|
236
250
|
- lib/noiseless/ast.rb
|
|
237
251
|
- lib/noiseless/ast/aggregation.rb
|
|
252
|
+
- lib/noiseless/ast/aggregation_builder.rb
|
|
238
253
|
- lib/noiseless/ast/bool.rb
|
|
239
254
|
- lib/noiseless/ast/bulk.rb
|
|
240
255
|
- lib/noiseless/ast/collapse.rb
|
|
@@ -258,13 +273,17 @@ files:
|
|
|
258
273
|
- lib/noiseless/bulk_importer.rb
|
|
259
274
|
- lib/noiseless/callbacks.rb
|
|
260
275
|
- lib/noiseless/connection_manager.rb
|
|
276
|
+
- lib/noiseless/controller_runtime.rb
|
|
261
277
|
- lib/noiseless/document_manager.rb
|
|
262
278
|
- lib/noiseless/dsl.rb
|
|
279
|
+
- lib/noiseless/embedding.rb
|
|
263
280
|
- lib/noiseless/generators/application_search_generator.rb
|
|
264
281
|
- lib/noiseless/instrumentation.rb
|
|
265
282
|
- lib/noiseless/introspection.rb
|
|
266
283
|
- lib/noiseless/introspection/console.rb
|
|
284
|
+
- lib/noiseless/introspection/mermaid_diagrams.rb
|
|
267
285
|
- lib/noiseless/introspection/query_visualizer.rb
|
|
286
|
+
- lib/noiseless/log_subscriber.rb
|
|
268
287
|
- lib/noiseless/mapping.rb
|
|
269
288
|
- lib/noiseless/mapping_definition_processor.rb
|
|
270
289
|
- lib/noiseless/model.rb
|
|
@@ -272,7 +291,9 @@ files:
|
|
|
272
291
|
- lib/noiseless/multi_search.rb
|
|
273
292
|
- lib/noiseless/pagination.rb
|
|
274
293
|
- lib/noiseless/query_builder.rb
|
|
294
|
+
- lib/noiseless/query_delegation.rb
|
|
275
295
|
- lib/noiseless/railtie.rb
|
|
296
|
+
- lib/noiseless/record_class_resolver.rb
|
|
276
297
|
- lib/noiseless/response.rb
|
|
277
298
|
- lib/noiseless/response/aggregations.rb
|
|
278
299
|
- lib/noiseless/response/empty.rb
|
|
@@ -285,7 +306,6 @@ files:
|
|
|
285
306
|
- lib/noiseless/test_case.rb
|
|
286
307
|
- lib/noiseless/test_helper.rb
|
|
287
308
|
- lib/noiseless/version.rb
|
|
288
|
-
- lib/tasks/benchmark.rake
|
|
289
309
|
- lib/tasks/release.rake
|
|
290
310
|
- lib/tasks/test.rake
|
|
291
311
|
homepage: https://github.com/seuros/noiseless
|
|
@@ -301,14 +321,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
301
321
|
requirements:
|
|
302
322
|
- - ">="
|
|
303
323
|
- !ruby/object:Gem::Version
|
|
304
|
-
version: '
|
|
324
|
+
version: '4.0'
|
|
305
325
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
306
326
|
requirements:
|
|
307
327
|
- - ">="
|
|
308
328
|
- !ruby/object:Gem::Version
|
|
309
329
|
version: '0'
|
|
310
330
|
requirements: []
|
|
311
|
-
rubygems_version: 4.0.
|
|
331
|
+
rubygems_version: 4.0.20
|
|
312
332
|
specification_version: 4
|
|
313
333
|
summary: Async-first Rails search abstraction with multi-backend support
|
|
314
334
|
test_files: []
|
data/lib/tasks/benchmark.rake
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
namespace :benchmark do
|
|
4
|
-
desc "Benchmark search performance across Elasticsearch, OpenSearch, and PostgreSQL"
|
|
5
|
-
task search: :environment do
|
|
6
|
-
require "benchmark/ips"
|
|
7
|
-
require "async"
|
|
8
|
-
|
|
9
|
-
# Use configured connections from Rails
|
|
10
|
-
engines = {
|
|
11
|
-
elasticsearch: :primary,
|
|
12
|
-
opensearch: :secondary,
|
|
13
|
-
postgresql: :postgresql
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
puts "=" * 80
|
|
17
|
-
puts "MULTI-ENGINE SEARCH BENCHMARK"
|
|
18
|
-
puts "=" * 80
|
|
19
|
-
puts "Records: 10k benchmark articles"
|
|
20
|
-
puts "Engines: #{engines.keys.join(', ')}"
|
|
21
|
-
puts "=" * 80
|
|
22
|
-
|
|
23
|
-
# Load PostgreSQL data
|
|
24
|
-
puts "\nš Loading PostgreSQL..."
|
|
25
|
-
Article.delete_all
|
|
26
|
-
fixtures_path = Rails.root.join("../../test/fixtures")
|
|
27
|
-
ActiveRecord::FixtureSet.create_fixtures(fixtures_path, ["benchmark_articles"])
|
|
28
|
-
puts "ā
Loaded #{Article.count} records"
|
|
29
|
-
|
|
30
|
-
# Register PostgreSQL model
|
|
31
|
-
Noiseless.connections.client(:postgresql).register_model(Article, index_name: "articles")
|
|
32
|
-
|
|
33
|
-
puts "\nš Benchmark ready. Run with: bundle exec rake benchmark:search"
|
|
34
|
-
end
|
|
35
|
-
end
|