How to Do Complex Querying with Logical Operations by Using Searchkick

How to do complex querying with logical operations by using searchkick

A OR B OR ( C AND D )

Product.search where: {or: [[{brand: 'nike'}, {in-stock: true}, {price: {lte: 12}, color: 'red'}]]} 

A AND B AND ( C OR D )

Product.search where: {brand: 'nike', in-stock: true, or: [ [{price: {lte: 12}}, {color: 'red'}] ]}

Update

(A OR B) AND (C OR D)

 Product.search where: {or: [[ {or: [[{brand: "nike"}, {in-stock: "true"}]]}], [{or: [[{price: 100}, {color: "red"}]]}]]}

Searchkick Aggregation OR

You should be able to achieve your desired result using the or_ parameter in your where clause. There's an example of this in the Searchkick docs, but for your specific scenario, the following should work:

Product.search(
"shower",
fields: [:name],
aggs: [:showers_ids, :accessories_ids, :bath_ids],
where: {
_or: [
{showers_ids: [46, 41]},
{accessories_ids: [104, 102]}
]
}
)

Searchkick where hash optional params

options = {
other_param: other_param
yet_another: yet_another
}

options[:gender] = params[:gender] if params[:gender].present?

Editing to satisfy request below

[:gender, :sex, :colour].each do |s|
options[:s] = params[:s] if params[:s].present?
end

How can I write RSpec tests that make sure records are being reindexed by Searchkick?

I want to make sure that my after_create hooks on Image are causing Product to get reindexed.

You're not testing reindexing, just that reindexing is initiated at the appropriate time. So mocks are the way to go. Test the actual reindexing elsewhere, if you feel that's necessary.

Assuming Image looks something like this:

class Image < ApplicationRecord
belongs_to :product

# Note: the docs suggest after_commit so all saves will be reindexed.
after_commit :reindex_product

def reindex_product
product.reindex
end
end

The test, in RSpec, would look something like...

describe '.create' do
it 'reindexes the product' do
expect(product).to receive(:reindex)

Image.create( product: product, ... )
end
end

# This test illustrates why after_create might be insufficient.
describe '#save' do
it 'reindexes the product' do
expect(product).to receive(:reindex)

image = Image.new( product: product, ... )
image.save!
end
end

Or, if you're using asynchronous reindexing, you would check that a reindexing job was queued.

How do I do a partial match in Elasticsearch?

The point is that the ElasticSearch regex you are using requires a full string match:

Lucene’s patterns are always anchored. The pattern provided must match the entire string.

Thus, to match any character (but a newline), you can use .* pattern:

match: { text: '.*google.*'}
^^ ^^

In ES6+, use regexp insted of match:

"query": {
"regexp": { "text": ".*google.*"}
}

One more variation is for cases when your string can have newlines: match: { text: '(.|\n)*google(.|\n)*'}. This awful (.|\n)* is a must in ElasticSearch because this regex flavor does not allow any [\s\S] workarounds, nor any DOTALL/Singleline flags. "The Lucene regular expression engine is not Perl-compatible but supports a smaller range of operators."

However, if you do not plan to match any complicated patterns and need no word boundary checking, regex search for a mere substring is better performed with a mere wildcard search:

{
"query": {
"wildcard": {
"text": {
"value": "*google*",
"boost": 1.0,
"rewrite": "constant_score"
}
}
}
}

See Wildcard search for more details.

NOTE: The wildcard pattern also needs to match the whole input string, thus

  • google* finds all strings starting with google
  • *google* finds all strings containing google
  • *google finds all strings ending with google

Also, bear in mind the only pair of special characters in wildcard patterns:

?, which matches any single character
*, which can match zero or more characters, including an empty one


Related Topics



Leave a reply



Submit