Class: Stretcher::Server

Inherits:
EsComponent show all
Defined in:
lib/stretcher/server.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from EsComponent

#do_alias, #do_delete_query, #do_refresh, #do_search

Constructor Details

#initialize(uri = 'http://localhost:9200', options = {}) ⇒ Server

Represents a Server context in elastic search. Use with_server when you want to use the block syntax. The options hash takes an optional instance of Logger under :logger.

server = Stretcher::Server.new('http://localhost:9200')

The default implementation here uses the net_http_persistent adapter for faraday. If you would like to use a different HTTP library, or alter other faraday config settings you may specify an optional :faraday_configurator argument, with a Proc as a value. This will be called once with the faraday builder.

For instance: configurator = proc {|builder| builder.adapter :typhoeus Stretcher::Server.new(‘localhost:9200’, :faraday_configurator => configurator)

You may want to set one or both of :read_timeout and :open_timeout, for Faraday’s HTTP settings. The default is read_timeout: 30, open_timeout: 2, which can be quite long in many situations



79
80
81
82
83
84
85
# File 'lib/stretcher/server.rb', line 79

def initialize(uri='http://localhost:9200', options={})
  @request_mtx = Mutex.new
  @uri = uri.to_s
  @uri_components = URI.parse(@uri)
  @http = self.class.build_client(@uri_components, options)
  @logger = self.class.build_logger(options)
end

Instance Attribute Details

#httpObject (readonly)

Returns the value of attribute http.



3
4
5
# File 'lib/stretcher/server.rb', line 3

def http
  @http
end

#loggerObject (readonly)

Returns the value of attribute logger.



3
4
5
# File 'lib/stretcher/server.rb', line 3

def logger
  @logger
end

#uriObject (readonly)

Returns the value of attribute uri.



3
4
5
# File 'lib/stretcher/server.rb', line 3

def uri
  @uri
end

Class Method Details

.build_client(uri_components, options = {}) ⇒ Object

Internal use only. Returns a properly configured HTTP client when initializing an instance



7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/stretcher/server.rb', line 7

def self.build_client(uri_components, options={})
  http = Faraday.new(:url => uri_components) do |builder|
    builder.response :mashify
    builder.response :multi_json, :content_type => /\bjson$/

    builder.request :multi_json

    builder.options[:timeout] = options[:read_timeout] || 30
    builder.options[:open_timeout] = options[:open_timeout] || 2

    if faraday_configurator = options[:faraday_configurator]
      faraday_configurator.call(builder)
    else
      builder.adapter :excon
    end
  end
  http.headers = {
    :accept =>  'application/json',
    :user_agent => "Stretcher Ruby Gem #{Stretcher::VERSION}",
    "Content-Type" => "application/json"
  }

  if uri_components.user || uri_components.password
    http.basic_auth(uri_components.user, uri_components.password)
  end

  http
end

.build_logger(options) ⇒ Object

Internal use only. Builds a logger when initializing an instance



38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/stretcher/server.rb', line 38

def self.build_logger(options)
  logger = options[:logger] || Logger.new(STDOUT)

  # We don't want to override the formatter if an external logger is used
  if !options[:logger]
    log_level = options[:log_level] || :warn
    logger.level = Logger.const_get(log_level.to_s.upcase)
    logger.formatter = proc do |severity, datetime, progname, msg|
      "[Stretcher][#{severity}]: #{msg}\n"
    end
  end
  
  logger
end

.with_server(*args) {|s| ... } ⇒ Object

Instantiate a new instance in a manner convenient for using the block syntax. Can be used interchangably with Stretcher::Server.new but will return the value of the block if present. See the regular constructor for full options.

Yields:

  • (s)


56
57
58
59
# File 'lib/stretcher/server.rb', line 56

def self.with_server(*args)
  s = self.new(*args)
  yield s
end

Instance Method Details

#aliases(body = nil) ⇒ Object

Implements the Aliases API Ex: server.aliases({add: {index: :my_index, alias: :my_alias}}) as per: www.elasticsearch.org/guide/reference/api/admin-indices-aliases.html



192
193
194
195
196
197
198
# File 'lib/stretcher/server.rb', line 192

def aliases(body=nil)
  if body
    request(:post, path_uri("/_aliases"), {}, body)
  else
    request(:get, path_uri("/_aliases"))
  end
end

#analyze(text, analysis_params) ⇒ Object

Implements the Analyze API Ex:

server.analyze("Candles", analyzer: :snowball)
# => #<Hashie::Mash tokens=[#<Hashie::Mash end_offset=7 position=1 start_offset=0 token="candl" type="<ALPHANUM>">]>

as per: www.elasticsearch.org/guide/reference/api/admin-indices-analyze.html



182
183
184
185
186
# File 'lib/stretcher/server.rb', line 182

def analyze(text, analysis_params)
  request(:get, path_uri("/_analyze"), analysis_params) do |req|
    req.body = text
  end
end

#bulk(data, options = {}) ⇒ Object

Perform a raw bulk operation. You probably want to use Stretcher::Index#bulk_index which properly formats a bulk index request.



108
109
110
# File 'lib/stretcher/server.rb', line 108

def bulk(data, options={})
  request(:post, path_uri("/_bulk"), options, data)
end

#cluster(&block) ⇒ Object

Returns the Stretcher::Cluster for this server Optionally takes a block, which will be passed a single arg with the Cluster object. The block returns the evaluated value of the block.



101
102
103
104
# File 'lib/stretcher/server.rb', line 101

def cluster(&block)
  cluster = Cluster.new(self, :logger => logger)
  block ? block.call(cluster) : cluster
end

#get_alias(alias_name_or_prefix) ⇒ Object



200
201
202
# File 'lib/stretcher/server.rb', line 200

def get_alias(alias_name_or_prefix)
  do_alias(alias_name_or_prefix)
end

#index(name, &block) ⇒ Object

Returns a Stretcher::Index object for the index name. Optionally takes a block, which will be passed a single arg with the Index obj The block syntax returns the evaluated value of the block

my_server.index(:foo) # => #<Stretcher::Index ...>
my_server.index(:foo) {|idx| 1+1} # => 2


93
94
95
96
# File 'lib/stretcher/server.rb', line 93

def index(name, &block)
  idx = Index.new(self, name, :logger => logger)
  block ? block.call(idx) : idx
end

#legacy_mget(body) ⇒ Object

legacy implementation of mget for backwards compat



173
174
175
# File 'lib/stretcher/server.rb', line 173

def legacy_mget(body)
  request(:get, path_uri("/_mget"), {}, body)
end

#mget(docs = [], arg_opts = {}) ⇒ Object

Retrieves multiple documents, possibly from multiple indexes Takes an array of docs, returns an array of docs as per: www.elasticsearch.org/guide/reference/api/multi-get.html If you pass :exists => true as the second argument it will not return stubs for missing documents. :exists => false works in reverse



157
158
159
160
161
162
163
164
165
166
167
168
169
170
# File 'lib/stretcher/server.rb', line 157

def mget(docs=[], arg_opts={})
  #Legacy API
  return legacy_mget(docs) if docs.is_a?(Hash)
  
  opts = {:exists => true}.merge(arg_opts)
  
  res = request(:get, path_uri("/_mget"), {}, {:docs => docs})[:docs]
  if opts.has_key?(:exists)
    match = opts[:exists]
    res.select {|d| d[:exists] == match}
  else
    res
  end
end

#msearch(body = []) ⇒ Object

Takes an array of msearch data as per www.elasticsearch.org/guide/reference/api/multi-search.html Should look something like:

data = [
  {"index" : "test"}
  {"query" : {"match_all" : {}}, "from" : 0, "size" : 10}
  {"index" : "test", "search_type" : "count"}
  {"query" : {"match_all" : {}}}
]
server.msearch(data)

Raises:

  • (ArgumentError)


138
139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/stretcher/server.rb', line 138

def msearch(body=[])
  raise ArgumentError, "msearch takes an array!" unless body.is_a?(Array)
  fmt_body = body.map {|l| MultiJson.dump(l) }.join("\n") << "\n"

  res = request(:get, path_uri("/_msearch"), {}, fmt_body)

  errors = res.responses.map(&:error).compact
  if !errors.empty?
    raise RequestError.new(res), "Could not msearch #{errors.inspect}"
  end

  res['responses'].map {|r| SearchResults.new(r)}
end

#path_uri(path = nil) ⇒ Object

Full path to the server root dir



210
211
212
# File 'lib/stretcher/server.rb', line 210

def path_uri(path=nil)
  URI.join(@uri.to_s, "#{@uri_components.path}/#{path.to_s}").to_s
end

#refreshObject

Perform a refresh, making all indexed documents available



205
206
207
# File 'lib/stretcher/server.rb', line 205

def refresh
  do_refresh
end

#request(method, path, params = {}, body = nil, headers = {}, &block) ⇒ Object

Handy way to query the server, returning only the body Will raise an exception when the status is not in the 2xx range



216
217
218
219
220
221
222
223
224
225
226
227
228
229
# File 'lib/stretcher/server.rb', line 216

def request(method, path, params={}, body=nil, headers={}, &block)
  req = http.build_request(method)
  req.path = path
  req.params.update(Util.clean_params(params)) if params
  req.body = body
  req.headers.update(headers) if headers
  block.call(req) if block
  logger.debug { Util.curl_format(req) }

  @request_mtx.synchronize {
    env = req.to_env(http)
    check_response(http.app.call(env))
  }
end

#statsObject

Retrieves stats for this server



113
114
115
# File 'lib/stretcher/server.rb', line 113

def stats
  request :get, path_uri("/_stats")
end

#statusObject

Retrieves status for this server



118
119
120
# File 'lib/stretcher/server.rb', line 118

def status
  request :get, path_uri("/_status")
end

#up?Boolean

Returns true if the server is currently reachable, raises an error otherwise

Returns:

  • (Boolean)


123
124
125
126
# File 'lib/stretcher/server.rb', line 123

def up?
  request(:get, path_uri)
  true
end