From 18532ef1cf18df47f24b1f7d0a7e6374f95a5809 Mon Sep 17 00:00:00 2001 From: Tobias Maier Date: Fri, 14 Jun 2013 23:24:58 +0200 Subject: [PATCH 1/3] Move more_like_this query to Tire::Search::MoreLikeThis::Query --- lib/tire/queries/more_like_this.rb | 2 +- .../queries/more_like_this/more_like_this.rb | 44 ++++++++++--------- 2 files changed, 24 insertions(+), 22 deletions(-) diff --git a/lib/tire/queries/more_like_this.rb b/lib/tire/queries/more_like_this.rb index 6203dca..62b3f5b 100644 --- a/lib/tire/queries/more_like_this.rb +++ b/lib/tire/queries/more_like_this.rb @@ -39,5 +39,5 @@ require 'tire/queries/more_like_this/more_like_this' Tire::Search::Query.class_eval do - include Tire::Search::MoreLikeThis + include Tire::Search::MoreLikeThis::Query end diff --git a/lib/tire/queries/more_like_this/more_like_this.rb b/lib/tire/queries/more_like_this/more_like_this.rb index f637eec..f5a9688 100644 --- a/lib/tire/queries/more_like_this/more_like_this.rb +++ b/lib/tire/queries/more_like_this/more_like_this.rb @@ -1,30 +1,32 @@ module Tire module Search module MoreLikeThis - def more_like_this(like_text, options = {}) - @value = {:mlt => {:like_text => like_text}} - @value[:mlt].update(validate_more_like_this_options(options)) - @value - end + module Query + def more_like_this(like_text, options = {}) + @value = {:mlt => {:like_text => like_text}} + @value[:mlt].update(validate_more_like_this_options(options)) + @value + end - def more_like_this_field(field, like_text, options = {}) - @value = {:mlt_field => {field => {:like_text => like_text}}} - # :fields is invalid in this context. Better than doing some kind of meta-black magic. - options.delete(:fields) - @value[:mlt_field][field].update(validate_more_like_this_options(options)) - @value - end + def more_like_this_field(field, like_text, options = {}) + @value = {:mlt_field => {field => {:like_text => like_text}}} + # :fields is invalid in this context. Better than doing some kind of meta-black magic. + options.delete(:fields) + @value[:mlt_field][field].update(validate_more_like_this_options(options)) + @value + end - alias_method :mlt, :more_like_this - alias_method :mlt_field, :more_like_this_field + alias_method :mlt, :more_like_this + alias_method :mlt_field, :more_like_this_field - private - def validate_more_like_this_options(options) - valid_options = [:fields, :percent_terms_to_match, :min_term_freq, - :max_query_terms, :stop_words, :min_doc_freq, :max_doc_freq, - :min_word_len, :max_word_len, :boost_terms, :boost, :analyzer] - options.delete_if { |key, value| !valid_options.member? key } + private + def validate_more_like_this_options(options) + valid_options = [:fields, :percent_terms_to_match, :min_term_freq, + :max_query_terms, :stop_words, :min_doc_freq, :max_doc_freq, + :min_word_len, :max_word_len, :boost_terms, :boost, :analyzer] + options.delete_if { |key, value| !valid_options.member? key } + end end end end -end \ No newline at end of file +end From 84eb39a305dbd6da4c700576aad3378d3d405677 Mon Sep 17 00:00:00 2001 From: Tobias Maier Date: Fri, 14 Jun 2013 23:26:56 +0200 Subject: [PATCH 2/3] Add Tire::Search::MoreLikeThis::Search * Inherits from Tire::Search::Search * #initialize is a copy of original method * Add document_id as attribute * Change path to /_mlt --- .../queries/more_like_this/more_like_this.rb | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/lib/tire/queries/more_like_this/more_like_this.rb b/lib/tire/queries/more_like_this/more_like_this.rb index f5a9688..de41d3f 100644 --- a/lib/tire/queries/more_like_this/more_like_this.rb +++ b/lib/tire/queries/more_like_this/more_like_this.rb @@ -27,6 +27,27 @@ def validate_more_like_this_options(options) options.delete_if { |key, value| !valid_options.member? key } end end + + class Search < Tire::Search::Search + + attr_reader :document_id + + def initialize(indices=nil, document_id=nil, options={}, &block) + if indices.is_a?(Hash) + set_indices_options(indices) + @indices = indices.keys + else + @indices = Array(indices) + end + @types = Array(options.delete(:type)).map { |type| Utils.escape(type) } + @options = options + @document_id = document_id + + @path = ['/', @indices.join(','), @types.join(','), @document_id, '_mlt'].compact.join('/').squeeze('/') + + block.arity < 1 ? instance_eval(&block) : block.call(self) if block_given? + end + end end end end From 9de3971d771dfed6945e99727422efb8d7d0d6d0 Mon Sep 17 00:00:00 2001 From: Tobias Maier Date: Fri, 14 Jun 2013 23:28:55 +0200 Subject: [PATCH 3/3] Add more_like_this to Tire::Model::Search::InstanceMethods * Copy of Tire::Model::Search::ClassMethods.search * Handles mlt_fields * Searches with Tire::Search::MoreLikeThis::Search --- lib/tire/queries/more_like_this.rb | 81 ++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/lib/tire/queries/more_like_this.rb b/lib/tire/queries/more_like_this.rb index 62b3f5b..abbe239 100644 --- a/lib/tire/queries/more_like_this.rb +++ b/lib/tire/queries/more_like_this.rb @@ -41,3 +41,84 @@ Tire::Search::Query.class_eval do include Tire::Search::MoreLikeThis::Query end + +module Tire::Model::Search::InstanceMethods + # Returns search results for a given query. + # + # Query can be passed simply as a String: + # + # @article.more_like_this 'love' + # + # Any options, such as pagination or sorting, can be passed as a second argument: + # + # @article.more_like_this 'love', :per_page => 25, :page => 2 + # @article.more_like_this 'love', :sort => 'title' + # + # For more powerful query definition, use the query DSL passed as a block: + # + # @article.more_like_this do + # query { terms :tags, ['ruby', 'python'] } + # facet 'tags' { terms :tags } + # end + # + # You can pass options as the first argument, in this case: + # + # @article.more_like_this :per_page => 25, :page => 2 do + # query { string 'love' } + # end + # + # This methods returns a Tire::Results::Collection instance, containing instances + # of Tire::Results::Item, populated by the data available in _Elasticsearch, by default. + # + # If you'd like to load the "real" models from the database, you may use the `:load` option: + # + # @article.more_like_this 'love', :load => true + # + # You can pass options as a Hash to the model's `find` method: + # + # @article.more_like_this :load => { :include => 'comments' } do ... end + # + def more_like_this(*args, &block) + default_options = {:type => instance.class.tire.document_type, :index => instance.class.tire.index.name} + + if block_given? + options = args.shift || {} + else + query, options = args + options ||= {} + end + + options[:mlt_fields] = options[:mlt_fields].join(',') if options[:mlt_fields] + options = default_options.update(options) + sort = Array( options.delete(:order) || options.delete(:sort) ) + + s = Tire::Search::MoreLikeThis::Search.new(options.delete(:index), instance.id, options) + + page = options.delete(:page) + per_page = options.delete(:per_page) || Tire::Results::Pagination::default_per_page + + s.size( per_page.to_i ) if per_page + s.from( page.to_i <= 1 ? 0 : (per_page.to_i * (page.to_i-1)) ) if page && per_page + + s.sort do + sort.each do |t| + field_name, direction = t.split(':') + by field_name, direction + end + end unless sort.empty? + + version = options.delete(:version) + s.version(version) if version + + if block_given? + block.arity < 1 ? s.instance_eval(&block) : block.call(s) + else + s.query { string query } + # TODO: Actualy, allow passing all the valid options from + # + s.fields Array(options[:fields]) if options[:fields] + end + + s.results + end +end