Commit d146b9c39ec9bd42493af8e5bbc2bac0ee6b1dec
0 parents
Exists in
master
and in
21 other branches
First commit
Showing
9 changed files
with
185 additions
and
0 deletions
Show diff stats
1 | +++ a/LICENSE.txt | ||
@@ -0,0 +1,22 @@ | @@ -0,0 +1,22 @@ | ||
1 | +Copyright (c) 2013 Andrew Kane | ||
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. |
1 | +++ a/README.md | ||
@@ -0,0 +1,55 @@ | @@ -0,0 +1,55 @@ | ||
1 | +# Searchkick | ||
2 | + | ||
3 | +Search made easy | ||
4 | + | ||
5 | +## Usage | ||
6 | + | ||
7 | +### Reindex with Zero Downtime | ||
8 | + | ||
9 | +Elasticsearch has a feature called aliases that allows you to reindex with no downtime. | ||
10 | + | ||
11 | +```ruby | ||
12 | +Book.tire.reindex | ||
13 | +``` | ||
14 | + | ||
15 | +This creates a new index `books_20130714181054` and points the `books` alias to the new index when complete - an atomic operation :) | ||
16 | + | ||
17 | +**First time:** If books is an existing index, it will be replaced by an alias. | ||
18 | + | ||
19 | +Searchkick uses `find_in_batches` to import documents. To filter documents or eagar load associations, use the `tire_import` scope. | ||
20 | + | ||
21 | +```ruby | ||
22 | +class Book < ActiveRecord::Base | ||
23 | + scope :tire_import, where(active: true).includes(:author, :chapters) | ||
24 | +end | ||
25 | +``` | ||
26 | + | ||
27 | +There is also a rake task. | ||
28 | + | ||
29 | +```sh | ||
30 | +rake searchkick:reindex CLASS=Book | ||
31 | +``` | ||
32 | + | ||
33 | +[Thanks to Jaroslav Kalistsuk for the original source](https://gist.github.com/jarosan/3124884) | ||
34 | + | ||
35 | +## Installation | ||
36 | + | ||
37 | +Add this line to your application's Gemfile: | ||
38 | + | ||
39 | +```ruby | ||
40 | +gem "searchkick" | ||
41 | +``` | ||
42 | + | ||
43 | +And then execute: | ||
44 | + | ||
45 | +```sh | ||
46 | +bundle | ||
47 | +``` | ||
48 | + | ||
49 | +## Contributing | ||
50 | + | ||
51 | +1. Fork it | ||
52 | +2. Create your feature branch (`git checkout -b my-new-feature`) | ||
53 | +3. Commit your changes (`git commit -am 'Add some feature'`) | ||
54 | +4. Push to the branch (`git push origin my-new-feature`) | ||
55 | +5. Create new Pull Request |
1 | +++ a/lib/searchkick.rb | ||
@@ -0,0 +1,49 @@ | @@ -0,0 +1,49 @@ | ||
1 | +require "searchkick/version" | ||
2 | +require "searchkick/tasks" | ||
3 | +require "tire" | ||
4 | + | ||
5 | +module Searchkick | ||
6 | + module ClassMethods | ||
7 | + | ||
8 | + # https://gist.github.com/jarosan/3124884 | ||
9 | + def reindex | ||
10 | + alias_name = klass.tire.index.name | ||
11 | + new_index = alias_name + "_" + Time.now.strftime("%Y%m%d%H%M%S") | ||
12 | + | ||
13 | + # Rake::Task["tire:import"].invoke | ||
14 | + index = Tire::Index.new(new_index) | ||
15 | + Tire::Tasks::Import.create_index(index, klass) | ||
16 | + scope = klass.respond_to?(:tire_import) ? klass.tire_import : klass | ||
17 | + scope.find_in_batches do |batch| | ||
18 | + index.import batch | ||
19 | + end | ||
20 | + | ||
21 | + if a = Tire::Alias.find(alias_name) | ||
22 | + puts "[IMPORT] Alias found: #{Tire::Alias.find(alias_name).indices.to_ary.join(",")}" | ||
23 | + old_indices = Tire::Alias.find(alias_name).indices | ||
24 | + old_indices.each do |index| | ||
25 | + a.indices.delete index | ||
26 | + end | ||
27 | + | ||
28 | + a.indices.add new_index | ||
29 | + a.save | ||
30 | + | ||
31 | + old_indices.each do |index| | ||
32 | + puts "[IMPORT] Deleting index: #{index}" | ||
33 | + i = Tire::Index.new(index) | ||
34 | + i.delete if i.exists? | ||
35 | + end | ||
36 | + else | ||
37 | + puts "[IMPORT] No alias found. Deleting index, creating new one, and setting up alias" | ||
38 | + i = Tire::Index.new(alias_name) | ||
39 | + i.delete if i.exists? | ||
40 | + Tire::Alias.create(name: alias_name, indices: [new_index]) | ||
41 | + end | ||
42 | + | ||
43 | + puts "[IMPORT] Saved alias #{alias_name} pointing to #{new_index}" | ||
44 | + end | ||
45 | + | ||
46 | + end | ||
47 | +end | ||
48 | + | ||
49 | +Tire::Model::Search::ClassMethodsProxy.send :include, Searchkick::ClassMethods |
1 | +++ a/searchkick.gemspec | ||
@@ -0,0 +1,25 @@ | @@ -0,0 +1,25 @@ | ||
1 | +# coding: utf-8 | ||
2 | +lib = File.expand_path('../lib', __FILE__) | ||
3 | +$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) | ||
4 | +require 'searchkick/version' | ||
5 | + | ||
6 | +Gem::Specification.new do |spec| | ||
7 | + spec.name = "searchkick" | ||
8 | + spec.version = Searchkick::VERSION | ||
9 | + spec.authors = ["Andrew Kane"] | ||
10 | + spec.email = ["andrew@chartkick.com"] | ||
11 | + spec.description = %q{Search made easy} | ||
12 | + spec.summary = %q{Search made easy} | ||
13 | + spec.homepage = "https://github.com/ankane/searchkick" | ||
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.add_dependency "tire" | ||
22 | + | ||
23 | + spec.add_development_dependency "bundler", "~> 1.3" | ||
24 | + spec.add_development_dependency "rake" | ||
25 | +end |