mezis / blurrily

Millisecond fuzzy string matching for Ruby
MIT License
90 stars 14 forks source link

MultiTenancy #36

Open mrmattwright opened 9 years ago

mrmattwright commented 9 years ago

Hello, Matt here! :)

One thing that would be amazing in Blurrily is the ability to hold multiple types and to optionally search by type:

So you would have code like: client.put('London', 1337, 'Location') client.put('London Grammar', 1335, 'Band')

the optionally find like this: map.find('lonndon') finds both

map.find('lonndon', 'Band') finds only 'London Grammar'

Not sure if that is possible the way the trigrams are stored in a single file though?

mezis commented 9 years ago

We (at HouseTrip) have chosen to mot make multitenancy part of blurrily's C internals to keep it as simple as possible.

The server does support multiple "databases" though, as provided by MapGroup, and you could have one client per "type" (database) without significant overhead.

I'd suggest writing a wrapper class around the client, e.g. (pseudocode):

class MultiClient
  def initialize(types)
     @clients = {}
     types.each { |t| @client[type] = Blurrily::Client.new(db_name: type) }
  end

  def put(value, key, type)
     @clients[type].put(value, key)
  end

  def find(key, type=nil)
     if type
       return @clients[type].find(key)
     end
     @clients.values.map { |c| c.find(key) }.magic_sort_method
  end
end
mrmattwright commented 9 years ago

Fast response! Thanks. Sounds like a sensible approach. That makes a lot of sense and is in fact how we are doing some other tenancy type issues...more on a per client basis (as we are SaaS)... so we have

NEO4J_TENANCIES[org.tenancy_name]

Type things going on, and in fact already have a Blurrily instance per Organisation Tenancy. I'll add the next level down too, which will be a per tenancy tenancy as you suggest...will send a screenshot. :)

Incidentally we are using Angular.js + Bootstrap TypeAhead to get our list of results from Blurily, works really well! Thanks, chat soon! M.

mrmattwright commented 9 years ago

Julien..your suggestion worked very well, thanks! Ended up looking like this...

We just sorted on the Blurrily Score and Weights that come back in the end, which seems to work well enough.

I must say it is fast. Calling 9 clients and then sorting (and displaying the resulting .json) all happens in around 250ms. Solid!

client = Blurrily::Client.new(config)
fuzzy_matches = client.find(params['name']).map!{|tuple| tuple.push("Person") }

fuzzy_matches.concat(Organisation.find_all_by_name(params['name']).map!{|tuple| tuple.push("Organisation")})
fuzzy_matches.concat(CorporateTitle.find_all_by_name(params['name']).map!{|tuple| tuple.push("CorporateTitle")})

#Order by score asc then weight desc 
fuzzy_matches.sort!{|a,b| [b[1],a[2]] <=> [a[1],b[2]]}

We added a bit of FontAwesome, Angular and Bootstrap so it now looks a little like this:

screenshot 2014-10-15 08 47 32

mezis commented 9 years ago

Nice!

Pretty sure we could cut down those 250ms by half or better, by being a bit smarter with clients (using a single connection & pipelining requests). I’ve put it on my to-do list… no promises ^_^