Picky Case Study: Location Based Ads Tweet
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 ServerShare
Previous Picky Case Study: Restricting Results