Permalink
Browse files

Changed Article mapping so that we can search & facet against author …

…names

Based on previous refactoring, we're now addding a specific mapping for the `author` property,
so that it's analyzed as "multi field" property.

This means it's:

1. Split into tokens the usual way search engine works, with the snowball analyzer.
2. Left "as is", without any modification, as an "exact" sub-property.

This illustrates one of the usual use-cases for multi field properties: you want to search
against them as usual, but you also want to use their literal, unmodified value for aggregations.

This allows us to get rid of database calls (`Author.find(facet['term'])`) in the view layer,
and use information already in the index for displaying the faceted navigation sidebar.

Notice we facet against the `author.name.exact` field, and that we have changed the mechanics
of limiting results based on user's choice in right-hand sidebar: instead of query, we are
using filter, again on the `author.name.exact` field.

This means, the **query** is used to limit the results, but **faceted navigation** still displays
the distribution of results among authors, when you limit the results to a specific author,
because a **filter** is used; facets are bound only by queries, not filters.

See <http://www.elasticsearch.org/guide/reference/api/search/facets/index.html> for more information.
  • Loading branch information...
1 parent ee1f6f3 commit 03c45c365d1cc23c27ec67280b0fe315164ab116 @karmi committed Dec 16, 2011
@@ -8,25 +8,29 @@ class Article < ActiveRecord::Base
mapping do
indexes :id, type: 'integer'
indexes :author_id, type: 'integer'
- indexes :author_name
+ indexes :author, type: 'object',
+ properties: {
+ name: { type: 'multi_field',
+ fields: { name: { type: 'string', analyzer: 'snowball' },
+ exact: { type: 'string', index: 'not_analyzed' } } } }
indexes :name, boost: 10
indexes :content # analyzer: 'snowball'
indexes :published_at, type: 'date'
indexes :comments_count, type: 'integer'
@Silex
Silex Apr 25, 2012

Aren't you supposed to remove/refactor :comments_count too?

end
- def self.search(params)
+ def self.search(params={})
tire.search(page: params[:page], per_page: 2) do
query do
boolean do
must { string params[:query], default_operator: "AND" } if params[:query].present?
must { range :published_at, lte: Time.zone.now }
- must { term :author_id, params[:author_id] } if params[:author_id].present?
end
end
+ filter :term, 'author.name.exact' => params[:author] if params[:author].present?
sort { by :published_at, "desc" } if params[:query].blank?
facet "authors" do
- terms :author_id
+ terms 'author.name.exact'
end
# raise to_curl
end
@@ -12,9 +12,9 @@
<ul>
<% @articles.facets['authors']['terms'].each do |facet| %>
<li>
- <%= link_to_unless_current Author.find(facet['term']).name, params.merge(author_id: facet['term']) %>
- <% if params[:author_id] == facet['term'].to_s %>
- (<%= link_to "remove", author_id: nil %>)
+ <%= link_to_unless_current facet['term'], params.merge(author: facet['term']) %>
+ <% if params[:author] == facet['term'].to_s %>
+ (<%= link_to "remove", params.merge(author: nil) %>)
<% else %>
(<%= facet['count'] %>)
<% end %>

2 comments on commit 03c45c3

@9mm
9mm commented on 03c45c3 Sep 25, 2012

What does this part do? exact: { type: 'string', index: 'not_analyzed' }

@ches
ches commented on 03c45c3 Nov 16, 2012

@ecefx He explains in the commit message -- multi_field is used to index the author two ways:

  1. With snowball, you could search articles for "smith" and find those written by Bob Smith.
  2. With no analysis, so "Bob Smith" is indexed as-is, thus you can aggregate (such as faceting) by the exact name. The keys name and exact are arbitrary, you can choose them to refer to each defined multi-field meaningfully.
Please sign in to comment.