elasticsearch-rails2 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +17 -0
- data/.travis.yml +3 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +201 -0
- data/Rakefile +11 -0
- data/elasticsearch-rails2.gemspec +31 -0
- data/lib/elasticsearch/rails2.rb +63 -0
- data/lib/elasticsearch/rails2/client.rb +58 -0
- data/lib/elasticsearch/rails2/configuration.rb +39 -0
- data/lib/elasticsearch/rails2/naming.rb +125 -0
- data/lib/elasticsearch/rails2/response.rb +77 -0
- data/lib/elasticsearch/rails2/response/result.rb +62 -0
- data/lib/elasticsearch/rails2/response/results.rb +52 -0
- data/lib/elasticsearch/rails2/searching.rb +120 -0
- data/lib/elasticsearch/rails2/version.rb +5 -0
- data/spec/client_spec.rb +38 -0
- data/spec/naming_spec.rb +88 -0
- data/spec/rails2_spec.rb +53 -0
- data/spec/response/result_spec.rb +89 -0
- data/spec/response/results_spec.rb +33 -0
- data/spec/response_spec.rb +13 -0
- data/spec/searching_search_request_spec.rb +62 -0
- data/spec/searching_spec.rb +36 -0
- data/spec/spec_helper.rb +27 -0
- data/spec/support/active_record.rb +3 -0
- data/tasks/rspec.rake +3 -0
- metadata +198 -0
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Edgar Gonzalez
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,201 @@
|
|
1
|
+
# Elasticsearch::Rails2 [](https://travis-ci.org/edgar/elasticsearch-rails2)
|
2
|
+
|
3
|
+
The `elasticsearch-rails2` library is based on the
|
4
|
+
[`elasticsearch-model`](https://github.com/elasticsearch/elasticsearch-model) and builds on top of the
|
5
|
+
the [`elasticsearch`](https://github.com/elasticsearch/elasticsearch-ruby) library.
|
6
|
+
|
7
|
+
It aims to simplify integration of [Ruby on Rails](http://rubyonrails.org) 2.3 models (`ActiveRecord`)
|
8
|
+
with the [Elasticsearch](http://www.elasticsearch.org) search.
|
9
|
+
|
10
|
+
(If your app is in Ruby on Rails 2.3 you can't use [`elasticsearch-model`](https://github.com/elasticsearch/elasticsearch-model) because it requires Ruby on Rails >= 3.0)
|
11
|
+
|
12
|
+
The library is compatible with Ruby 1.9.3.
|
13
|
+
|
14
|
+
## Installation
|
15
|
+
|
16
|
+
Add this line to your application's Gemfile:
|
17
|
+
|
18
|
+
gem 'elasticsearch-rails2'
|
19
|
+
|
20
|
+
And then execute:
|
21
|
+
|
22
|
+
$ bundle
|
23
|
+
|
24
|
+
Or install it yourself as:
|
25
|
+
|
26
|
+
$ gem install elasticsearch-rails2
|
27
|
+
|
28
|
+
## Usage
|
29
|
+
|
30
|
+
Let's suppose you have an `Article` model:
|
31
|
+
|
32
|
+
```ruby
|
33
|
+
require 'elasticsearch/rails2'
|
34
|
+
|
35
|
+
class Article < ActiveRecord::Base
|
36
|
+
include Elasticsearch::Rails2
|
37
|
+
end
|
38
|
+
```
|
39
|
+
|
40
|
+
This will extend the model with functionality related to Elasticsearch:
|
41
|
+
|
42
|
+
### Elasticsearch client
|
43
|
+
|
44
|
+
The module will set up a [client](https://github.com/elasticsearch/elasticsearch-ruby/tree/master/elasticsearch),
|
45
|
+
connected to `localhost:9200`, by default. You can access and use it as any other `Elasticsearch::Client`:
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
Article.client.cluster.health
|
49
|
+
# => { "cluster_name"=>"elasticsearch", "status"=>"yellow", ... }
|
50
|
+
```
|
51
|
+
|
52
|
+
To use a client with different configuration, just set up a client for the model:
|
53
|
+
|
54
|
+
```ruby
|
55
|
+
Article.client = Elasticsearch::Client.new host: 'api.server.org'
|
56
|
+
```
|
57
|
+
|
58
|
+
Or configure the client for all models:
|
59
|
+
|
60
|
+
```ruby
|
61
|
+
Elasticsearch::Rails2.client = Elasticsearch::Client.new log: true
|
62
|
+
```
|
63
|
+
|
64
|
+
You might want to do this during you application bootstrap process, e.g. in a Rails initializer.
|
65
|
+
|
66
|
+
Please refer to the
|
67
|
+
[`elasticsearch-transport`](https://github.com/elasticsearch/elasticsearch-ruby/tree/master/elasticsearch-transport)
|
68
|
+
library documentation for all the configuration options, and to the
|
69
|
+
[`elasticsearch-api`](http://rubydoc.info/gems/elasticsearch-api) library documentation
|
70
|
+
for information about the Ruby client API.
|
71
|
+
|
72
|
+
### Searching
|
73
|
+
|
74
|
+
For starters, we can try the "simple" type of search:
|
75
|
+
|
76
|
+
```ruby
|
77
|
+
response = Article.search 'fox dogs'
|
78
|
+
|
79
|
+
response.took
|
80
|
+
# => 3
|
81
|
+
|
82
|
+
response.results.total
|
83
|
+
# => 2
|
84
|
+
|
85
|
+
response.results.first._score
|
86
|
+
# => 0.02250402
|
87
|
+
|
88
|
+
response.results.first._source.title
|
89
|
+
# => "Quick brown fox"
|
90
|
+
```
|
91
|
+
|
92
|
+
#### Search results
|
93
|
+
|
94
|
+
The returned `response` object is a rich wrapper around the JSON returned from Elasticsearch,
|
95
|
+
providing access to response metadata and the actual results ("hits").
|
96
|
+
|
97
|
+
Each "hit" is wrapped in the `Result` class, and provides method access
|
98
|
+
to its properties via [`Hashie::Mash`](http://github.com/intridea/hashie).
|
99
|
+
|
100
|
+
The `results` object supports the `Enumerable` interface:
|
101
|
+
|
102
|
+
```ruby
|
103
|
+
response.results.map { |r| r._source.title }
|
104
|
+
# => ["Quick brown fox", "Fast black dogs"]
|
105
|
+
|
106
|
+
response.results.select { |r| r.title =~ /^Q/ }
|
107
|
+
# => [#<Elasticsearch::Model::Response::Result:0x007 ... "_source"=>{"title"=>"Quick brown fox"}}>]
|
108
|
+
```
|
109
|
+
|
110
|
+
In fact, the `response` object will delegate `Enumerable` methods to `results`:
|
111
|
+
|
112
|
+
```ruby
|
113
|
+
response.any? { |r| r.title =~ /fox|dog/ }
|
114
|
+
# => true
|
115
|
+
```
|
116
|
+
|
117
|
+
To use `Array`'s methods (including any _ActiveSupport_ extensions), just call `to_a` on the object:
|
118
|
+
|
119
|
+
```ruby
|
120
|
+
response.to_a.last.title
|
121
|
+
# "Fast black dogs"
|
122
|
+
```
|
123
|
+
|
124
|
+
#### Search results as database records
|
125
|
+
|
126
|
+
Instead of returning documents from Elasticsearch, the `records` method will return a collection
|
127
|
+
of model instances, fetched from the primary database, ordered by score:
|
128
|
+
|
129
|
+
```ruby
|
130
|
+
response.records.to_a
|
131
|
+
# Article Load (0.3ms) SELECT "articles".* FROM "articles" WHERE "articles"."id" IN (1, 2)
|
132
|
+
# => [#<Article id: 1, title: "Quick brown fox">, #<Article id: 2, title: "Fast black dogs">]
|
133
|
+
```
|
134
|
+
|
135
|
+
The returned object is the genuine collection of model instances returned by your database,
|
136
|
+
|
137
|
+
The `records` method returns the real instances of your model, which is useful when you want to access your
|
138
|
+
model methods -- at the expense of slowing down your application, of course.
|
139
|
+
In most cases, working with `results` coming from Elasticsearch is sufficient, and much faster. See the
|
140
|
+
[`elasticsearch-rails`](https://github.com/elasticsearch/elasticsearch-rails/tree/master/elasticsearch-rails)
|
141
|
+
library for more information about compatibility with the Ruby on Rails framework.
|
142
|
+
|
143
|
+
#### The Elasticsearch DSL
|
144
|
+
|
145
|
+
In most situation, you'll want to pass the search definition
|
146
|
+
in the Elasticsearch [domain-specific language](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl.html) to the client:
|
147
|
+
|
148
|
+
```ruby
|
149
|
+
response = Article.search query: { match: { title: "Fox Dogs" } },
|
150
|
+
highlight: { fields: { title: {} } }
|
151
|
+
|
152
|
+
response.results.first.highlight.title
|
153
|
+
# ["Quick brown <em>fox</em>"]
|
154
|
+
```
|
155
|
+
|
156
|
+
You can pass any object which implements a `to_hash` method, or you can use your favourite JSON builder
|
157
|
+
to build the search definition as a JSON string:
|
158
|
+
|
159
|
+
```ruby
|
160
|
+
require 'jbuilder'
|
161
|
+
|
162
|
+
query = Jbuilder.encode do |json|
|
163
|
+
json.query do
|
164
|
+
json.match do
|
165
|
+
json.title do
|
166
|
+
json.query "fox dogs"
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
response = Article.search query
|
173
|
+
response.results.first.title
|
174
|
+
# => "Quick brown fox"
|
175
|
+
```
|
176
|
+
|
177
|
+
### Index Configuration
|
178
|
+
|
179
|
+
By default, index name and document type will be inferred from your class name,
|
180
|
+
you can set it explicitely, however:
|
181
|
+
|
182
|
+
```ruby
|
183
|
+
class Article
|
184
|
+
index_name "articles-#{Rails.env}"
|
185
|
+
document_type "post"
|
186
|
+
end
|
187
|
+
```
|
188
|
+
|
189
|
+
For `index_name` there is a global setting in case you want to use the same index for all models:
|
190
|
+
|
191
|
+
```ruby
|
192
|
+
Elasticsearch::Rails2.index_name = 'production'
|
193
|
+
```
|
194
|
+
|
195
|
+
## Contributing
|
196
|
+
|
197
|
+
1. Fork it
|
198
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
199
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
200
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
201
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
|
3
|
+
Dir.glob('tasks/**/*.rake').each(&method(:import))
|
4
|
+
|
5
|
+
task :default => :spec
|
6
|
+
task :test => :spec
|
7
|
+
|
8
|
+
desc "Open an irb session preloaded with this library"
|
9
|
+
task :console do
|
10
|
+
sh "irb -rubygems -I lib -r elasticsearch/rails2.rb"
|
11
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'elasticsearch/rails2/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "elasticsearch-rails2"
|
8
|
+
spec.version = Elasticsearch::Rails2::VERSION
|
9
|
+
spec.authors = ["Edgar Gonzalez"]
|
10
|
+
spec.email = ["edgargonzalez@gmail.com"]
|
11
|
+
spec.description = "Rails 2.3 ActiveRecord integrations for Elasticsearch"
|
12
|
+
spec.summary = "Rails 2.3 ActiveRecord integrations for Elasticsearch"
|
13
|
+
spec.homepage = "https://github.com/edgar/elasticsearch-rails2"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.required_ruby_version = "1.9.3"
|
22
|
+
|
23
|
+
spec.add_dependency "elasticsearch", '>= 1.0.5'
|
24
|
+
spec.add_dependency "activerecord", '2.3.18'
|
25
|
+
spec.add_dependency "hashie"
|
26
|
+
|
27
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
28
|
+
spec.add_development_dependency "rake"
|
29
|
+
spec.add_development_dependency 'rspec', "~> 3.1.0"
|
30
|
+
spec.add_development_dependency 'sqlite3'
|
31
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'elasticsearch'
|
2
|
+
|
3
|
+
require 'hashie'
|
4
|
+
require 'active_record'
|
5
|
+
|
6
|
+
require "elasticsearch/rails2/version"
|
7
|
+
require "elasticsearch/rails2/configuration"
|
8
|
+
require "elasticsearch/rails2/client"
|
9
|
+
require "elasticsearch/rails2/naming"
|
10
|
+
require "elasticsearch/rails2/searching"
|
11
|
+
require "elasticsearch/rails2/response"
|
12
|
+
require "elasticsearch/rails2/response/result"
|
13
|
+
require "elasticsearch/rails2/response/results"
|
14
|
+
|
15
|
+
module Elasticsearch
|
16
|
+
module Rails2
|
17
|
+
|
18
|
+
def self.included(base)
|
19
|
+
base.send :include, Elasticsearch::Rails2::Client::InstanceMethods
|
20
|
+
base.extend Elasticsearch::Rails2::Client::ClassMethods
|
21
|
+
|
22
|
+
base.send :include, Elasticsearch::Rails2::Naming::InstanceMethods
|
23
|
+
base.extend Elasticsearch::Rails2::Naming::ClassMethods
|
24
|
+
|
25
|
+
base.extend Elasticsearch::Rails2::Searching::ClassMethods
|
26
|
+
end
|
27
|
+
|
28
|
+
module ClassMethods
|
29
|
+
# Get the client common for all models
|
30
|
+
#
|
31
|
+
# @example Get the client
|
32
|
+
#
|
33
|
+
# Elasticsearch::Model.client
|
34
|
+
# => #<Elasticsearch::Transport::Client:0x007f96a7d0d000 @transport=... >
|
35
|
+
#
|
36
|
+
def client
|
37
|
+
@client ||= Elasticsearch::Client.new
|
38
|
+
end
|
39
|
+
|
40
|
+
# Set the client for all models
|
41
|
+
#
|
42
|
+
# @example Configure (set) the client for all models
|
43
|
+
#
|
44
|
+
# Elasticsearch::Model.client Elasticsearch::Client.new host: 'http://localhost:9200', tracer: true
|
45
|
+
# => #<Elasticsearch::Transport::Client:0x007f96a6dd0d80 @transport=... >
|
46
|
+
#
|
47
|
+
# @note You have to set the client before you call Elasticsearch methods on the model,
|
48
|
+
# or set it directly on the model; see {Elasticsearch::Model::Client::ClassMethods#client}
|
49
|
+
#
|
50
|
+
def client=(client)
|
51
|
+
@client = client
|
52
|
+
end
|
53
|
+
|
54
|
+
def options=(options={})
|
55
|
+
Configuration::VALID_OPTIONS_KEYS.each do |key|
|
56
|
+
send("#{key}=", options[key])
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
extend ClassMethods
|
61
|
+
extend Configuration
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Elasticsearch
|
2
|
+
module Rails2
|
3
|
+
module Client
|
4
|
+
# Contains an `Elasticsearch::Client` instance
|
5
|
+
#
|
6
|
+
module ClassMethods
|
7
|
+
|
8
|
+
# Get the client for a specific model class
|
9
|
+
#
|
10
|
+
# @example Get the client for `Building` and perform API request
|
11
|
+
#
|
12
|
+
# Building.client.cluster.health
|
13
|
+
# # => { "cluster_name" => "elasticsearch" ... }
|
14
|
+
#
|
15
|
+
def client
|
16
|
+
@client ||= Elasticsearch::Rails2.client
|
17
|
+
end
|
18
|
+
|
19
|
+
# Set the client for a specific model class
|
20
|
+
#
|
21
|
+
# @example Configure the client for the `Building` model
|
22
|
+
#
|
23
|
+
# Building.client = Elasticsearch::Client.new host: 'http://api.server:8080'
|
24
|
+
# Building.search ...
|
25
|
+
#
|
26
|
+
def client=(client)
|
27
|
+
@client = client
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
module InstanceMethods
|
32
|
+
|
33
|
+
# Get or set the client for a specific model instance
|
34
|
+
#
|
35
|
+
# @example Get the client for a specific record and perform API request
|
36
|
+
#
|
37
|
+
# @building = Building.first
|
38
|
+
# @building.client.info
|
39
|
+
# # => { "name" => "Node-1", ... }
|
40
|
+
#
|
41
|
+
def client
|
42
|
+
@client ||= self.class.client
|
43
|
+
end
|
44
|
+
|
45
|
+
# Set the client for a specific model instance
|
46
|
+
#
|
47
|
+
# @example Set the client for a specific record
|
48
|
+
#
|
49
|
+
# @building = Building.first
|
50
|
+
# @building.client = Elasticsearch::Client.new host: 'http://api.server:8080'
|
51
|
+
#
|
52
|
+
def client=(client)
|
53
|
+
@client = client
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Elasticsearch
|
2
|
+
module Rails2
|
3
|
+
# Defines constants and methods related to configuration
|
4
|
+
module Configuration
|
5
|
+
# An array of valid keys in the options hash when configuring Elasticsearch::Rails2
|
6
|
+
VALID_OPTIONS_KEYS = [
|
7
|
+
:index_name
|
8
|
+
].freeze
|
9
|
+
|
10
|
+
# By default, don't set an index_name
|
11
|
+
DEFAULT_INDEX_NAME = nil
|
12
|
+
|
13
|
+
# @private
|
14
|
+
attr_accessor *VALID_OPTIONS_KEYS
|
15
|
+
|
16
|
+
# When this module is extended, set all configuration options to their default values
|
17
|
+
def self.extended(base)
|
18
|
+
base.reset
|
19
|
+
end
|
20
|
+
|
21
|
+
# Convenience method to allow configuration options to be set in a block
|
22
|
+
def configure
|
23
|
+
yield self
|
24
|
+
end
|
25
|
+
|
26
|
+
# Create a hash of options and their values
|
27
|
+
def options
|
28
|
+
VALID_OPTIONS_KEYS.inject({}) do |option, key|
|
29
|
+
option.merge!(key => send(key))
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Reset all configuration options to defaults
|
34
|
+
def reset
|
35
|
+
self.index_name = DEFAULT_INDEX_NAME
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|