<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Erics Tech Blog &#187; sphinx</title>
	<atom:link href="http://eric.lubow.org/tag/sphinx/feed/" rel="self" type="application/rss+xml" />
	<link>http://eric.lubow.org</link>
	<description>Thoughts, musings, and other idealistic (sometimes useful) systems and development hoopla.</description>
	<lastBuildDate>Fri, 18 Nov 2011 14:56:45 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1.4</generator>
		<item>
		<title>Model Specific Formatted Search Results Using Thinking Sphinx</title>
		<link>http://eric.lubow.org/2010/ruby/rails/model-specific-formatted-search-results-using-thinking-sphinx/</link>
		<comments>http://eric.lubow.org/2010/ruby/rails/model-specific-formatted-search-results-using-thinking-sphinx/#comments</comments>
		<pubDate>Mon, 08 Feb 2010 14:15:23 +0000</pubDate>
		<dc:creator>eric</dc:creator>
				<category><![CDATA[Rails]]></category>
		<category><![CDATA[database]]></category>
		<category><![CDATA[search]]></category>
		<category><![CDATA[sphinx]]></category>

		<guid isPermaLink="false">http://eric.lubow.org/?p=538</guid>
		<description><![CDATA[Having recently implemented Thinking Sphinx on one of my web sites, I thought it would be cool to be able to search every indexed model. With Thinking Sphinx, it&#8217;s easy to have a bunch of different classes returned in the results. The tougher part is displaying them in a way that is organized (although admittedly [...]]]></description>
			<content:encoded><![CDATA[<p>Having recently implemented <a href="http://freelancing-god.github.com/ts/en">Thinking Sphinx</a> on one of my web sites, I thought it would be cool to be able to search every indexed model.  With Thinking Sphinx, it&#8217;s easy to have a bunch of different classes returned in the results.  The tougher part is displaying them in a way that is organized (although admittedly not very DRY).<br />
<span id="more-538"></span><br />
Let&#8217;s start out with the controller method for search results (<strong>app/controllers/search_controller.rb</strong>):</p>
<div class="codecolorer-container rails default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="rails codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> result<br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">if</span> !params<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:model</span><span style="color:#006600; font-weight:bold;">&#93;</span>.<span style="color:#9900CC;">blank</span>?<br />
&nbsp; &nbsp; &nbsp; <span style="color:#0066ff; font-weight:bold;">@model</span> = params<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:model</span><span style="color:#006600; font-weight:bold;">&#93;</span><br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">else</span><br />
&nbsp; &nbsp; &nbsp; <span style="color:#0066ff; font-weight:bold;">@model</span> = <span style="color:#996600;">&quot;ThinkingSphinx&quot;</span><br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
&nbsp; &nbsp; <span style="color:#0066ff; font-weight:bold;">@query</span> = params<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:search</span><span style="color:#006600; font-weight:bold;">&#93;</span><span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:query</span><span style="color:#006600; font-weight:bold;">&#93;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color:#0066ff; font-weight:bold;">@results</span> = Search.<span style="color:#9900CC;">model_search</span><span style="color:#006600; font-weight:bold;">&#40;</span>@model, <span style="color:#0066ff; font-weight:bold;">@query</span><span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div></div>
<p>Also, let&#8217;s make sure we define the actual search model.  I define it in a separate search library (<strong>lib/search.rb</strong>).  This is the relevant snippet of code:</p>
<div class="codecolorer-container rails default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="rails codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> <span style="color:#0000FF; font-weight:bold;">self</span>.<span style="color:#9900CC;">model_search</span><span style="color:#006600; font-weight:bold;">&#40;</span>model, keywords, var = <span style="color:#006600; font-weight:bold;">&#123;</span><span style="color:#006600; font-weight:bold;">&#125;</span><span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; <span style="color:#0066ff; font-weight:bold;">@search_options</span> = <span style="color:#006600; font-weight:bold;">&#123;</span> <span style="color:#ff3333; font-weight:bold;">:page</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> var<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:page</span><span style="color:#006600; font-weight:bold;">&#93;</span> <span style="color:#006600; font-weight:bold;">||</span> <span style="color:#006666;">1</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color:#ff3333; font-weight:bold;">:per_page</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006666;">15</span> <span style="color:#006600; font-weight:bold;">&#125;</span><br />
<br />
&nbsp; &nbsp; <span style="color:#0066ff; font-weight:bold;">@search_options</span>.<span style="color:#9900CC;">merge</span>!<span style="color:#006600; font-weight:bold;">&#40;</span> <span style="color:#ff3333; font-weight:bold;">:order</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">&quot;@relevance DESC&quot;</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color:#ff3333; font-weight:bold;">:sort_mode</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#ff3333; font-weight:bold;">:expr</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color:#ff3333; font-weight:bold;">:sort_by</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">&quot;@weight * @weight&quot;</span><span style="color:#006600; font-weight:bold;">&#41;</span><br />
<br />
&nbsp; &nbsp; model.<span style="color:#9900CC;">constantize</span>.<span style="color:#9900CC;">search</span><span style="color:#006600; font-weight:bold;">&#40;</span>keywords, <span style="color:#0066ff; font-weight:bold;">@search_options</span><span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div></div>
<p>Assuming that we are working with the all models search, where the above model is <em>ThinkingSphinx</em>, let&#8217;s iterate over the search results with this code in the view (<strong>app/views/search/results.html.erb</strong>):</p>
<div class="codecolorer-container rails default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="rails codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color:#006600; font-weight:bold;">&lt;</span> <span style="color:#006600; font-weight:bold;">%</span> <span style="color:#9966CC; font-weight:bold;">if</span> <span style="color:#0066ff; font-weight:bold;">@results</span>.<span style="color:#9900CC;">total_entries</span> <span style="color:#006600; font-weight:bold;">&gt;</span> <span style="color:#006666;">0</span> <span style="color:#006600; font-weight:bold;">%&gt;</span><br />
<span style="color:#006600; font-weight:bold;">&lt;</span>div id=<span style="color:#996600;">&quot;localLocationList&quot;</span><span style="color:#006600; font-weight:bold;">&gt;</span><br />
&nbsp; &nbsp; <span style="color:#006600; font-weight:bold;">&lt;</span>ul <span style="color:#9966CC; font-weight:bold;">class</span>=<span style="color:#996600;">&quot;list&quot;</span><span style="color:#006600; font-weight:bold;">&gt;</span><br />
&nbsp; &nbsp; <span style="color:#006600; font-weight:bold;">&lt;</span> <span style="color:#006600; font-weight:bold;">%</span> <span style="color:#0066ff; font-weight:bold;">@results</span>.<span style="color:#5A0A0A; font-weight:bold;">each</span> <span style="color:#9966CC; font-weight:bold;">do</span> <span style="color:#006600; font-weight:bold;">|</span>result<span style="color:#006600; font-weight:bold;">|</span> <span style="color:#006600; font-weight:bold;">%&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color:#006600; font-weight:bold;">&lt;</span>li<span style="color:#006600; font-weight:bold;">&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color:#006600; font-weight:bold;">&lt;</span> <span style="color:#006600; font-weight:bold;">%</span>= display_search_result<span style="color:#006600; font-weight:bold;">&#40;</span>result<span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#006600; font-weight:bold;">%&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color:#006600; font-weight:bold;">&lt;/</span>li<span style="color:#006600; font-weight:bold;">&gt;</span><br />
&nbsp; &nbsp; <span style="color:#006600; font-weight:bold;">&lt;</span> <span style="color:#006600; font-weight:bold;">%</span> <span style="color:#9966CC; font-weight:bold;">end</span> <span style="color:#006600; font-weight:bold;">%&gt;</span><br />
&nbsp; &nbsp; <span style="color:#006600; font-weight:bold;">&lt;/</span>ul<span style="color:#006600; font-weight:bold;">&gt;</span><br />
&nbsp; &nbsp; <span style="color:#006600; font-weight:bold;">&lt;</span>div <span style="color:#9966CC; font-weight:bold;">class</span>=<span style="color:#996600;">&quot;clear&quot;</span><span style="color:#006600; font-weight:bold;">&gt;&lt;/</span>div<span style="color:#006600; font-weight:bold;">&gt;</span><br />
<span style="color:#006600; font-weight:bold;">&lt;/</span>div<span style="color:#006600; font-weight:bold;">&gt;</span><br />
<span style="color:#006600; font-weight:bold;">&lt;</span> <span style="color:#006600; font-weight:bold;">%</span> <span style="color:#9966CC; font-weight:bold;">end</span> <span style="color:#006600; font-weight:bold;">%&gt;</span></div></div>
<p>And the view helper (<strong>app/helpers/search_helper.rb</strong>):</p>
<div class="codecolorer-container rails default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="rails codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color:#9966CC; font-weight:bold;">def</span> display_search_result<span style="color:#006600; font-weight:bold;">&#40;</span>result<span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; <span style="color:#CC0066; font-weight:bold;">eval</span> <span style="color:#996600;">&quot;render :partial =&gt; '#{result.class.to_s.downcase.pluralize}/result',<br />
&nbsp; &nbsp; :locals =&gt; { :result =&gt; result }&quot;</span><br />
<span style="color:#9966CC; font-weight:bold;">end</span></div></div>
<p>The interesting thing about this bit of code is the <strong>eval</strong>.  The <strong>eval</strong> on each iteration decides which search result partial to display based on the class and then passes the result to the partial for display.  So if the result has a class of <em>Business</em>, the partial <strong>app/views/businesses/_result.html.erb</strong> will be rendered.  This is a quick example of a search result partial:</p>
<div class="codecolorer-container rails default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="rails codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color:#006600; font-weight:bold;">&lt;</span>span id=<span style="color:#996600;">&quot;localBizName&quot;</span><span style="color:#006600; font-weight:bold;">&gt;&lt;</span> <span style="color:#006600; font-weight:bold;">%</span>= <span style="color:#5A0A0A; font-weight:bold;">link_to</span> result.<span style="color:#9900CC;">name</span>, business_path<span style="color:#006600; font-weight:bold;">&#40;</span> result <span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#006600; font-weight:bold;">%&gt;&lt;/</span>span<span style="color:#006600; font-weight:bold;">&gt;&lt;</span>br <span style="color:#006600; font-weight:bold;">/&gt;</span><br />
<span style="color:#006600; font-weight:bold;">&lt;</span><span style="color:#CC0066; font-weight:bold;">p</span> <span style="color:#9966CC; font-weight:bold;">class</span>=<span style="color:#996600;">&quot;smallOffset&quot;</span><span style="color:#006600; font-weight:bold;">&gt;&lt;</span> <span style="color:#006600; font-weight:bold;">%</span>= truncate<span style="color:#006600; font-weight:bold;">&#40;</span> <span style="color:#996600;">&quot;#{result.description}&quot;</span>, :<span style="color:#5A0A0A; font-weight:bold;">length</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006666;">128</span> <span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#006600; font-weight:bold;">%&gt;&lt;/</span>p<span style="color:#006600; font-weight:bold;">&gt;</span></div></div>
<p>This is useful because all models don&#8217;t have the same characteristics.  By creating a search result partial for each model type, this can be reused for consistent looking search results around your webapp.  If the search is model specific, the same result partial will be used in every iteration over the results.  If the search is model agnostic, then you can display your search results in a consistent manner.</p>


<p>Related posts:<ol><li><a href='http://eric.lubow.org/2010/seo/sortfix-or-a-next-generation-search-tool/' rel='bookmark' title='Sortfix Or A Next Generation Search Tool'>Sortfix Or A Next Generation Search Tool</a></li>
<li><a href='http://eric.lubow.org/2009/ruby/rails/adding-an-average-column-to-a-model/' rel='bookmark' title='Adding An Average Column To A Model'>Adding An Average Column To A Model</a></li>
<li><a href='http://eric.lubow.org/2008/databases/mysql/mysql-encoded-uri-search-and-replace/' rel='bookmark' title='MySQL Encoded URI Search and Replace'>MySQL Encoded URI Search and Replace</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://eric.lubow.org/2010/ruby/rails/model-specific-formatted-search-results-using-thinking-sphinx/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

