Browse files

Added support for passing search params (`search_type`, `timeout`, et…

…c.) to search requests

Previously, passing of parameters such as search_type [http://www.elasticsearch.org/guide/reference/api/search/search-type.html]
to search requests wasn't supported, so in cases like getting counts or being interested in just facets,
the workaround was to use `size 0`.

This commit implements passing of parameters to search requests as URL-encoded string.

Just pass the parameters you need to the `search` method:

    s = Tire.search 'articles-test', :search_type => 'count' do
      query { term :tags, 'ruby' }
    end

    p s.results.total
    # => 2
    p s.json['hits']
    # => {"total"=>2, "max_score"=>0.0, "hits"=>[]}

See the possible list of request parameters here:

* http://www.elasticsearch.org/guide/reference/api/search/request-body.html
* http://www.elasticsearch.org/guide/reference/api/search/uri-request.html

Closes #242, closes #198, closes #196, closes #89, closes #88, closes #258, closes #100.
  • Loading branch information...
1 parent 2b3729c commit d764c0d43780d34adf7975161c2575d3d89fd8c2 @karmi karmi committed with karmi Mar 20, 2012
Showing with 72 additions and 13 deletions.
  1. +3 −0 lib/tire.rb
  2. +7 −4 lib/tire/search.rb
  3. +34 −0 test/integration/count_test.rb
  4. +2 −3 test/integration/explanation_test.rb
  5. +26 −6 test/unit/search_test.rb
View
3 lib/tire.rb
@@ -3,6 +3,9 @@
require 'active_model'
require 'hashr'
+require 'active_support/core_ext/object/to_param'
+require 'active_support/core_ext/object/to_query'
+
require 'tire/rubyext/hash'
require 'tire/rubyext/symbol'
require 'tire/logger'
View
11 lib/tire/search.rb
@@ -6,7 +6,7 @@ class Search
attr_reader :indices, :json, :query, :facets, :filters, :options, :explain
- def initialize(indices=nil, options = {}, &block)
+ def initialize(indices=nil, options={}, &block)
@indices = Array(indices)
@types = Array(options.delete(:type))
@options = options
@@ -28,6 +28,10 @@ def url
Configuration.url + @path
end
+ def params
+ @options.empty? ? '' : '?' + @options.to_param
+ end
+
def query(&block)
@query = Query.new
block.arity < 1 ? @query.instance_eval(&block) : block.call(@query)
@@ -87,7 +91,7 @@ def version(value)
end
def perform
- @response = Configuration.client.get(self.url, self.to_json)
+ @response = Configuration.client.get(self.url + self.params, self.to_json)
if @response.failure?
STDERR.puts "[REQUEST FAILED] #{self.to_curl}\n"
raise SearchRequestFailed, @response.to_s
@@ -100,11 +104,10 @@ def perform
end
def to_curl
- %Q|curl -X GET "#{self.url}?pretty=true" -d '#{self.to_json}'|
+ %Q|curl -X GET "#{url}#{params.empty? ? '?' : params.to_s + '&'}pretty=true" -d '#{to_json}'|
end
def to_hash
- #
@options.delete(:payload) || begin
request = {}
request.update( { :query => @query.to_hash } ) if @query
View
34 test/integration/count_test.rb
@@ -0,0 +1,34 @@
+require 'test_helper'
+
+module Tire
+
+ class CountIntegrationTest < Test::Unit::TestCase
+ include Test::Integration
+
+ context "Count" do
+
+ should "return total number of hits for the query, but no hits" do
+ s = Tire.search 'articles-test', :search_type => 'count' do
+ query { term :tags, 'ruby' }
+ end
+
+ assert_equal 2, s.results.total
+ assert_equal 0, s.results.count
+ assert s.results.empty?
+ end
+
+ should "return facets in results" do
+ s = Tire.search 'articles-test' do
+ query { term :tags, 'ruby' }
+ facet('tags') { terms :tags }
+ end
+
+ assert ! s.results.facets['tags'].empty?
+ assert_equal 2, s.results.facets['tags']['terms'].select { |t| t['term'] == 'ruby' }. first['count']
+ assert_equal 1, s.results.facets['tags']['terms'].select { |t| t['term'] == 'python' }.first['count']
+ end
+
+ end
+
+ end
+end
View
5 test/integration/explanation_test.rb
@@ -21,19 +21,18 @@ class ExplanationIntegrationTest < Test::Unit::TestCase
should "add '_explanation' field to the result item" do
# Tire::Configuration.logger STDERR, :level => 'debug'
- s = Tire.search('explanation-test') do
+ s = Tire.search 'explanation-test', :explain => true do
query do
boolean do
should { string 'content:Fox' }
end
end
- explain :true
end
doc = s.results.first
explanation = doc._explanation
-
+
assert explanation.description.include?("product of:")
assert explanation.value < 0.6
assert_not_nil explanation.details
View
32 test/unit/search_test.rb
@@ -35,12 +35,32 @@ class SearchTest < Test::Unit::TestCase
assert_match %r|index/bar/_search|, s.url
end
- should_eventually "allow specify routing query parameter" do
- s = Search::Search.new('index', :routing => 123) do
- query { string 'foo' }
- end
+ should "allow to pass search parameters" do
+ s = Search::Search.new('index', :routing => 123, :timeout => 1) { query { string 'foo' } }
+
+ assert ! s.params.empty?
+
+ assert_match %r|routing=123|, s.params
+ assert_match %r|timeout=1|, s.params
+ end
+
+ should "encode search parameters in the request" do
+ Configuration.client.expects(:get).with do |url, payload|
+ url.include? 'routing=123&timeout=1'
+ end.returns mock_response( { 'hits' => { 'hits' => [ {:_id => 1} ] } }.to_json )
- assert_match %r|routing=123|, s.url
+ Search::Search.new('index', :routing => 123, :timeout => 1) { query { string 'foo' } }.perform
+ end
+
+ should "encode missing params as an empty string" do
+ Configuration.client.expects(:get).with do |url, payload|
+ (! url.include? '?') && (! url.include? '&')
+ end.returns mock_response( { 'hits' => { 'hits' => [ {:_id => 1} ] } }.to_json )
+
+ s = Search::Search.new('index') { query { string 'foo' } }
+ s.perform
+
+ assert_equal '', s.params
end
should "allow to pass block to query" do
@@ -188,7 +208,7 @@ def foo; 'bar'; end
hash = MultiJson.decode( s.to_json )
assert_equal [{'title' => 'desc'}, '_score'], hash['sort']
end
-
+
end
context "facets" do

0 comments on commit d764c0d

Please sign in to comment.