redis 5.4.1 → 6.0.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/CHANGELOG.md +52 -1
- data/README.md +165 -12
- data/lib/redis/client.rb +42 -10
- data/lib/redis/commands/geo.rb +108 -6
- data/lib/redis/commands/hashes.rb +166 -2
- data/lib/redis/commands/keys.rb +5 -1
- data/lib/redis/commands/lists.rb +93 -0
- data/lib/redis/commands/modules/json.rb +530 -0
- data/lib/redis/commands/modules/search/aggregation.rb +418 -0
- data/lib/redis/commands/modules/search/dialect.rb +14 -0
- data/lib/redis/commands/modules/search/field.rb +306 -0
- data/lib/redis/commands/modules/search/hybrid.rb +359 -0
- data/lib/redis/commands/modules/search/index.rb +351 -0
- data/lib/redis/commands/modules/search/index_definition.rb +114 -0
- data/lib/redis/commands/modules/search/miscellaneous.rb +607 -0
- data/lib/redis/commands/modules/search/query.rb +738 -0
- data/lib/redis/commands/modules/search/result.rb +488 -0
- data/lib/redis/commands/modules/search/schema.rb +211 -0
- data/lib/redis/commands/modules/search.rb +19 -0
- data/lib/redis/commands/sets.rb +41 -0
- data/lib/redis/commands/sorted_sets.rb +0 -1
- data/lib/redis/commands/streams.rb +28 -8
- data/lib/redis/commands.rb +30 -10
- data/lib/redis/distributed.rb +271 -1
- data/lib/redis/lib_identity.rb +105 -0
- data/lib/redis/subscribe.rb +1 -1
- data/lib/redis/version.rb +1 -1
- data/lib/redis.rb +141 -11
- metadata +22 -9
|
@@ -0,0 +1,418 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Redis
|
|
4
|
+
module Commands
|
|
5
|
+
module Search
|
|
6
|
+
# A fluent builder for FT.AGGREGATE requests.
|
|
7
|
+
#
|
|
8
|
+
# Aggregation steps (+group_by+, +sort_by+, +apply+, +filter+, +limit+, +load+) are
|
|
9
|
+
# chained on; each returns +self+. {#to_redis_args} renders them into the argument array
|
|
10
|
+
# passed to +FT.AGGREGATE+, emitting +LOAD+ steps before +DIALECT+ and the remaining steps
|
|
11
|
+
# after it.
|
|
12
|
+
#
|
|
13
|
+
# @example
|
|
14
|
+
# req = Redis::Commands::Search::AggregateRequest.new("*")
|
|
15
|
+
# .group_by("@category", Redis::Commands::Search::Reducers.count(alias_name: "n"))
|
|
16
|
+
class AggregateRequest
|
|
17
|
+
# @param query [String] the aggregation query string (defaults to "*")
|
|
18
|
+
# @param with_cursor [Boolean] emit +WITHCURSOR+ to page results with a cursor
|
|
19
|
+
# @param cursor_count [Integer, nil] the cursor +COUNT+ (batch size)
|
|
20
|
+
# @param cursor_max_idle [Integer, nil] the cursor +MAXIDLE+ in milliseconds
|
|
21
|
+
# @param dialect [Integer] the query +DIALECT+ version (defaults to {DEFAULT_DIALECT})
|
|
22
|
+
def initialize(query = "*", with_cursor: false, cursor_count: nil, cursor_max_idle: nil,
|
|
23
|
+
dialect: DEFAULT_DIALECT)
|
|
24
|
+
@query = query
|
|
25
|
+
@with_cursor = with_cursor
|
|
26
|
+
@cursor_count = cursor_count
|
|
27
|
+
@cursor_max_idle = cursor_max_idle
|
|
28
|
+
@dialect = dialect
|
|
29
|
+
@steps = []
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Add a +GROUPBY+ step with optional +REDUCE+ functions.
|
|
33
|
+
#
|
|
34
|
+
# @param fields [String, Array<String>] the field(s) to group by
|
|
35
|
+
# @param reducers [Array<Reducers>] the reducers applied to each group
|
|
36
|
+
# @return [self]
|
|
37
|
+
def group_by(fields, *reducers)
|
|
38
|
+
step = ["GROUPBY", Array(fields).size.to_s, *Array(fields)]
|
|
39
|
+
reducers.each do |reducer|
|
|
40
|
+
step.concat(["REDUCE", reducer.name, reducer.args.size.to_s])
|
|
41
|
+
step.concat(reducer.args)
|
|
42
|
+
step.concat(["AS", reducer.alias_name]) if reducer.alias_name
|
|
43
|
+
end
|
|
44
|
+
@steps << step.flatten
|
|
45
|
+
self
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Add a +SORTBY+ step.
|
|
49
|
+
#
|
|
50
|
+
# @param sort_by_fields [Array<Asc, Desc, String>] the fields to sort by; +Asc+/+Desc+
|
|
51
|
+
# wrappers carry an explicit direction, plain strings sort with the server default
|
|
52
|
+
# @param max [Integer, nil] limit the sort to the top +MAX+ results
|
|
53
|
+
# @return [self]
|
|
54
|
+
def sort_by(*sort_by_fields, max: nil)
|
|
55
|
+
# Count total arguments (field + order for each)
|
|
56
|
+
nargs = sort_by_fields.sum do |field|
|
|
57
|
+
field.is_a?(Asc) || field.is_a?(Desc) ? 2 : 1
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
step = ["SORTBY", nargs]
|
|
61
|
+
sort_by_fields.each do |field|
|
|
62
|
+
if field.is_a?(Asc) || field.is_a?(Desc)
|
|
63
|
+
step << field.name << field.order
|
|
64
|
+
else
|
|
65
|
+
step << field
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
step << "MAX" << max if max
|
|
69
|
+
@steps << step
|
|
70
|
+
self
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Add one +APPLY+ step per expression.
|
|
74
|
+
#
|
|
75
|
+
# @param expressions [Hash{String, Symbol => String}] map of result alias => expression
|
|
76
|
+
# @return [self]
|
|
77
|
+
def apply(expressions)
|
|
78
|
+
expressions.each do |as, expression|
|
|
79
|
+
@steps << ["APPLY", expression, "AS", as.to_s]
|
|
80
|
+
end
|
|
81
|
+
self
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Add a +LIMIT+ (paging) step.
|
|
85
|
+
#
|
|
86
|
+
# @param offset [Integer] the index of the first row to return
|
|
87
|
+
# @param num [Integer] the maximum number of rows to return
|
|
88
|
+
# @return [self]
|
|
89
|
+
def limit(offset, num)
|
|
90
|
+
@steps << ["LIMIT", offset, num]
|
|
91
|
+
self
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# Add a +FILTER+ step that keeps rows matching +expression+.
|
|
95
|
+
#
|
|
96
|
+
# @param expression [String] the filter expression
|
|
97
|
+
# @return [self]
|
|
98
|
+
def filter(expression)
|
|
99
|
+
@steps << ["FILTER", expression]
|
|
100
|
+
self
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Add a +LOAD+ step. With no fields, loads all attributes (+LOAD *+).
|
|
104
|
+
#
|
|
105
|
+
# @param fields [Array<String>] the fields to load (empty loads all)
|
|
106
|
+
# @return [self]
|
|
107
|
+
def load(*fields)
|
|
108
|
+
@steps << if fields.empty?
|
|
109
|
+
["LOAD", "*"]
|
|
110
|
+
else
|
|
111
|
+
["LOAD", fields.size, *fields.flatten]
|
|
112
|
+
end
|
|
113
|
+
self
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# Include the document scores in the aggregation (+ADDSCORES+).
|
|
117
|
+
#
|
|
118
|
+
# @param add_scores [Boolean] whether to emit +ADDSCORES+
|
|
119
|
+
# @return [self]
|
|
120
|
+
def add_scores(add_scores: true)
|
|
121
|
+
@add_scores = add_scores
|
|
122
|
+
self
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# Set the query +DIALECT+ version.
|
|
126
|
+
#
|
|
127
|
+
# @param dialect_version [Integer] the dialect version
|
|
128
|
+
# @return [self]
|
|
129
|
+
def dialect(dialect_version)
|
|
130
|
+
@dialect = dialect_version
|
|
131
|
+
self
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# Render the request into the +FT.AGGREGATE+ argument array.
|
|
135
|
+
#
|
|
136
|
+
# +LOAD+ steps are emitted before +DIALECT+ and all other steps after it.
|
|
137
|
+
#
|
|
138
|
+
# @return [Array] the argument token array (query string first)
|
|
139
|
+
def to_redis_args
|
|
140
|
+
args = [@query]
|
|
141
|
+
if @with_cursor
|
|
142
|
+
args << "WITHCURSOR"
|
|
143
|
+
args << "COUNT" << @cursor_count if @cursor_count
|
|
144
|
+
args << "MAXIDLE" << @cursor_max_idle if @cursor_max_idle
|
|
145
|
+
end
|
|
146
|
+
args << "ADDSCORES" if @add_scores
|
|
147
|
+
# Add LOAD steps first (before DIALECT)
|
|
148
|
+
load_steps = @steps.select { |step| step[0] == "LOAD" }
|
|
149
|
+
load_steps.each { |step| args.concat(step) }
|
|
150
|
+
|
|
151
|
+
args << "DIALECT" << @dialect if @dialect
|
|
152
|
+
|
|
153
|
+
# Add remaining steps (after DIALECT)
|
|
154
|
+
other_steps = @steps.reject { |step| step[0] == "LOAD" }
|
|
155
|
+
other_steps.each { |step| args.concat(step) }
|
|
156
|
+
args
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
# Wraps a field name with an ascending (+ASC+) sort order for {AggregateRequest#sort_by}.
|
|
161
|
+
class Asc
|
|
162
|
+
# @return [String] the field name
|
|
163
|
+
# @return [String] the order keyword, always "ASC"
|
|
164
|
+
attr_reader :name, :order
|
|
165
|
+
|
|
166
|
+
# @param name [String] the field name to sort ascending
|
|
167
|
+
def initialize(name)
|
|
168
|
+
@name = name
|
|
169
|
+
@order = 'ASC'
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
# Wraps a field name with a descending (+DESC+) sort order for {AggregateRequest#sort_by}.
|
|
174
|
+
class Desc
|
|
175
|
+
# @return [String] the field name
|
|
176
|
+
# @return [String] the order keyword, always "DESC"
|
|
177
|
+
attr_reader :name, :order
|
|
178
|
+
|
|
179
|
+
# @param name [String] the field name to sort descending
|
|
180
|
+
def initialize(name)
|
|
181
|
+
@name = name
|
|
182
|
+
@order = 'DESC'
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
# Factory for the +REDUCE+ functions used inside {AggregateRequest#group_by}.
|
|
187
|
+
#
|
|
188
|
+
# Each class method returns a +Reducers+ instance carrying the function name, its
|
|
189
|
+
# arguments, and an optional result alias.
|
|
190
|
+
#
|
|
191
|
+
# @example
|
|
192
|
+
# Redis::Commands::Search::Reducers.sum("@price", alias_name: "total")
|
|
193
|
+
class Reducers
|
|
194
|
+
# Build a +COUNT+ reducer.
|
|
195
|
+
#
|
|
196
|
+
# @param alias_name [String, nil] the result alias
|
|
197
|
+
# @return [Reducers]
|
|
198
|
+
def self.count(alias_name: nil)
|
|
199
|
+
new("COUNT", alias_name: alias_name)
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
# Build a +COUNT_DISTINCT+ reducer.
|
|
203
|
+
#
|
|
204
|
+
# @param property [String] the property to count distinct values of
|
|
205
|
+
# @param alias_name [String, nil] the result alias
|
|
206
|
+
# @return [Reducers]
|
|
207
|
+
def self.count_distinct(property, alias_name: nil)
|
|
208
|
+
new("COUNT_DISTINCT", property, alias_name: alias_name)
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
# Build a +COUNT_DISTINCTISH+ (approximate distinct count) reducer.
|
|
212
|
+
#
|
|
213
|
+
# @param property [String] the property to count distinct values of
|
|
214
|
+
# @param alias_name [String, nil] the result alias
|
|
215
|
+
# @return [Reducers]
|
|
216
|
+
def self.count_distinctish(property, alias_name: nil)
|
|
217
|
+
new("COUNT_DISTINCTISH", property, alias_name: alias_name)
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
# Build a +SUM+ reducer.
|
|
221
|
+
#
|
|
222
|
+
# @param property [String] the property to sum
|
|
223
|
+
# @param alias_name [String, nil] the result alias
|
|
224
|
+
# @return [Reducers]
|
|
225
|
+
def self.sum(property, alias_name: nil)
|
|
226
|
+
new("SUM", property, alias_name: alias_name)
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
# Build a +MIN+ reducer.
|
|
230
|
+
#
|
|
231
|
+
# @param property [String] the property to take the minimum of
|
|
232
|
+
# @param alias_name [String, nil] the result alias
|
|
233
|
+
# @return [Reducers]
|
|
234
|
+
def self.min(property, alias_name: nil)
|
|
235
|
+
new("MIN", property, alias_name: alias_name)
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
# Build a +MAX+ reducer.
|
|
239
|
+
#
|
|
240
|
+
# @param property [String] the property to take the maximum of
|
|
241
|
+
# @param alias_name [String, nil] the result alias
|
|
242
|
+
# @return [Reducers]
|
|
243
|
+
def self.max(property, alias_name: nil)
|
|
244
|
+
new("MAX", property, alias_name: alias_name)
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
# Build an +AVG+ reducer.
|
|
248
|
+
#
|
|
249
|
+
# @param property [String] the property to average
|
|
250
|
+
# @param alias_name [String, nil] the result alias
|
|
251
|
+
# @return [Reducers]
|
|
252
|
+
def self.avg(property, alias_name: nil)
|
|
253
|
+
new("AVG", property, alias_name: alias_name)
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
# Build a +STDDEV+ (standard deviation) reducer.
|
|
257
|
+
#
|
|
258
|
+
# @param property [String] the property to compute the standard deviation of
|
|
259
|
+
# @param alias_name [String, nil] the result alias
|
|
260
|
+
# @return [Reducers]
|
|
261
|
+
def self.stddev(property, alias_name: nil)
|
|
262
|
+
new("STDDEV", property, alias_name: alias_name)
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
# Build a +QUANTILE+ reducer.
|
|
266
|
+
#
|
|
267
|
+
# @param property [String] the property to compute the quantile of
|
|
268
|
+
# @param quantile [Float] the quantile in the range 0..1
|
|
269
|
+
# @param alias_name [String, nil] the result alias
|
|
270
|
+
# @return [Reducers]
|
|
271
|
+
def self.quantile(property, quantile, alias_name: nil)
|
|
272
|
+
new("QUANTILE", property, quantile, alias_name: alias_name)
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
# Build a +TOLIST+ reducer (collects distinct values into a list).
|
|
276
|
+
#
|
|
277
|
+
# @param property [String] the property to collect
|
|
278
|
+
# @param alias_name [String, nil] the result alias
|
|
279
|
+
# @return [Reducers]
|
|
280
|
+
def self.tolist(property, alias_name: nil)
|
|
281
|
+
new("TOLIST", property, alias_name: alias_name)
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
# Build a +FIRST_VALUE+ reducer, optionally ordered by another property.
|
|
285
|
+
#
|
|
286
|
+
# @param property [String] the property whose first value is taken
|
|
287
|
+
# @param alias_name [String, nil] the result alias
|
|
288
|
+
# @param sort_by [String, nil] the property to order by before taking the first value
|
|
289
|
+
# @param sort_order [Symbol, String, nil] the sort direction ("ASC"/"DESC", default "ASC")
|
|
290
|
+
# @return [Reducers]
|
|
291
|
+
def self.first_value(property, alias_name: nil, sort_by: nil, sort_order: nil)
|
|
292
|
+
args = [property]
|
|
293
|
+
if sort_by
|
|
294
|
+
args << "BY" << sort_by
|
|
295
|
+
args << (sort_order || "ASC").to_s.upcase
|
|
296
|
+
end
|
|
297
|
+
new("FIRST_VALUE", *args, alias_name: alias_name)
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
# Build a +RANDOM_SAMPLE+ reducer.
|
|
301
|
+
#
|
|
302
|
+
# @param property [String] the property to sample
|
|
303
|
+
# @param sample_size [Integer] the number of values to sample
|
|
304
|
+
# @param alias_name [String, nil] the result alias
|
|
305
|
+
# @return [Reducers]
|
|
306
|
+
def self.random_sample(property, sample_size, alias_name: nil)
|
|
307
|
+
new("RANDOM_SAMPLE", property, sample_size, alias_name: alias_name)
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
# Build a +COLLECT+ reducer, which gathers each group's rows, projects a chosen set of
|
|
311
|
+
# fields, optionally deduplicates, sorts and limits them, and emits them as an array of
|
|
312
|
+
# per-entry maps under the reducer alias.
|
|
313
|
+
#
|
|
314
|
+
# Field and sort-key names must carry an +@+ prefix on the wire (like the other reducers,
|
|
315
|
+
# the caller supplies it); output map keys are the same names with the +@+ stripped.
|
|
316
|
+
#
|
|
317
|
+
# @example top 5 per group by rating
|
|
318
|
+
# Reducers.collect(
|
|
319
|
+
# fields: ["@title", "@rating"],
|
|
320
|
+
# sort_by: [Desc.new("@rating")],
|
|
321
|
+
# limit: [0, 5],
|
|
322
|
+
# alias_name: "top"
|
|
323
|
+
# )
|
|
324
|
+
#
|
|
325
|
+
# @param fields [Symbol, Array<String>] +:all+ emits +FIELDS *+ (projects the fields the
|
|
326
|
+
# pipeline has materialized at this stage — not a whole-document fetch); an Array emits
|
|
327
|
+
# +FIELDS <count> <@field> ...+
|
|
328
|
+
# @param distinct [Boolean] emit +DISTINCT+ to deduplicate entries. NOTE: not yet
|
|
329
|
+
# implemented server-side; sending it currently fails parsing. Kept for forward
|
|
330
|
+
# compatibility — do not rely on it until the server ships it.
|
|
331
|
+
# @param sort_by [Array<String, Asc, Desc>, nil] sort keys; a plain String sorts ascending
|
|
332
|
+
# (the default), an +Asc+/+Desc+ wrapper sets the direction explicitly. NOTE: +SORTBY+
|
|
333
|
+
# without +limit+ returns at most 10 entries per group (the server default).
|
|
334
|
+
# @param limit [Array(Integer, Integer), nil] a +[offset, count]+ pair emitting
|
|
335
|
+
# +LIMIT <offset> <count>+; with +sort_by+ this is a bounded top-N selection
|
|
336
|
+
# @param alias_name [String, nil] the reducer output column name (+AS+)
|
|
337
|
+
# @return [Reducers]
|
|
338
|
+
# @raise [ArgumentError] if +fields+ is an empty list and not +:all+
|
|
339
|
+
def self.collect(fields:, distinct: false, sort_by: nil, limit: nil, alias_name: nil)
|
|
340
|
+
tokens = collect_fields_tokens(fields)
|
|
341
|
+
tokens << "DISTINCT" if distinct
|
|
342
|
+
tokens.concat(collect_sortby_tokens(sort_by))
|
|
343
|
+
tokens.concat(["LIMIT", *limit]) if limit
|
|
344
|
+
|
|
345
|
+
new("COLLECT", *tokens, alias_name: alias_name)
|
|
346
|
+
end
|
|
347
|
+
|
|
348
|
+
# Render the +FIELDS+ clause tokens for {collect}.
|
|
349
|
+
def self.collect_fields_tokens(fields)
|
|
350
|
+
return ["FIELDS", "*"] if fields == :all
|
|
351
|
+
|
|
352
|
+
fields = Array(fields)
|
|
353
|
+
raise ArgumentError, "collect fields must be :all or a non-empty list" if fields.empty?
|
|
354
|
+
|
|
355
|
+
["FIELDS", fields.size.to_s, *fields]
|
|
356
|
+
end
|
|
357
|
+
private_class_method :collect_fields_tokens
|
|
358
|
+
|
|
359
|
+
# Render the optional +SORTBY+ clause tokens for {collect}. Each Asc/Desc wrapper emits a
|
|
360
|
+
# name and its direction (2 tokens); a plain String emits just the name (ASC is implicit).
|
|
361
|
+
def self.collect_sortby_tokens(sort_by)
|
|
362
|
+
return [] if sort_by.nil? || sort_by.empty?
|
|
363
|
+
|
|
364
|
+
sort_tokens = sort_by.flat_map do |field|
|
|
365
|
+
field.is_a?(Asc) || field.is_a?(Desc) ? [field.name, field.order] : [field]
|
|
366
|
+
end
|
|
367
|
+
["SORTBY", sort_tokens.size.to_s, *sort_tokens]
|
|
368
|
+
end
|
|
369
|
+
private_class_method :collect_sortby_tokens
|
|
370
|
+
|
|
371
|
+
# @return [String] the reducer function name
|
|
372
|
+
# @return [Array] the reducer arguments
|
|
373
|
+
# @return [String, nil] the result alias
|
|
374
|
+
attr_reader :name, :args, :alias_name
|
|
375
|
+
|
|
376
|
+
# @param name [String] the reducer function name
|
|
377
|
+
# @param args [Array] the reducer arguments
|
|
378
|
+
# @param alias_name [String, nil] the result alias
|
|
379
|
+
def initialize(name, *args, alias_name: nil)
|
|
380
|
+
@name = name
|
|
381
|
+
@args = args
|
|
382
|
+
@alias_name = alias_name
|
|
383
|
+
end
|
|
384
|
+
|
|
385
|
+
# Set the result alias (+AS+) for this reducer.
|
|
386
|
+
#
|
|
387
|
+
# @param alias_name [String] the result alias
|
|
388
|
+
# @return [self]
|
|
389
|
+
def as(alias_name)
|
|
390
|
+
@alias_name = alias_name
|
|
391
|
+
self
|
|
392
|
+
end
|
|
393
|
+
end
|
|
394
|
+
|
|
395
|
+
# Represents an +FT.CURSOR+ read for paging through aggregation results.
|
|
396
|
+
class Cursor
|
|
397
|
+
# @return [Integer] the cursor id
|
|
398
|
+
# @return [Integer] the +COUNT+ (batch size, 0 to omit)
|
|
399
|
+
attr_accessor :cid, :count
|
|
400
|
+
|
|
401
|
+
# @param cid [Integer] the cursor id returned by a prior aggregation
|
|
402
|
+
def initialize(cid)
|
|
403
|
+
@cid = cid
|
|
404
|
+
@count = 0
|
|
405
|
+
end
|
|
406
|
+
|
|
407
|
+
# Render the cursor arguments for +FT.CURSOR READ+.
|
|
408
|
+
#
|
|
409
|
+
# @return [Array<String>] the argument token array
|
|
410
|
+
def build_args
|
|
411
|
+
args = [@cid.to_s]
|
|
412
|
+
args.concat(["COUNT", @count.to_s]) if @count > 0
|
|
413
|
+
args
|
|
414
|
+
end
|
|
415
|
+
end
|
|
416
|
+
end
|
|
417
|
+
end
|
|
418
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Redis
|
|
4
|
+
module Commands
|
|
5
|
+
module Search
|
|
6
|
+
# Default query dialect used for FT.SEARCH and FT.AGGREGATE
|
|
7
|
+
# +DEFAULT_DIALECT+. Dialect 2 is the recommended baseline: it supports modern query syntax
|
|
8
|
+
# such as vector (KNN) and geoshape predicates, whereas the server's built-in default is
|
|
9
|
+
# dialect 1. Override per query via {Query#dialect} / {AggregateRequest#dialect} or the
|
|
10
|
+
# +dialect:+ option to +ft_search+/+ft_aggregate+.
|
|
11
|
+
DEFAULT_DIALECT = 2
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|