From 570db153d7fc9e3d386fbd922f0fe449872726d7 Mon Sep 17 00:00:00 2001 From: Florian Eck Date: Tue, 29 Sep 2020 18:27:10 +0200 Subject: [PATCH 01/21] change version --- lib/smart_search.rb | 5 ++++- smart_search.gemspec | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/smart_search.rb b/lib/smart_search.rb index 15f3574..df0f19c 100755 --- a/lib/smart_search.rb +++ b/lib/smart_search.rb @@ -35,7 +35,7 @@ def smart_search(options = {:on => [], :split => false}) attr_accessor :query_score, :dont_update_search_tags self.tags = options[:on] || [] - elsif is_smart_search? && Rails.env.production? + elsif is_smart_search? # Allow re-adding attributes for search logger.info("Re-Adding search data on #{self.name}: #{options[:on].inspect}".yellow) self.tags += options[:on] @@ -80,6 +80,9 @@ def find_by_tags(tags = "", options = {}) end results = self.where(self.primary_key => result_ids) + + results = result.offset(options[:offset]) if options[:offset] + results = result.limit(options[:limit]) if options[:per_page] end def find_by_splitted_tags(search_fields = {}) diff --git a/smart_search.gemspec b/smart_search.gemspec index 84f6278..70d4e7e 100755 --- a/smart_search.gemspec +++ b/smart_search.gemspec @@ -1,6 +1,6 @@ Gem::Specification.new do |s| s.name = 'smart_search' - s.version = '1.0.2' + s.version = '1.1' s.summary = "Simple, easy to use search MySQL based search for ActiveRecord" s.description = "SmartSearch adds full-text search functions to ActiveRecord running with MySQL, including search for similiar words. Its fast, simple, and works with almost zero-config!" s.authors = ["Florian Eck"] From 906edd9dbf9a58d983433701e871c2e491525d87 Mon Sep 17 00:00:00 2001 From: Florian Eck Date: Tue, 29 Sep 2020 18:54:17 +0200 Subject: [PATCH 02/21] rake task --- lib/smart_search.rb | 27 +++++++++++++++++++++++++++ lib/tasks/smart_search.rake | 5 +++++ 2 files changed, 32 insertions(+) diff --git a/lib/smart_search.rb b/lib/smart_search.rb index df0f19c..2b7b123 100755 --- a/lib/smart_search.rb +++ b/lib/smart_search.rb @@ -18,6 +18,9 @@ module ClassMethods # Enable SmartSearch for the current ActiveRecord model. def smart_search(options = {:on => [], :split => false}) if table_exists? + if SmartSearch::Config.search_models.index(self.name).nil? + SmartSearch::Config.search_models << self.name + end # Check if search_tags exists if !is_smart_search? @@ -282,6 +285,30 @@ def self.get_search_models def self.get_public_models self.public_models.map {|m| m.constantize} end + + def self.rebuild_index + puts "Rebuilding Search index..." + + SmartSearch::Config.search_models.each do |name| + puts "... #{name}" + end + + ActiveRecord::Base.logger = nil + + model_bar = ProgressBar.create(:title => "Building models", :total => SmartSearch::Config.search_models.size, format: "%t: (%c/%C) |%W| %f") + + SmartSearch::Config.get_search_models.each do |model| + puts model.tags.join("\n") + entry_bar = ProgressBar.create(:title => model.name, :total => model.all.size, format: "%t: (%c/%C) |%W| %f") + model.all.each do |entry| + entry.create_search_tags + entry_bar.increment + end + + model_bar.increment + puts "\n\n" + end + end end diff --git a/lib/tasks/smart_search.rake b/lib/tasks/smart_search.rake index d3b6c78..624c8ef 100755 --- a/lib/tasks/smart_search.rake +++ b/lib/tasks/smart_search.rake @@ -4,6 +4,11 @@ namespace :smart_search do require File.expand_path("../../smart_similarity", __FILE__) SmartSimilarity.load_from_query_history end + + desc "Rebuild search index for all avialble models" + task :rebuild_index => :environment do + SmartSearch::Config.rebuild_index + end end From 5d74017fb9b2cbdac0fd63b0c982e2f9ac54653f Mon Sep 17 00:00:00 2001 From: Florian Eck Date: Thu, 1 Oct 2020 16:43:56 +0200 Subject: [PATCH 03/21] fix results return nil ... --- lib/smart_search.rb | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/smart_search.rb b/lib/smart_search.rb index 2b7b123..13e3de4 100755 --- a/lib/smart_search.rb +++ b/lib/smart_search.rb @@ -61,7 +61,7 @@ def find_by_tags(tags = "", options = {}) result_ids = [] result_scores = {} - results = SmartSearchTag.select("entry_id, sum(boost) as score").group(:entry_id).where(table_name: self.table_name) + #results = SmartSearchTag.select("entry_id, sum(boost) as score").group(:entry_id).where(table_name: self.table_name) query = case ActiveRecord::Base.connection.adapter_name when 'PostgreSQL' @@ -84,8 +84,10 @@ def find_by_tags(tags = "", options = {}) results = self.where(self.primary_key => result_ids) - results = result.offset(options[:offset]) if options[:offset] - results = result.limit(options[:limit]) if options[:per_page] + results = results.offset(options[:offset]) if options[:offset] + results = results.limit(options[:limit]) if options[:per_page] + + return results end def find_by_splitted_tags(search_fields = {}) From b40d3d605f74598949caefc30cb017193d36b88b Mon Sep 17 00:00:00 2001 From: Florian Eck Date: Wed, 21 Oct 2020 19:17:02 +0200 Subject: [PATCH 04/21] allow to skip order by score --- lib/smart_search.rb | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/lib/smart_search.rb b/lib/smart_search.rb index 13e3de4..5ceda0b 100755 --- a/lib/smart_search.rb +++ b/lib/smart_search.rb @@ -57,35 +57,37 @@ def find_by_tags(tags = "", options = {}) tags = store_history_and_get_sanitized_search_tags(tags) tags = map_similarity_tags(tags) - # Load ranking from Search tags result_ids = [] - result_scores = {} #results = SmartSearchTag.select("entry_id, sum(boost) as score").group(:entry_id).where(table_name: self.table_name) query = case ActiveRecord::Base.connection.adapter_name when 'PostgreSQL' - "select entry_id, sum(boost) as score + "select entry_id #{SmartSearch::Config.order_by_score ? ', sum(boost) as score' : ''} from smart_search_tags where #{ActiveRecord::Base.connection.quote_column_name('table_name')}= '#{self.table_name}' - group by entry_id + GROUP BY entry_id HAVING (#{tags.join(' AND ')}) - order by score DESC" + #{SmartSearch::Config.order_by_score ? 'ORDER BY score DESC' : ''}" + else - "select entry_id, sum(boost) as score, #{adapater_based_group_method}(search_tags) as grouped_tags - from smart_search_tags where #{ActiveRecord::Base.connection.quote_column_name('table_name')}= '#{self.table_name}' and - (#{tags.join(' AND ')}) group by entry_id order by score DESC" + "select entry_id #{SmartSearch::Config.order_by_score ? ', sum(boost) as score' : ''}, #{adapater_based_group_method}(search_tags) as grouped_tags + FROM smart_search_tags + WHERE #{ActiveRecord::Base.connection.quote_column_name('table_name')}= '#{self.table_name}' and + (#{tags.join(' AND ')}) + GROUP BY entry_id + #{SmartSearch::Config.order_by_score ? 'ORDER BY score DESC' : ''}" end SmartSearchTag.connection.select_all(query).each do |r| result_ids << r["entry_id"].to_i - result_scores[r["entry_id"].to_i] = r['score'].to_f end results = self.where(self.primary_key => result_ids) results = results.offset(options[:offset]) if options[:offset] results = results.limit(options[:limit]) if options[:per_page] + results = results.reorder(self.order_default) if self.order_default return results end @@ -276,9 +278,11 @@ class Config cattr_accessor :search_models cattr_accessor :public_models + cattr_accessor :order_by_score self.search_models = [] self.public_models = [] + self.order_by_score = true def self.get_search_models self.search_models.map {|m| m.constantize} From 26b5327f6502299d0f0e80d01828edfb4fa8be79 Mon Sep 17 00:00:00 2001 From: Florian Eck Date: Tue, 27 Oct 2020 16:47:23 +0100 Subject: [PATCH 05/21] reworkd query for PSQL, mysql still missing --- lib/smart_search.rb | 60 +++++++++++++++++++++++++++++---------------- 1 file changed, 39 insertions(+), 21 deletions(-) diff --git a/lib/smart_search.rb b/lib/smart_search.rb index 5ceda0b..e99c689 100755 --- a/lib/smart_search.rb +++ b/lib/smart_search.rb @@ -57,37 +57,55 @@ def find_by_tags(tags = "", options = {}) tags = store_history_and_get_sanitized_search_tags(tags) tags = map_similarity_tags(tags) - result_ids = [] + base_select = "#{self.quoted_table_name}.* #{SmartSearch::Config.order_by_score ? ', SUM(boost) AS score' : ''}" - #results = SmartSearchTag.select("entry_id, sum(boost) as score").group(:entry_id).where(table_name: self.table_name) + join_query = "LEFT JOIN #{SmartSearchTag.quoted_table_name} + ON #{SmartSearchTag.quoted_table_name}.#{ActiveRecord::Base.connection.quote_column_name('table_name')} = '#{self.table_name}' + AND #{SmartSearchTag.quoted_table_name}.#{ActiveRecord::Base.connection.quote_column_name('entry_id')} = #{self.primary_key}" - query = case ActiveRecord::Base.connection.adapter_name - when 'PostgreSQL' - "select entry_id #{SmartSearch::Config.order_by_score ? ', sum(boost) as score' : ''} - from smart_search_tags where #{ActiveRecord::Base.connection.quote_column_name('table_name')}= '#{self.table_name}' - GROUP BY entry_id - HAVING (#{tags.join(' AND ')}) - #{SmartSearch::Config.order_by_score ? 'ORDER BY score DESC' : ''}" + group_clause = "#{self.quoted_table_name}.#{self.primary_key}, #{SmartSearchTag.column_names.map {|c| SmartSearchTag.quoted_table_name + '.' + c }.join(", ") }" - else - "select entry_id #{SmartSearch::Config.order_by_score ? ', sum(boost) as score' : ''}, #{adapater_based_group_method}(search_tags) as grouped_tags - FROM smart_search_tags - WHERE #{ActiveRecord::Base.connection.quote_column_name('table_name')}= '#{self.table_name}' and - (#{tags.join(' AND ')}) - GROUP BY entry_id - #{SmartSearch::Config.order_by_score ? 'ORDER BY score DESC' : ''}" - end + order_clause = if self.order_default + "#{self.order_default}" + elsif SmartSearch::Config.order_by_score + "score DESC" + end + results = case ActiveRecord::Base.connection.adapter_name + when 'PostgreSQL' - SmartSearchTag.connection.select_all(query).each do |r| - result_ids << r["entry_id"].to_i + self.select(base_select) + .joins(join_query) + .group(group_clause) + .having("#{tags.join(' AND ')}") + else + [base_select, group_clause, "HAVING (#{tags.join(' AND ')})", order_clause].join(" ") end - results = self.where(self.primary_key => result_ids) + + # query = case ActiveRecord::Base.connection.adapter_name +# when 'PostgreSQL' +# "select entry_id #{SmartSearch::Config.order_by_score ? ', sum(boost) as score' : ''} +# from smart_search_tags where #{ActiveRecord::Base.connection.quote_column_name('table_name')}= '#{self.table_name}' +# GROUP BY entry_id +# HAVING (#{tags.join(' AND ')}) +# #{SmartSearch::Config.order_by_score ? 'ORDER BY score DESC' : ''}" +# +# else +# "select entry_id #{SmartSearch::Config.order_by_score ? ', sum(boost) as score' : ''}, #{adapater_based_group_method}(search_tags) as grouped_tags +# FROM smart_search_tags +# WHERE #{ActiveRecord::Base.connection.quote_column_name('table_name')}= '#{self.table_name}' and +# (#{tags.join(' AND ')}) +# GROUP BY entry_id +# #{SmartSearch::Config.order_by_score ? 'ORDER BY score DESC' : ''}" +# end + + + + results = results.offset(options[:offset]) if options[:offset] results = results.limit(options[:limit]) if options[:per_page] - results = results.reorder(self.order_default) if self.order_default return results end From d5487230000e370bb5c62eca836e37324ceb7ba9 Mon Sep 17 00:00:00 2001 From: Florian Eck Date: Tue, 27 Oct 2020 18:11:32 +0100 Subject: [PATCH 06/21] fiy pager --- lib/smart_search.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/smart_search.rb b/lib/smart_search.rb index e99c689..8302657 100755 --- a/lib/smart_search.rb +++ b/lib/smart_search.rb @@ -105,7 +105,7 @@ def find_by_tags(tags = "", options = {}) results = results.offset(options[:offset]) if options[:offset] - results = results.limit(options[:limit]) if options[:per_page] + results = results.limit(options[:per_page]) if options[:per_page] return results end From 203e55f50a9e10885419e4f72593d8b0c778004a Mon Sep 17 00:00:00 2001 From: Florian Eck Date: Wed, 11 Nov 2020 14:20:31 +0100 Subject: [PATCH 07/21] fix ambigious primary key bug --- lib/smart_search.rb | 2 +- smart_search.gemspec | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/smart_search.rb b/lib/smart_search.rb index 8302657..d457c2b 100755 --- a/lib/smart_search.rb +++ b/lib/smart_search.rb @@ -61,7 +61,7 @@ def find_by_tags(tags = "", options = {}) join_query = "LEFT JOIN #{SmartSearchTag.quoted_table_name} ON #{SmartSearchTag.quoted_table_name}.#{ActiveRecord::Base.connection.quote_column_name('table_name')} = '#{self.table_name}' - AND #{SmartSearchTag.quoted_table_name}.#{ActiveRecord::Base.connection.quote_column_name('entry_id')} = #{self.primary_key}" + AND #{SmartSearchTag.quoted_table_name}.#{ActiveRecord::Base.connection.quote_column_name('entry_id')} = #{self.quoted_table_name}.#{self.primary_key}" group_clause = "#{self.quoted_table_name}.#{self.primary_key}, #{SmartSearchTag.column_names.map {|c| SmartSearchTag.quoted_table_name + '.' + c }.join(", ") }" diff --git a/smart_search.gemspec b/smart_search.gemspec index 70d4e7e..5d0c952 100755 --- a/smart_search.gemspec +++ b/smart_search.gemspec @@ -1,6 +1,6 @@ Gem::Specification.new do |s| s.name = 'smart_search' - s.version = '1.1' + s.version = '1.1.1' s.summary = "Simple, easy to use search MySQL based search for ActiveRecord" s.description = "SmartSearch adds full-text search functions to ActiveRecord running with MySQL, including search for similiar words. Its fast, simple, and works with almost zero-config!" s.authors = ["Florian Eck"] From 8a88d8a8d6f722a7df59df540c9e97d1f1a27dc8 Mon Sep 17 00:00:00 2001 From: Florian Eck Date: Tue, 26 Jan 2021 15:57:03 +0100 Subject: [PATCH 08/21] mysqlFix --- lib/smart_search.rb | 70 ++++++++++++++++++--------------------------- 1 file changed, 28 insertions(+), 42 deletions(-) diff --git a/lib/smart_search.rb b/lib/smart_search.rb index d457c2b..17b4e44 100755 --- a/lib/smart_search.rb +++ b/lib/smart_search.rb @@ -17,32 +17,36 @@ def self.included(base) module ClassMethods # Enable SmartSearch for the current ActiveRecord model. def smart_search(options = {:on => [], :split => false}) - if table_exists? - if SmartSearch::Config.search_models.index(self.name).nil? - SmartSearch::Config.search_models << self.name - end - # Check if search_tags exists - if !is_smart_search? + begin + if table_exists? + if SmartSearch::Config.search_models.index(self.name).nil? + SmartSearch::Config.search_models << self.name + end + # Check if search_tags exists + if !is_smart_search? - cattr_accessor :condition_default, :group_default, :tags, :order_default, :enable_similarity, :default_template_path + cattr_accessor :condition_default, :group_default, :tags, :order_default, :enable_similarity, :default_template_path - # BETA! - cattr_accessor :split_searchable_fields - self.split_searchable_fields = options[:split] + # BETA! + cattr_accessor :split_searchable_fields + self.split_searchable_fields = options[:split] - send :include, InstanceMethods - self.send(:after_commit, :create_search_tags, :if => :update_search_tags?) unless options[:auto] == false - self.send(:after_destroy, :clear_search_tags) - self.enable_similarity ||= true + send :include, InstanceMethods + self.send(:after_commit, :create_search_tags, :if => :update_search_tags?) unless options[:auto] == false + self.send(:after_destroy, :clear_search_tags) + self.enable_similarity ||= true - attr_accessor :query_score, :dont_update_search_tags + attr_accessor :query_score, :dont_update_search_tags - self.tags = options[:on] || [] - elsif is_smart_search? - # Allow re-adding attributes for search - logger.info("Re-Adding search data on #{self.name}: #{options[:on].inspect}".yellow) - self.tags += options[:on] + self.tags = options[:on] || [] + elsif is_smart_search? + # Allow re-adding attributes for search + logger.info("Re-Adding search data on #{self.name}: #{options[:on].inspect}".yellow) + self.tags += options[:on] + end end + rescue ActiveRecord::NoDatabaseError => e + puts "Could not set up smart_search due to missing database" end end @@ -79,31 +83,13 @@ def find_by_tags(tags = "", options = {}) .group(group_clause) .having("#{tags.join(' AND ')}") else - [base_select, group_clause, "HAVING (#{tags.join(' AND ')})", order_clause].join(" ") + self.select(base_select) + .joins(join_query) + .group(group_clause) + .having("#{tags.join(' AND ')}") end - # query = case ActiveRecord::Base.connection.adapter_name -# when 'PostgreSQL' -# "select entry_id #{SmartSearch::Config.order_by_score ? ', sum(boost) as score' : ''} -# from smart_search_tags where #{ActiveRecord::Base.connection.quote_column_name('table_name')}= '#{self.table_name}' -# GROUP BY entry_id -# HAVING (#{tags.join(' AND ')}) -# #{SmartSearch::Config.order_by_score ? 'ORDER BY score DESC' : ''}" -# -# else -# "select entry_id #{SmartSearch::Config.order_by_score ? ', sum(boost) as score' : ''}, #{adapater_based_group_method}(search_tags) as grouped_tags -# FROM smart_search_tags -# WHERE #{ActiveRecord::Base.connection.quote_column_name('table_name')}= '#{self.table_name}' and -# (#{tags.join(' AND ')}) -# GROUP BY entry_id -# #{SmartSearch::Config.order_by_score ? 'ORDER BY score DESC' : ''}" -# end - - - - - results = results.offset(options[:offset]) if options[:offset] results = results.limit(options[:per_page]) if options[:per_page] From bf458bd5e00e7c0710710c77e154891e30de2b33 Mon Sep 17 00:00:00 2001 From: Florian Eck Date: Fri, 16 Apr 2021 13:53:42 +0200 Subject: [PATCH 09/21] improve REGexp sanitize --- lib/smart_search.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/smart_search.rb b/lib/smart_search.rb index 17b4e44..3ed470e 100755 --- a/lib/smart_search.rb +++ b/lib/smart_search.rb @@ -121,7 +121,7 @@ def find_by_splitted_tags(search_fields = {}) private def store_history_and_get_sanitized_search_tags(orig_tags) orig_tags = orig_tags.join(" ") if orig_tags.is_a?(Array) - sanitized_tags = orig_tags.gsub(/[\(\)\[\]\'\"\*\%\|\&]/, '').split(/[\ -]/).select {|t| !t.blank?} + sanitized_tags = orig_tags.gsub(/[\(\)\[\]\'\"\*\%\|\&\+\.\$]/, '').split(/[\ -]/).select {|t| !t.blank?} # Save Data for similarity analysis if sanitized_tags.join(' ').size > 3 From 07ed7ec95669134b3e87189ae139a3ddbf02011f Mon Sep 17 00:00:00 2001 From: Florian Eck Date: Fri, 16 Apr 2021 13:54:39 +0200 Subject: [PATCH 10/21] version update --- smart_search.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/smart_search.gemspec b/smart_search.gemspec index 5d0c952..ce188bb 100755 --- a/smart_search.gemspec +++ b/smart_search.gemspec @@ -1,6 +1,6 @@ Gem::Specification.new do |s| s.name = 'smart_search' - s.version = '1.1.1' + s.version = '1.1.2' s.summary = "Simple, easy to use search MySQL based search for ActiveRecord" s.description = "SmartSearch adds full-text search functions to ActiveRecord running with MySQL, including search for similiar words. Its fast, simple, and works with almost zero-config!" s.authors = ["Florian Eck"] From 3f275306a9dde4f35edb4d90ef491c0c7eed61c1 Mon Sep 17 00:00:00 2001 From: Florian Eck Date: Mon, 26 Apr 2021 18:13:31 +0200 Subject: [PATCH 11/21] also sanitize '?' --- lib/smart_search.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/smart_search.rb b/lib/smart_search.rb index 3ed470e..7d7ddf0 100755 --- a/lib/smart_search.rb +++ b/lib/smart_search.rb @@ -121,7 +121,7 @@ def find_by_splitted_tags(search_fields = {}) private def store_history_and_get_sanitized_search_tags(orig_tags) orig_tags = orig_tags.join(" ") if orig_tags.is_a?(Array) - sanitized_tags = orig_tags.gsub(/[\(\)\[\]\'\"\*\%\|\&\+\.\$]/, '').split(/[\ -]/).select {|t| !t.blank?} + sanitized_tags = orig_tags.gsub(/[\(\)\[\]\'\"\*\%\|\&\+\.\$\?]/, '').split(/[\ -]/).select {|t| !t.blank?} # Save Data for similarity analysis if sanitized_tags.join(' ').size > 3 From a43629c4f15517be86c275767267f23af196910b Mon Sep 17 00:00:00 2001 From: Florian Eck Date: Wed, 28 Apr 2021 18:49:04 +0200 Subject: [PATCH 12/21] allow to pass block to results --- lib/smart_search.rb | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/lib/smart_search.rb b/lib/smart_search.rb index 7d7ddf0..bfa1a80 100755 --- a/lib/smart_search.rb +++ b/lib/smart_search.rb @@ -56,7 +56,7 @@ def is_smart_search? end # Serach database for given search tags - def find_by_tags(tags = "", options = {}) + def find_by_tags(tags = "", options = {}, &block) tags = store_history_and_get_sanitized_search_tags(tags) tags = map_similarity_tags(tags) @@ -89,6 +89,13 @@ def find_by_tags(tags = "", options = {}) .having("#{tags.join(' AND ')}") end + if options[:distinct] == true + results = results.distinct + end + + if block_given? + results = yield(results) + end results = results.offset(options[:offset]) if options[:offset] results = results.limit(options[:per_page]) if options[:per_page] @@ -96,7 +103,7 @@ def find_by_tags(tags = "", options = {}) return results end - def find_by_splitted_tags(search_fields = {}) + def find_by_splitted_tags(search_fields = {}, &block) sanitized_search_fields = {} search_fields.each do |field, tags| next if tags.blank? @@ -114,7 +121,11 @@ def find_by_splitted_tags(search_fields = {}) end result_ids = eval(result_list.map(&:to_s).join(" & ")) - self.where(self.primary_key => result_ids) + result = self.where(self.primary_key => result_ids) + + if block_given? + result = yield(result) + end end # Private Query Helper Methods From 963d443ae6e6b045c1c32121c14fdf0b2abcddfe Mon Sep 17 00:00:00 2001 From: Florian Eck Date: Wed, 28 Apr 2021 18:55:53 +0200 Subject: [PATCH 13/21] consistend variable naming --- lib/smart_search.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/smart_search.rb b/lib/smart_search.rb index bfa1a80..a3689b2 100755 --- a/lib/smart_search.rb +++ b/lib/smart_search.rb @@ -121,10 +121,10 @@ def find_by_splitted_tags(search_fields = {}, &block) end result_ids = eval(result_list.map(&:to_s).join(" & ")) - result = self.where(self.primary_key => result_ids) + results = self.where(self.primary_key => result_ids) if block_given? - result = yield(result) + results = yield(results) end end From 47d61c853dee7c87e401bc464cd28f625ad63e95 Mon Sep 17 00:00:00 2001 From: Florian Eck Date: Wed, 19 May 2021 17:24:45 +0200 Subject: [PATCH 14/21] allow batch create search tags --- lib/smart_search.rb | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/lib/smart_search.rb b/lib/smart_search.rb index a3689b2..ed4ee29 100755 --- a/lib/smart_search.rb +++ b/lib/smart_search.rb @@ -212,23 +212,33 @@ def update_search_tags? end # create search tags for this very record based on the attributes defined in ':on' option passed to the 'Class.smart_search' method - def create_search_tags + def create_search_tags(options = {}) # storing tags must never fail the systems begin self.get_calculated_tags_list! self.clear_search_tags + data = [] + (self.class.split_searchable_fields ? @calculated_tags_list : get_merged_calculated_tags).each do |t| if !t[:search_tags].blank? && t[:search_tags].size > 1 - begin - SmartSearchTag.create(t.merge!(:table_name => self.class.table_name, :entry_id => self.id, :search_tags => t[:search_tags].strip.split(" ").uniq.join(" "))) - rescue Exception => e - + if options[:export] + data << t.merge!(:table_name => self.class.table_name, :entry_id => self.id, :search_tags => t[:search_tags].strip.split(" ").uniq.join(" ")) + else + begin + SmartSearchTag.create(t.merge!(:table_name => self.class.table_name, :entry_id => self.id, :search_tags => t[:search_tags].strip.split(" ").uniq.join(" "))) + rescue Exception => e + + end end end end + if options[:export] + return data + end + rescue Exception => e Rails.logger.error "SMART SEARCH FAILED TO TO STORE SEARCH TAGS #{self.class.name} #{self.id}" Rails.logger.error e.message From dd16049b32926a269ca73814b2cfa6884071a1ef Mon Sep 17 00:00:00 2001 From: Florian Eck Date: Fri, 14 Jan 2022 23:13:54 +0100 Subject: [PATCH 15/21] improve query for non-similar search tags --- lib/smart_search.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/smart_search.rb b/lib/smart_search.rb index ed4ee29..84dd74f 100755 --- a/lib/smart_search.rb +++ b/lib/smart_search.rb @@ -156,7 +156,11 @@ def map_similarity_tags(tags) when 'PostgreSQL' "string_agg(search_tags, ' ') ~* '#{similars}'" else - "search_tags REGEXP '#{similars}'" + if similars.any? + "search_tags REGEXP '#{similars}'" + else + "search_tags LIKE '%#{t}%'" + end end end From d51633a73efd3d7fd342717dce847fb621c91e62 Mon Sep 17 00:00:00 2001 From: Florian Eck Date: Fri, 14 Jan 2022 23:41:55 +0100 Subject: [PATCH 16/21] imporove query sanitze --- lib/smart_search.rb | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/smart_search.rb b/lib/smart_search.rb index 84dd74f..52345b7 100755 --- a/lib/smart_search.rb +++ b/lib/smart_search.rb @@ -34,7 +34,11 @@ def smart_search(options = {:on => [], :split => false}) send :include, InstanceMethods self.send(:after_commit, :create_search_tags, :if => :update_search_tags?) unless options[:auto] == false self.send(:after_destroy, :clear_search_tags) - self.enable_similarity ||= true + if options[:disable_similarity].present? + self.enable_similarity = false + else + self.enable_similarity = true + end attr_accessor :query_score, :dont_update_search_tags @@ -132,7 +136,7 @@ def find_by_splitted_tags(search_fields = {}, &block) private def store_history_and_get_sanitized_search_tags(orig_tags) orig_tags = orig_tags.join(" ") if orig_tags.is_a?(Array) - sanitized_tags = orig_tags.gsub(/[\(\)\[\]\'\"\*\%\|\&\+\.\$\?]/, '').split(/[\ -]/).select {|t| !t.blank?} + sanitized_tags = orig_tags.gsub(/[\(\)\[\]\'\"\*\%\|\&\+\.\$\?]/, ' ').split(/[\ -]/).select {|t| !t.blank?} # Save Data for similarity analysis if sanitized_tags.join(' ').size > 3 From 36a5fa683621acfc2eb9a25f4c256325dae483e3 Mon Sep 17 00:00:00 2001 From: Florian Eck Date: Fri, 14 Jan 2022 23:49:14 +0100 Subject: [PATCH 17/21] fix --- lib/smart_search.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/smart_search.rb b/lib/smart_search.rb index 52345b7..00a207e 100755 --- a/lib/smart_search.rb +++ b/lib/smart_search.rb @@ -155,13 +155,13 @@ def map_similarity_tags(tags) # Similarity if self.enable_similarity == true tags.map do |t| - similars = SmartSimilarity.similars(t, :increment_counter => true).join("|") + similars = SmartSimilarity.similars(t, :increment_counter => true) case ActiveRecord::Base.connection.adapter_name when 'PostgreSQL' - "string_agg(search_tags, ' ') ~* '#{similars}'" + "string_agg(search_tags, ' ') ~* '#{similars.join("|")}'" else if similars.any? - "search_tags REGEXP '#{similars}'" + "search_tags REGEXP '#{similars.join("|")}'" else "search_tags LIKE '%#{t}%'" end From 57a0e6a23bf32fb991d65cc216f68f3c6dd8da60 Mon Sep 17 00:00:00 2001 From: Florian Eck Date: Fri, 14 Jan 2022 23:54:53 +0100 Subject: [PATCH 18/21] meh --- lib/smart_search.rb | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/lib/smart_search.rb b/lib/smart_search.rb index 00a207e..b4f7f50 100755 --- a/lib/smart_search.rb +++ b/lib/smart_search.rb @@ -155,16 +155,12 @@ def map_similarity_tags(tags) # Similarity if self.enable_similarity == true tags.map do |t| - similars = SmartSimilarity.similars(t, :increment_counter => true) + similars = SmartSimilarity.similars(t, :increment_counter => true).join("|") case ActiveRecord::Base.connection.adapter_name when 'PostgreSQL' - "string_agg(search_tags, ' ') ~* '#{similars.join("|")}'" + "string_agg(search_tags, ' ') ~* '#{similars}'" else - if similars.any? - "search_tags REGEXP '#{similars.join("|")}'" - else - "search_tags LIKE '%#{t}%'" - end + "search_tags REGEXP '#{similars}'" end end From bdf8af56c2ad14e85495b96043c3e56643e9ade6 Mon Sep 17 00:00:00 2001 From: Florian Eck Date: Mon, 7 Aug 2023 06:56:59 +0200 Subject: [PATCH 19/21] remove amatch and use 'DidYouMean' --- lib/smart_similarity.rb | 10 ++-------- smart_search.gemspec | 3 +-- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/lib/smart_similarity.rb b/lib/smart_similarity.rb index 02dfeac..bae2537 100755 --- a/lib/smart_similarity.rb +++ b/lib/smart_similarity.rb @@ -17,12 +17,6 @@ class SmartSimilarity < ActiveRecord::Base #== Konstanten # Defines the min. result of word simililarity check SIMILARITY_FACTOR = 0.81 - # Defines first simililarity check method - SIMILARITY_METHOD_1 = :jarowinkler - # Defines first simililarity check method - SIMILARITY_METHOD_2 = :levenshtein - - # An average of both results will generated and compered with 'SIMILARITY_FACTOR' # Limit Number of similar words SIMILARITY_LIMIT = 5 @@ -100,8 +94,8 @@ def self.similars(word, options = {}) # Return match score for two words bases und the two defined similarity methods def self.match_words(word1, word2) - x1 = word1.downcase.send("#{SIMILARITY_METHOD_1}_similar", word2.downcase) - x2 = word1.downcase.send("#{SIMILARITY_METHOD_2}_similar", word2.downcase) + x1 = DidYouMean::JaroWinkler.distance(word1.downcase, word2.downcase) + x2 = DidYouMean::Levenshtein.distance(word1.downcase, word2.downcase) return (x1+x2)/2.0 end diff --git a/smart_search.gemspec b/smart_search.gemspec index ce188bb..062ef52 100755 --- a/smart_search.gemspec +++ b/smart_search.gemspec @@ -1,6 +1,6 @@ Gem::Specification.new do |s| s.name = 'smart_search' - s.version = '1.1.2' + s.version = '1.2.1' s.summary = "Simple, easy to use search MySQL based search for ActiveRecord" s.description = "SmartSearch adds full-text search functions to ActiveRecord running with MySQL, including search for similiar words. Its fast, simple, and works with almost zero-config!" s.authors = ["Florian Eck"] @@ -10,7 +10,6 @@ Gem::Specification.new do |s| s.homepage = 'https://github.com/florianeck/smart_search' s.add_dependency "rails", ">= 4.0.4" - s.add_dependency "amatch" s.add_dependency "friendly_extensions" s.add_dependency "unicode-emoji" s.add_dependency "ruby-progressbar" From 2380d2defaa1e2963a8dd4115550ea5bd8759a11 Mon Sep 17 00:00:00 2001 From: Florian Eck Date: Mon, 7 Aug 2023 06:59:44 +0200 Subject: [PATCH 20/21] fix dep --- lib/smart_search/engine.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/smart_search/engine.rb b/lib/smart_search/engine.rb index 56537e0..d5b9a41 100755 --- a/lib/smart_search/engine.rb +++ b/lib/smart_search/engine.rb @@ -2,10 +2,9 @@ module SmartSearch class Engine < Rails::Engine engine_name 'smart_search' - + isolate_namespace SmartSearch require "friendly_extensions" - require "amatch" end end From 573299fd0518e3f68bfb65e5dae5f13817e87de1 Mon Sep 17 00:00:00 2001 From: Florian Eck Date: Wed, 9 Aug 2023 20:18:25 +0200 Subject: [PATCH 21/21] remove dep --- smart_search.gemspec | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/smart_search.gemspec b/smart_search.gemspec index 062ef52..94414e8 100755 --- a/smart_search.gemspec +++ b/smart_search.gemspec @@ -1,6 +1,6 @@ Gem::Specification.new do |s| s.name = 'smart_search' - s.version = '1.2.1' + s.version = '1.2.2' s.summary = "Simple, easy to use search MySQL based search for ActiveRecord" s.description = "SmartSearch adds full-text search functions to ActiveRecord running with MySQL, including search for similiar words. Its fast, simple, and works with almost zero-config!" s.authors = ["Florian Eck"] @@ -9,9 +9,6 @@ Gem::Specification.new do |s| s.test_files = Dir.glob("test/**/*") s.homepage = 'https://github.com/florianeck/smart_search' - s.add_dependency "rails", ">= 4.0.4" s.add_dependency "friendly_extensions" s.add_dependency "unicode-emoji" - s.add_dependency "ruby-progressbar" - s.add_dependency "parallel" end \ No newline at end of file