Simple Search Feature in Rails/MySQL
Today, we decided that searching was a desirable feature for Giftify. So, I promised that we will have a search engine by the end of the day. I was able to get it done much faster, which is why I have time to make a post now.
One thing to note is that this is a very preliminary form of Search. The next iteration will definitely be acquiring Google! On a more realistic note, we will most likely use Ferret (Ruby implementation of Lucene) at some point. Take a look at here, here, and here.
But here’s short version of what I did today:
First, the table and objects to be searched. The items in our catalog have these characteristics which I would like to make searchable: “name”, “description”, “categories”. Note that the objective of this exercise is to search for an item which has the search word somewhere in its name, description, or list of categories which it’s associated with.
We already have the table/model Item. Add another model for the lookup words and a migration for a join table for the has_and_belongs_to_many relationship between Item and LookupWord.
class Item < ActiveRecord::Base
has_and_belongs_to_many :lookup_words
end
class LookupWord < ActiveRecord::Base
has_and_belongs_to_many :items
end
At this point you should be able to populate your lookup table of words. Note, that I put an index on the lookup_words table right off the bat which was probably a bad idea since it slowed down insertions into the table. I suggest building the lookup_words table first and then index it on the actual words for faster lookups.
The following Ruby script (within the Rails environment) does the job:
require 'rubygems'
require File.dirname(__FILE__) + '/config/environment'
item_to_lookup_word_map = {}
Item.find(:all).each do |item|
composite_search = item.name+" "+item.description+" "+item.categories
# take all the words (alpha) and array-ize
composite_search_array = composite_search.downcase.scan(/[a-z]+/).compact
# remove all words that are less than 3 letters long
composite_search_array.collect! {|w| w unless w.size<3}
composite_search_array.compact!
composite_search_array.uniq!
# add data to hash
item_to_lookup_word_map[item.id] = composite_search_array
end
total = item_to_lookup_word_map.values.inject(0) {|t, val| t += val.size}
print "total number of search index items: #{total}"
LookupWord.destroy_all
# now do the deed
Item.find(:all).each do |item|
item_to_lookup_word_map[item.id].each do |word|
lw = LookupWord.find_or_create_by_name(word)
lw.items << item
end
end
[…] but all the start-up fun kept me from doing it. The first part of the post was published on Oct 17 (Simple Search Feature) and covered my Do It Yourself solution for the catalog search feature in […]
Pingback by blog.sojoodi.com » Simple Search Feature in Rails/MySQL (Part 2) — December 2, 2007 @ 9:42 pm
Nice Blog. Good Look
Comment by Cialissi — July 17, 2008 @ 5:21 am