class Sensei::Client

Constants

DATA_TRANSACTION_KEY
DEFAULT_FACET_OPTIONS
TEST_TRANSACTION_KEY

Attributes

search_timeout[RW]

Public Class Methods

begin_transaction(key) click to toggle source
# File lib/sensei/client.rb, line 43
def self.begin_transaction key
  Thread.current[key] ||= []
  Thread.current[key] << []
end
configure(path = "config/sensei.yml") { |self| ... } click to toggle source
# File lib/sensei/client.rb, line 15
def self.configure(path = "config/sensei.yml")
  if File.exists? path
    config = YAML.load(ERB.new(File.read(path)).result)

    # Limit config to specific environment if Rails is defined
    defined? ::Rails and
      config = config[::Rails.env]

    self.sensei_hosts      = config['sensei_hosts']
    self.sensei_port       = config['sensei_port']
    self.http_kafka_port   = config['http_kafka_port']
    self.uid_key           = config['uid_key']
    self.http_kafka_hosts  = config['http_kafka_hosts']
    self.fake_update       = config['fake_update'] || false
  end

  yield self if block_given?
end
construct(options={}) click to toggle source
# File lib/sensei/client.rb, line 200
def self.construct options={}, &block
  out = self.new(options)
  search_query = class_eval(&block)
  out.query(search_query)
end
current_data_transaction() click to toggle source
# File lib/sensei/client.rb, line 35
def self.current_data_transaction
  Thread.current[DATA_TRANSACTION_KEY].last
end
current_test_transaction() click to toggle source
# File lib/sensei/client.rb, line 39
def self.current_test_transaction
  Thread.current[TEST_TRANSACTION_KEY].last
end
delete(uids) click to toggle source
# File lib/sensei/client.rb, line 125
def self.delete uids
  kafka_send(uids.map do |uid|
               {:type => 'delete', :uid => uid.to_s}
             end)
end
in_data_transaction?() click to toggle source
# File lib/sensei/client.rb, line 83
def self.in_data_transaction?
  self.in_sensei_transaction? DATA_TRANSACTION_KEY
end
in_sensei_transaction?(key) click to toggle source
# File lib/sensei/client.rb, line 48
def self.in_sensei_transaction? key
  Thread.current[key] ||= []
  Thread.current[key].count > 0
end
in_test_transaction?() click to toggle source
# File lib/sensei/client.rb, line 87
def self.in_test_transaction?
  self.in_sensei_transaction? TEST_TRANSACTION_KEY
end
kafka_commit(items) click to toggle source
# File lib/sensei/client.rb, line 116
def self.kafka_commit items
  if !fake_update
    req = Curl::Easy.new("http://#{http_kafka_hosts.sample}:#{http_kafka_port}/")
    req.http_post(items.map(&:to_json).join("\n"))
    raise Sensei::HTTPBadResponse, "Kafka url=#{req.url}, response_code=#{req.response_code}, response_body=#{req.body_str}" if req.response_code != 200
    req.body_str
  end
end
kafka_rollback(data_events) click to toggle source

Undo all of the data events that just occurred. This is only really useful during tests. Also, it’s only capable of rolling back insertions.

# File lib/sensei/client.rb, line 78
def self.kafka_rollback(data_events)
  to_delete = data_events.select{|x| x[uid_key]}.map{|x| {:_type => '_delete', :_uid => x[uid_key]}}
  kafka_commit to_delete
end
kafka_send(items) click to toggle source
# File lib/sensei/client.rb, line 103
def self.kafka_send items
  if in_data_transaction?
    current_data_transaction << items
  else
    kafka_commit items
  end

  if in_test_transaction?
    Thread.current[TEST_TRANSACTION_KEY].last << items
  end
  true
end
new(optargs={}) click to toggle source
# File lib/sensei/client.rb, line 96
def initialize optargs={}
  @query = optargs[:query].try(:to_sensei)
  @facets = (optargs[:facets] || {})
  @selections = (optargs[:selections] || {})
  @other_options = optargs.dup.keep_if {|k,v| ![:query, :facets, :selections].member?(k)}
end
q(h) click to toggle source
# File lib/sensei/client.rb, line 196
def self.q h
  h.to_sensei
end
sensei_url() click to toggle source
# File lib/sensei/client.rb, line 91
def self.sensei_url
  raise unless sensei_hosts
  "http://#{sensei_hosts.sample}:#{sensei_port || 8080}/sensei"
end
test_transaction(&block) click to toggle source
# File lib/sensei/client.rb, line 65
def self.test_transaction &block
  begin
    begin_transaction TEST_TRANSACTION_KEY
    block.call
  ensure
    kafka_rollback(current_test_transaction)
    Thread.current[TEST_TRANSACTION_KEY].pop
  end
end
transaction(&block) click to toggle source

This does a “data transaction,” in which any update events will get buffered until the block is finished, after which everything gets sent.

# File lib/sensei/client.rb, line 55
def self.transaction &block
  begin
    begin_transaction DATA_TRANSACTION_KEY
    block.call
    kafka_commit(current_data_transaction)
  ensure
    Thread.current[DATA_TRANSACTION_KEY].pop
  end
end
update(documents) click to toggle source
# File lib/sensei/client.rb, line 131
def self.update(documents)
  kafka_send documents
end

Public Instance Methods

all(q) click to toggle source
# File lib/sensei/client.rb, line 153
def all(q)
  @query ? (@query &= q.to_sensei) : (@query = q.to_sensei)
  self
end
any(q) click to toggle source
# File lib/sensei/client.rb, line 158
def any(q)
  @query ? (@query |= q.to_sensei) : (@query = q.to_sensei)
  self
end
facet(field, options={}) click to toggle source

Add a desired facet to the results

# File lib/sensei/client.rb, line 138
def facet(field, options={})
  @facets[field] = DEFAULT_FACET_OPTIONS.merge(options)
  self
end
facet_requests() click to toggle source

This method builds the requests necessary to perform the ‘select_search’ method.

# File lib/sensei/client.rb, line 234
def facet_requests
  @selections.map do |field, values|
    Sensei::Client.new(:query => @query,
                       :facets => @facets.dup.keep_if {|name, opts| name==field},
                       :selections => @selections.dup.keep_if {|name, opts| name != field},
                       :size => 0)
  end
end
not(q) click to toggle source
# File lib/sensei/client.rb, line 163
def not(q)
  @query ? (@query &= q.to_sensei.must_not) : (@query = q.to_sensei.must_not)
  self
end
options(opts = {}) click to toggle source
# File lib/sensei/client.rb, line 174
def options(opts = {})
  @other_options.merge!(opts)
  self
end
query(q) click to toggle source
# File lib/sensei/client.rb, line 148
def query(q)
  @query=q.to_sensei
  self
end
relevance(r) click to toggle source
# File lib/sensei/client.rb, line 143
def relevance(r)
  @relevance = r
  self
end
selection(fields = {}) click to toggle source

Do facet selection

# File lib/sensei/client.rb, line 169
def selection(fields = {})
  @selections.merge!(fields)
  self
end
to_h() click to toggle source
# File lib/sensei/client.rb, line 179
def to_h
  out = {}
  if @query
    out[:query] = @query.to_h
    if @relevance
      out[:query] = Sensei::BoolQuery.new(:operands => [@query], :operation => :must).to_h
      out[:query][:bool][:relevance] = @relevance
    end
  end

  (out[:facets] = @facets) if @facets.count > 0
  selections = @selections.map { |field, terms| {:terms => {field => {values: terms, :operator => "or"}}} }
  (out[:selections] = selections) if selections.count > 0
  out.merge!(@other_options)
  out
end