Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ All notable changes to this project will be documented in this file. The format

### Changed

- **BREAKING**: Restrict match APIs to a single query argument.
- **BREAKING**: Rename relation query methods `matching_all` and `matching_any`
to `match_all` and `match_any`.

Expand Down
2 changes: 1 addition & 1 deletion examples/rag/rag.rb
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ def generate(query, context)
[]
else
MockItem.search(:description)
.match_any(*terms)
.match_any(terms.join(" "))
.with_score
.order(search_score: :desc)
.limit(5)
Expand Down
76 changes: 0 additions & 76 deletions lib/parade_db/arel/README.md

This file was deleted.

21 changes: 9 additions & 12 deletions lib/parade_db/arel/builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def [](column)

def match(
column,
*terms,
term = nil,
tokenizer: nil,
distance: nil,
prefix: nil,
Expand All @@ -35,7 +35,7 @@ def match(
prefix: prefix,
transposition_cost_one: transposition_cost_one
)
rhs = term_query_node(terms)
rhs = term_query_node(term)
rhs = apply_fuzzy(
rhs,
distance: distance,
Expand All @@ -50,7 +50,7 @@ def match(

def match_any(
column,
*terms,
term = nil,
tokenizer: nil,
distance: nil,
prefix: nil,
Expand All @@ -64,7 +64,7 @@ def match_any(
prefix: prefix,
transposition_cost_one: transposition_cost_one
)
rhs = term_query_node(terms)
rhs = term_query_node(term)
rhs = apply_fuzzy(
rhs,
distance: distance,
Expand Down Expand Up @@ -538,19 +538,16 @@ def keyword_arg_node(name, value, quoted_name: false)
)
end

def join_terms(terms)
joined = terms.flatten.compact.map(&:to_s).join(" ")
def join_term(term)
joined = term.to_s
raise ArgumentError, "at least one search term is required" if joined.strip.empty?
joined
end

def term_query_node(terms)
values = terms.flatten.compact
if values.length == 1 && arel_expression?(values.first)
return values.first
end
def term_query_node(term)
return term if arel_expression?(term)

quoted_value(join_terms(values))
quoted_value(join_term(term))
end

def arel_expression?(value)
Expand Down
25 changes: 9 additions & 16 deletions lib/parade_db/arel/predications.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,16 @@ module Predications
TOKENIZER_EXPRESSION = /\A[a-zA-Z_][a-zA-Z0-9_]*(?:(?:::|\.)[a-zA-Z_][a-zA-Z0-9_]*)*(?:\(\s*[a-zA-Z0-9_'".,=\s:-]*\s*\))?\z/.freeze
BUILDER = Builder.new.freeze

def pdb_match(*terms, tokenizer: nil, distance: nil, prefix: nil, transposition_cost_one: nil, boost: nil)
rhs = pdb_term_query_node(terms)
def pdb_match(term = nil, tokenizer: nil, distance: nil, prefix: nil, transposition_cost_one: nil, boost: nil)
rhs = pdb_term_query_node(term)
rhs = pdb_apply_fuzzy(rhs, distance: distance, prefix: prefix, transposition_cost_one: transposition_cost_one)
rhs = pdb_apply_tokenizer(rhs, tokenizer)
rhs = pdb_apply_boost(rhs, boost)
::Arel::Nodes::InfixOperation.new("&&&", self, rhs)
end

def pdb_match_any(*terms, tokenizer: nil, distance: nil, prefix: nil, transposition_cost_one: nil, boost: nil)
rhs = pdb_term_query_node(terms)
def pdb_match_any(term = nil, tokenizer: nil, distance: nil, prefix: nil, transposition_cost_one: nil, boost: nil)
rhs = pdb_term_query_node(term)
rhs = pdb_apply_fuzzy(rhs, distance: distance, prefix: prefix, transposition_cost_one: transposition_cost_one)
rhs = pdb_apply_tokenizer(rhs, tokenizer)
rhs = pdb_apply_boost(rhs, boost)
Expand Down Expand Up @@ -193,20 +193,13 @@ def pdb_quoted(value)
::Arel::Nodes.build_quoted(value)
end

def pdb_join_terms(terms)
joined = terms.flatten.compact.map(&:to_s).join(" ")
raise ArgumentError, "at least one search term is required" if joined.strip.empty?

joined
end
def pdb_term_query_node(term)
return term if pdb_arel_expression?(term)

def pdb_term_query_node(terms)
values = terms.flatten.compact
if values.length == 1 && pdb_arel_expression?(values.first)
return values.first
end
joined = term.to_s
raise ArgumentError, "at least one search term is required" if joined.strip.empty?

pdb_quoted(pdb_join_terms(values))
pdb_quoted(joined)
end

def pdb_arel_expression?(value)
Expand Down
15 changes: 7 additions & 8 deletions lib/parade_db/search_methods.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ module SearchMethods
max_word_length
stopwords
].freeze

# Internal state tracking
attr_accessor :_paradedb_current_field
attr_accessor :_paradedb_facet_fields
Expand Down Expand Up @@ -121,7 +120,7 @@ def search(column)
end

def match_all(
*terms,
term = nil,
tokenizer: nil,
distance: nil,
prefix: nil,
Expand All @@ -132,12 +131,12 @@ def match_all(
require_search_field!

node =
if terms.empty? && tokenizer.nil? && distance.nil? && prefix.nil? && transposition_cost_one.nil?
if term.nil? && tokenizer.nil? && distance.nil? && prefix.nil? && transposition_cost_one.nil?
builder.match_all(_paradedb_current_field, boost: boost, constant_score: constant_score)
else
builder.match(
_paradedb_current_field,
*terms,
term,
tokenizer: tokenizer,
distance: distance,
prefix: prefix,
Expand All @@ -150,7 +149,7 @@ def match_all(
end

def match_any(
*terms,
term,
tokenizer: nil,
distance: nil,
prefix: nil,
Expand All @@ -162,7 +161,7 @@ def match_any(

node = builder.match_any(
_paradedb_current_field,
*terms,
term,
tokenizer: tokenizer,
distance: distance,
prefix: prefix,
Expand All @@ -173,10 +172,10 @@ def match_any(
where(grouped(node))
end

def excluding(*terms)
def excluding(term)
require_search_field!

neg = builder.match(_paradedb_current_field, *terms)
neg = builder.match(_paradedb_current_field, term)
where(grouped(neg.not))
end

Expand Down
14 changes: 7 additions & 7 deletions spec/arel_behavior_integration_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class ArelBehaviorCategory < ActiveRecord::Base

# ---- match (match_all) ----
it "match returns expected rows" do
ids = search(:description).match_all("running", "shoes").order(:id).pluck(:id)
ids = search(:description).match_all("running shoes").order(:id).pluck(:id)
assert_equal [1, 2], ids
end
it "match single term broader results" do
Expand All @@ -41,13 +41,13 @@ class ArelBehaviorCategory < ActiveRecord::Base
end
it "match with boost returns same rows" do
# Boost affects scoring, not result set
ids = search(:description).match_all("running", "shoes", boost: 2).order(:id).pluck(:id)
ids = search(:description).match_all("running shoes", boost: 2).order(:id).pluck(:id)
assert_equal [1, 2], ids
end

# ---- match_any ----
it "match any returns union" do
ids = search(:description).match_any("wireless", "hiking").order(:id).pluck(:id)
ids = search(:description).match_any("wireless hiking").order(:id).pluck(:id)
assert_equal [3, 5], ids
end
it "match any single term" do
Expand Down Expand Up @@ -260,7 +260,7 @@ class ArelBehaviorCategory < ActiveRecord::Base
end
it "with score ordering" do
rows = search(:description)
.match_all("running", "shoes")
.match_all("running shoes")
.with_score
.order(search_score: :desc)
.to_a
Expand Down Expand Up @@ -339,7 +339,7 @@ class ArelBehaviorCategory < ActiveRecord::Base
# ---- with_facets ----
it "with facets returns rows and facets" do
rel = search(:description)
.match_all("running", "shoes")
.match_all("running shoes")
.with_facets(:rating, size: 10)
.order(:id)
.limit(10)
Expand Down Expand Up @@ -374,7 +374,7 @@ class ArelBehaviorCategory < ActiveRecord::Base
# ---- Arel builder executed via where(Arel.sql(...)) ----
it "arel builder match via where" do
builder = ParadeDB::Arel::Builder.new(:products)
predicate = builder.match(:description, "running", "shoes")
predicate = builder.match(:description, "running shoes")
predicate_sql = ParadeDB::Arel.to_sql(predicate, ArelBehaviorProduct.connection)

ids = ArelBehaviorProduct.where(Arel.sql(predicate_sql)).order(:id).pluck(:id)
Expand Down Expand Up @@ -443,7 +443,7 @@ class ArelBehaviorCategory < ActiveRecord::Base
end
it "arel builder results match search api" do
# Verify Arel builder produces identical results to the high-level API
api_ids = search(:description).match_all("running", "shoes").order(:id).pluck(:id)
api_ids = search(:description).match_all("running shoes").order(:id).pluck(:id)

builder = ParadeDB::Arel::Builder.new(:products)
predicate = builder.match(:description, "running shoes")
Expand Down
8 changes: 4 additions & 4 deletions spec/arel_builder_unit_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ def sql(node)
node = @builder.match(:description, "shoes")
assert_equal %("products"."description" &&& 'shoes'), sql(node)
end
it "match multiple terms joined" do
node = @builder.match(:description, "running", "shoes", "lightweight")
it "match query" do
node = @builder.match(:description, "running shoes lightweight")
assert_equal %("products"."description" &&& 'running shoes lightweight'), sql(node)
end
it "match accepts sql function term" do
Expand Down Expand Up @@ -81,8 +81,8 @@ def sql(node)
node = @builder.match_any(:description, "wireless")
assert_equal %("products"."description" ||| 'wireless'), sql(node)
end
it "match any multiple terms" do
node = @builder.match_any(:description, "wireless", "bluetooth", "earbuds")
it "match any query" do
node = @builder.match_any(:description, "wireless bluetooth earbuds")
assert_equal %("products"."description" ||| 'wireless bluetooth earbuds'), sql(node)
end
it "match any accepts sql function term" do
Expand Down
4 changes: 2 additions & 2 deletions spec/arel_integration_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ def sql(node)
end
it "full matrix of operators" do
nodes = []
nodes << @builder.match(:description, "running", "shoes")
nodes << @builder.match_any(:description, "wireless", "bluetooth")
nodes << @builder.match(:description, "running shoes")
nodes << @builder.match_any(:description, "wireless bluetooth")
nodes << @builder.phrase(:description, "running shoes", slop: 2)
nodes << @builder.term(:description, "shose", distance: 2, prefix: false, boost: 2)
nodes << @builder.term(:description, "literal")
Expand Down
8 changes: 4 additions & 4 deletions spec/arel_predications_unit_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ def sql(node)
node = @t[:description].pdb_match("shoes")
assert_equal %("products"."description" &&& 'shoes'), sql(node)
end
it "pdb_match multiple terms joined" do
node = @t[:description].pdb_match("running", "shoes", "lightweight")
it "pdb_match query" do
node = @t[:description].pdb_match("running shoes lightweight")
assert_equal %("products"."description" &&& 'running shoes lightweight'), sql(node)
end
it "pdb_match accepts sql function term" do
Expand All @@ -42,8 +42,8 @@ def sql(node)
node = @t[:description].pdb_match_any("wireless")
assert_equal %("products"."description" ||| 'wireless'), sql(node)
end
it "pdb_match_any multiple terms" do
node = @t[:description].pdb_match_any("wireless", "bluetooth", "earbuds")
it "pdb_match_any query" do
node = @t[:description].pdb_match_any("wireless bluetooth earbuds")
assert_equal %("products"."description" ||| 'wireless bluetooth earbuds'), sql(node)
end
it "pdb_match_any accepts sql function term" do
Expand Down
4 changes: 2 additions & 2 deletions spec/arel_visitor_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ def sql(node)
ParadeDB::Arel.to_sql(node)
end
it "match" do
node = @builder.match(:description, "running", "shoes")
node = @builder.match(:description, "running shoes")
assert_equal %("products"."description" &&& 'running shoes'), sql(node)
end
it "match any" do
node = @builder.match_any(:description, "wireless", "bluetooth")
node = @builder.match_any(:description, "wireless bluetooth")
assert_equal %("products"."description" ||| 'wireless bluetooth'), sql(node)
end
it "match any with tokenizer override" do
Expand Down
Loading
Loading