Picky Case Study: Location Based Ads

ruby / picky / case study

This is a post in the Picky series on its workings.

Intro

Let’s say we offered a search engine where we could search stores using a name and/or location. A location could be a zipcode or suburb.

class Store
 attr_reader :id,
             :name,
             :location
end

Now, when users search a store using a name and location, it should also show us what other stores are there, in a sidebar, to help with exploration and show the user what else is there.

So, when you’d look for “Barbershop Brooklyn”, you’d also get other nice stores that are located in “Brooklyn”.

It’s tricky. Without Picky.

We could define two indexes. Both index all stores. But one just has the location category, and the other has name and location.

But that is a waste of precious memory space.

That’s what the new Picky version can help with.

Picky 3.1.3

Version 3.1.3 introduces the ignore option in the search definition block:

stores = Index.new :stores do
  source { Store.order('name DESC') }
  category :name
  category :location
end

search = Search.new stores do
  ignore :name
end

The ignore :name makes that Search throw away (ignore) any tokens that map to that category. So if Picky finds that the word “barbershop” in “barbershop brooklyn” maps to the :name category, such that both would map to [:name, :location], then Picky throws away the “barbershop”, such that only :location brooklyn remains.

Location-based Ads

For our example, we would define the main search like this

main_search = Search.new stores

because we want it to not ignore anything. If the user enters “barbershop brooklyn”, it must be found in the name (barbershop) and location (brooklyn), or Picky won’t return it.

Now, the ads search works a little differently. Whatever search word maps to name, we ignore it. We are only interested in words matching the location

ads_search = Search.new stores do
  ignore :name
end

In the webapp, we would then search twice: Once for the “real” search, and once just for the ads to show on the side, using the same search.*

Because wouldn’t you just love to try Vinnie’s Pizza after Uncle Joe’s Barbershop? I would.

Examples

Not following? Let me give you a few examples:

Searching for “Barbershop” will yield results in the main search, but none in the ads, since “Barbershop” does not match any location.

Searching for “Santa Barbara” will probably yield something like “Santa Lucia Pizzeria, Santa Barbara” for the main results, and return ads from Santa Barbara, since “Santa” or “Barbara” matching as names is ignored.

Searching for “Chicago” will return basically the same for the main result and the ads. But who searches just for “Chicago”?

Advanced*

If you think calling the Picky server a second time just for the ads is too much, you can use the piggybacking technique:

In the Sinatra server, search the main search, but at the same time, search the ads. Then, stick the results for the ads onto the main results.

get '/stores' do
  query = params[:query]

  main_results = main_search.search query # etc.
  ads_results  = ads_search.search query # etc.

  results_hash = main_results.to_hash
  results_hash[:ads] = ads_results.to_hash

  results_hash.to_json
end

Then, in the app server, de-piggyback the ad results and render separately. As usual, it’s all Ruby.

Note

You could of course use a real geosearch instead of the simple location above. But it’s just more understandable like this.

Also, sometimes this is enough, and anything more correct is simply unnecessary and costs too much time.

Note 2

I recommend not to use this in the normal search. It’s just too surprising for users to have their precious search words thrown away like this.

As if they were just mere strings. To be tentacled away.

That reminds me… one of the next blog posts really has to be called “Day of the Tentacle”! cough

Next Picky Case Study: Running it in a DRb Server

Share


Previous

Comments?