-
-
Save gudata/5591598 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# An example of elasticsearch & Tire setup for ActiveRecord associations. | |
# | |
# A `Book has_many :chapters` scenario, with mapping and JSON serialization | |
# for indexing associated models. | |
# | |
# Demonstrates three important caveats as of now: | |
# | |
# 1. You you have to use `touch: true` in the `belongs_to` declaration, | |
# to automatically notify the parent model about the update. | |
# | |
# 2. You have to explicitely hook up updating elasticsearch index via | |
# the `after_touch` callback in the parent model. | |
# | |
# 3. You have to disable `include_root_in_json` for proper JSON serialization. | |
# | |
# | |
# Run me with: | |
# | |
# $ ruby active_record_associations.rb | |
# | |
require 'logger' | |
require 'ansi/core' | |
require 'active_record' | |
require 'oj' | |
require 'tire' | |
def _(message=nil); puts '-'*80, ANSI.bold(message.to_s), '-'*80; end | |
ActiveRecord::Base.logger = Logger.new(STDERR) | |
ActiveRecord::Base.establish_connection( adapter: 'sqlite3', database: ":memory:" ) | |
Tire.configure { logger STDERR } | |
_ "Creating ActiveRecord schema..." | |
ActiveRecord::Schema.define(version: 1) do | |
create_table :books do |t| | |
t.string :title | |
t.timestamps | |
end | |
create_table :chapters do |t| | |
t.string :text | |
t.integer :number, :book_id | |
t.timestamps | |
end | |
add_index(:chapters, :book_id) | |
end | |
_ "Deleting elasticsearch index..." | |
Tire.index('books').delete | |
# The Book class | |
# | |
class Book < ActiveRecord::Base | |
has_many :chapters | |
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | |
# Enable automatic saving in elasticsearch when associated objects change | |
# | |
after_touch() { tire.update_index } | |
# | |
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | |
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | |
# Properly serialize JSON for elasticsearch | |
# | |
self.include_root_in_json = false | |
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | |
include Tire::Model::Search | |
include Tire::Model::Callbacks | |
# Define the mapping | |
# | |
mapping do | |
indexes :title, type: 'string', boost: 10, analyzer: 'snowball' | |
indexes :created_at, type: 'date' | |
indexes :chapters do | |
indexes :text, analyzer: 'snowball' | |
end | |
end | |
# Define the JSON serialization | |
# | |
def to_indexed_json | |
to_json( include: { chapters: { only: [:text] } } ) | |
end | |
end | |
# The book Chapter class | |
# | |
class Chapter < ActiveRecord::Base | |
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | |
# Do not forget to automatically `touch` parent object from associations | |
belongs_to :book, touch: true | |
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | |
end | |
_ "Create book instance..." | |
book = Book.create title: "How to impress your Rails friends with elasticsearch" | |
book.chapters.create number: 1, text: "The world generates more and more information ..." | |
book.chapters.create number: 2, text: "After the elasticsearch installation ..." | |
p Book.first | |
p Book.first.chapters | |
_ "Refresh the index for immediate search (there's a 1 second delay by default)..." | |
Book.tire.index.refresh | |
_ "Search 'elasticsearch' in book titles..." | |
results = Book.search('title:elasticsearch') | |
puts ANSI.green( "Found: '%s'" % results.first.title ) | |
_ "Search 'install' in chapter text..." | |
results = Book.search('chapters.text:install') | |
puts ANSI.green( "Found: '%s'" % results.first.title ) | |
_ "Search 'elasticsearch' anywhere with highlighting..." | |
results = Book.search do | |
query { string "elasticsearch" } | |
highlight 'title', 'chapters.text' | |
end | |
puts ANSI.green( "Found: '%s'" % results.first.title ), | |
'-'*80, | |
"Highlights: ", | |
results.first.highlight.to_hash \ | |
.map { |k,v| ' - ' + k.to_s + ": " + v.first.to_s } \ | |
.map { |s| s.gsub(/<em>([^<]+)<\/em>/, ANSI.yellow + ANSI.bold + '\1' + ANSI.reset) } \ | |
.join("\n") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment