<?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>Miximum &#187; solr</title>
	<atom:link href="http://www.miximum.fr/tag/solr/feed" rel="self" type="application/rss+xml" />
	<link>http://www.miximum.fr</link>
	<description>Le blog d&#039;un ingénieur web freelance</description>
	<lastBuildDate>Wed, 16 Nov 2011 16:25:14 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1</generator>
		<item>
		<title>New release of tjSolrDoctrineBehaviorPlugin</title>
		<link>http://www.miximum.fr/actus/558-new-release-of-tjsolrdoctrinebehaviorplugin</link>
		<comments>http://www.miximum.fr/actus/558-new-release-of-tjsolrdoctrinebehaviorplugin#comments</comments>
		<pubDate>Mon, 03 Jan 2011 12:14:19 +0000</pubDate>
		<dc:creator>thibault</dc:creator>
				<category><![CDATA[Actus]]></category>
		<category><![CDATA[doctrine]]></category>
		<category><![CDATA[solr]]></category>
		<category><![CDATA[symfony]]></category>

		<guid isPermaLink="false">http://www.miximum.fr/?p=558</guid>
		<description><![CDATA[photo credit&#160;: &#160;&#187;grahamblackall Release an open-source software once, and you&#8217;ll be doomed to maintain it for life. This is just a quick message to let you know that I&#8217;ve released a new version of my Symfony Solr plugin&#160;: tjSolrDoctrineBehaviorPlugin. This plugin allows you to easily index and search among your doctrine objects. Wanna see the [...]]]></description>
			<content:encoded><![CDATA[<div class="postimg alignright"><a href="http://www.flickr.com/photos/13086721@N08/3268391472/" title="Mardi Gras Readers (FRONT PAGE #1)" target="_blank"><img src="http://farm4.static.flickr.com/3297/3268391472_08aee98e75_m.jpg" alt="Mardi Gras Readers (FRONT PAGE #1)" border="0" /></a><br /><small><a href="http://creativecommons.org/licenses/by-nc-nd/2.0/" title="Attribution-NonCommercial-NoDerivs License" target="_blank"><img src="http://www.miximum.fr/wp-content/plugins/photo-dropper/images/cc.png" alt="Creative Commons License" border="0" width="16" height="16" align="absmiddle" /></a> <a href="http://www.photodropper.com/photos/" target="_blank">photo</a> credit&nbsp;: <a href="http://www.flickr.com/photos/13086721@N08/3268391472/" title="&raquo;grahamblackall" target="_blank">&nbsp;&raquo;grahamblackall</a></small></div>
<p>Release an open-source software once, and you&#8217;ll be doomed to maintain it for life.</p>
<p>This is just a quick message to let you know that I&#8217;ve released a new version of my <a href="http://www.symfony-project.org/plugins/tjSolrDoctrineBehaviorPlugin">Symfony Solr plugin&nbsp;: tjSolrDoctrineBehaviorPlugin</a>.</p>
<p>This plugin allows you to easily index and search among your doctrine objects. Wanna see the changelog<span class="fine">&nbsp;</span>?</p>
<ul>
<li>I18n integration</li>
<li>Configure Solr and Jetty logging</li>
<li>Realtime indexing option</li>
<li>DataImportHandler (DIH) configuration</li>
<li>Task to rebuild index</li>
<li>Update documentation</li>
<li>Bug corrections</li>
</ul>
<p>I hope you will find it useful. Happy new year<span class="fine">&nbsp;</span>!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.miximum.fr/actus/558-new-release-of-tjsolrdoctrinebehaviorplugin/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Indexer Wikipédia dans Solr</title>
		<link>http://www.miximum.fr/methodes-et-outils/510-indexer-wikipedia-dans-solr</link>
		<comments>http://www.miximum.fr/methodes-et-outils/510-indexer-wikipedia-dans-solr#comments</comments>
		<pubDate>Mon, 25 Oct 2010 16:53:17 +0000</pubDate>
		<dc:creator>thibault</dc:creator>
				<category><![CDATA[Méthodes et outils]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[solr]]></category>
		<category><![CDATA[wikipedia]]></category>

		<guid isPermaLink="false">http://www.miximum.fr/?p=510</guid>
		<description><![CDATA[photo credit&#160;: Thibault Jouannic Dr&#244;le d&#8217;&#233;poque. Apr&#232;s deux jours magiques &#224; ParisWeb, et un retour chez moi dans une ambiance de guerre civile, le retour &#224; la r&#233;alit&#233; est&#8230; difficile. La reprise du quotidien apr&#232;s un tel &#233;v&#233;nement est toujours une p&#233;riode cafardog&#232;ne. Pour &#233;viter de sombrer dans la d&#233;prime la plus grise, je vous [...]]]></description>
			<content:encoded><![CDATA[<div class="postimg alignleft"><a href="http://www.flickr.com/photos/24469297@N05/5036470965/" title="En regardant le coucher de soleil" target="_blank"><img src="http://farm5.static.flickr.com/4147/5036470965_c9868f3e14_m.jpg" alt="En regardant le coucher de Soleil" border="0" /></a><br /><small><a href="http://creativecommons.org/licenses/by-nc-sa/2.0/" title="Attribution-NonCommercial-ShareAlike License" target="_blank"><img src="http://www.miximum.fr/wp-content/plugins/photo-dropper/images/cc.png" alt="Creative Commons License" border="0" width="16" height="16" align="absmiddle" /></a> <a href="http://www.photodropper.com/photos/" target="_blank">photo</a> credit&nbsp;: <a href="http://www.flickr.com/photos/24469297@N05/5036470965/" title="Thibault Jouannic" target="_blank">Thibault Jouannic</a></small></div>
<p>Dr&ocirc;le d&#8217;&eacute;poque. Apr&egrave;s <a href="http://ovineyards.com/english/parisweb-2010-my-tiny-brains-effort-to-summarize/">deux jours magiques &agrave; ParisWeb</a>, et un retour chez moi dans une ambiance de guerre civile, le retour &agrave; la r&eacute;alit&eacute; est&hellip; difficile.</p>
<p>La reprise du quotidien apr&egrave;s un tel &eacute;v&eacute;nement est toujours une p&eacute;riode cafardog&egrave;ne. Pour &eacute;viter de sombrer dans la d&eacute;prime la plus grise, je vous propose de nous fixer un objectif un tantinet ambitieux&nbsp;: et si nous indexions <a href="http://fr.wikipedia.org/">la plus grande base de connaissance au monde</a> dans le <a href="http://www.miximum.fr/tag/solr">meilleur moteur de recherche</a><span class="fine">&nbsp;</span>? (Si &ccedil;a ne vous plait pas, vous pouvez plut&ocirc;t <a href="http://twitter.com/#!/search/%23sudweb">vous abonner au tag #sudweb</a>.)</p>
<p>Chercher dans Wikip&eacute;dia gr&acirc;ce &agrave; Solr<span class="fine">&nbsp;</span>? Si, c&#8217;est possible.</p>
<h2>Des donn&eacute;es, des donn&eacute;es, des donn&eacute;es&hellip;</h2>
<p>Wikip&eacute;dia fournit r&eacute;guli&egrave;rement des <a href="http://download.wikimedia.org/frwiki/latest/">fichiers de dumps</a> permettant de r&eacute;cup&eacute;rer toutes les donn&eacute;es du site. Nous nous contenterons de r&eacute;cup&eacute;rer les articles complets (sans les r&eacute;visions, ni les commentaires), et en fran&ccedil;ais uniquement. Je vous m&acirc;che le travail, <a href="http://download.wikimedia.org/frwiki/latest/frwiki-latest-pages-articles.xml.bz2">il n&#8217;y a qu&#8217;un seul fichier &agrave; r&eacute;cup&eacute;rer</a>.</p>
<h2>Configurer le sch&eacute;ma</h2>
<p>La documentation de Solr fournit un <a href="http://wiki.apache.org/solr/DataImportHandler#Example:_Indexing_wikipedia">exemple de sch&eacute;ma pour indexer Wikipedia</a>. Nous allons l&#8217;optimiser pour prendre en compte la langue fran&ccedil;aise (je pars ici d&#8217;une install vierge de Solr).</p>
<p>Commen&ccedil;ons par ajouter un nouveau <em>fieldtype</em>&nbsp;: <strong>text_fr</strong>, dans le fichier schema.xml.</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;"><span class="sc3"><span class="re1">&lt;fieldtype</span> <span class="re0">name</span>=<span class="st0">&quot;text_fr&quot;</span> <span class="re0">class</span>=<span class="st0">&quot;solr.TextField&quot;</span><span class="re2">&gt;</span></span>
  <span class="sc3"><span class="re1">&lt;analyzer</span> <span class="re0">type</span>=<span class="st0">&quot;index&quot;</span><span class="re2">&gt;</span></span>
    <span class="sc3"><span class="re1">&lt;tokenizer</span> <span class="re0">class</span>=<span class="st0">&quot;solr.StandardTokenizerFactory&quot;</span><span class="re2">/&gt;</span></span>
    <span class="sc3"><span class="re1">&lt;filter</span> <span class="re0">class</span>=<span class="st0">&quot;solr.SynonymFilterFactory&quot;</span> <span class="re0">synonyms</span>=<span class="st0">&quot;synonyms_fr.txt&quot;</span> <span class="re0">ignoreCase</span>=<span class="st0">&quot;true&quot;</span> <span class="re0">expand</span>=<span class="st0">&quot;true&quot;</span><span class="re2">/&gt;</span></span>
    <span class="sc3"><span class="re1">&lt;filter</span> <span class="re0">class</span>=<span class="st0">&quot;solr.StandardFilterFactory&quot;</span><span class="re2">/&gt;</span></span>
    <span class="sc3"><span class="re1">&lt;filter</span> <span class="re0">class</span>=<span class="st0">&quot;solr.StopFilterFactory&quot;</span> <span class="re0">ignoreCase</span>=<span class="st0">&quot;true&quot;</span> <span class="re0">words</span>=<span class="st0">&quot;stopwords_fr.txt&quot;</span><span class="re2">/&gt;</span></span>
    <span class="sc3"><span class="re1">&lt;filter</span> <span class="re0">class</span>=<span class="st0">&quot;solr.WordDelimiterFilterFactory&quot;</span> <span class="re0">generateWordParts</span>=<span class="st0">&quot;1&quot;</span> <span class="re0">generateNumberParts</span>=<span class="st0">&quot;1&quot;</span> <span class="re0">catenateWords</span>=<span class="st0">&quot;1&quot;</span> <span class="re0">catenateNumbers</span>=<span class="st0">&quot;1&quot;</span> <span class="re0">catenateAll</span>=<span class="st0">&quot;0&quot;</span> <span class="re0">splitOnCaseChange</span>=</span>
<span class="sc3">    <span class="re1">&lt;filter</span> <span class="re0">class</span>=<span class="st0">&quot;solr.ISOLatin1AccentFilterFactory&quot;</span><span class="re2">/&gt;</span></span>
    <span class="sc3"><span class="re1">&lt;filter</span> <span class="re0">class</span>=<span class="st0">&quot;solr.LowerCaseFilterFactory&quot;</span><span class="re2">/&gt;</span></span>
    <span class="sc3"><span class="re1">&lt;filter</span> <span class="re0">class</span>=<span class="st0">&quot;solr.SnowballPorterFilterFactory&quot;</span> <span class="re0">language</span>=<span class="st0">&quot;French&quot;</span> <span class="re0">protected</span>=<span class="st0">&quot;protwords_fr.txt&quot;</span> <span class="re2">/&gt;</span></span>
  <span class="sc3"><span class="re1">&lt;/analyzer<span class="re2">&gt;</span></span></span>
  <span class="sc3"><span class="re1">&lt;analyzer</span> <span class="re0">type</span>=<span class="st0">&quot;query&quot;</span><span class="re2">&gt;</span></span>
    <span class="sc3"><span class="re1">&lt;tokenizer</span> <span class="re0">class</span>=<span class="st0">&quot;solr.StandardTokenizerFactory&quot;</span><span class="re2">/&gt;</span></span>
    <span class="sc3"><span class="re1">&lt;filter</span> <span class="re0">class</span>=<span class="st0">&quot;solr.SynonymFilterFactory&quot;</span> <span class="re0">synonyms</span>=<span class="st0">&quot;synonyms_fr.txt&quot;</span> <span class="re0">ignoreCase</span>=<span class="st0">&quot;true&quot;</span> <span class="re0">expand</span>=<span class="st0">&quot;true&quot;</span><span class="re2">/&gt;</span></span>
    <span class="sc3"><span class="re1">&lt;filter</span> <span class="re0">class</span>=<span class="st0">&quot;solr.StandardFilterFactory&quot;</span><span class="re2">/&gt;</span></span>
    <span class="sc3"><span class="re1">&lt;filter</span> <span class="re0">class</span>=<span class="st0">&quot;solr.StopFilterFactory&quot;</span> <span class="re0">ignoreCase</span>=<span class="st0">&quot;true&quot;</span> <span class="re0">words</span>=<span class="st0">&quot;stopwords_fr.txt&quot;</span><span class="re2">/&gt;</span></span>
    <span class="sc3"><span class="re1">&lt;filter</span> <span class="re0">class</span>=<span class="st0">&quot;solr.WordDelimiterFilterFactory&quot;</span> <span class="re0">generateWordParts</span>=<span class="st0">&quot;1&quot;</span> <span class="re0">generateNumberParts</span>=<span class="st0">&quot;1&quot;</span> <span class="re0">catenateWords</span>=<span class="st0">&quot;0&quot;</span> <span class="re0">catenateNumbers</span>=<span class="st0">&quot;0&quot;</span> <span class="re0">catenateAll</span>=<span class="st0">&quot;0&quot;</span> <span class="re0">splitOnCaseChange</span>=</span>
<span class="sc3">    <span class="re1">&lt;filter</span> <span class="re0">class</span>=<span class="st0">&quot;solr.ISOLatin1AccentFilterFactory&quot;</span><span class="re2">/&gt;</span></span>
    <span class="sc3"><span class="re1">&lt;filter</span> <span class="re0">class</span>=<span class="st0">&quot;solr.LowerCaseFilterFactory&quot;</span><span class="re2">/&gt;</span></span>
    <span class="sc3"><span class="re1">&lt;filter</span> <span class="re0">class</span>=<span class="st0">&quot;solr.SnowballPorterFilterFactory&quot;</span> <span class="re0">language</span>=<span class="st0">&quot;French&quot;</span> <span class="re0">protected</span>=<span class="st0">&quot;protwords_fr.txt&quot;</span> <span class="re2">/&gt;</span></span>
  <span class="sc3"><span class="re1">&lt;/analyzer<span class="re2">&gt;</span></span></span>
<span class="sc3"><span class="re1">&lt;/fieldtype<span class="re2">&gt;</span></span></span></pre></div></div>

<p>Vous remarquerez que ce type de champ n&eacute;cessite trois fichiers pour fonctionner.</p>
<ol>
<li><strong>synonyms_fr.txt</strong>, pour g&eacute;rer les synonymes dans l&#8217;indexation. Exemple&nbsp;:
<pre>
aiki => aikido
resto => restaurant
</pre>
</li>
<li><strong>stopwords_fr.txt</strong>, contient la liste des <a href="http://svn.apache.org/repos/asf/lucene/dev/trunk/modules/analysis/common/src/resources/org/apache/lucene/analysis/snowball/french_stop.txt">mots basiques qui ne doivent pas &ecirc;tre index&eacute;s</a>&nbsp;<span class="fine">&nbsp;</span>;</li>
<li><strong>protwords_fr.txt</strong>, contient la liste des mots qui ne doivent pas &ecirc;tre retrait&eacute;s par le <a href="http://wiki.apache.org/solr/LanguageAnalysis#French"><em>stemmer</em> fran&ccedil;ais</a>&nbsp;<span class="fine">&nbsp;</span>;</li>
</ol>
<p>Ensuite, toujours dans le m&ecirc;me fichier, configurons nos <em>fields</em>&nbsp;:</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;"><span class="sc3"><span class="re1">&lt;fields<span class="re2">&gt;</span></span></span>
  <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">name</span>=<span class="st0">&quot;id&quot;</span>        <span class="re0">type</span>=<span class="st0">&quot;string&quot;</span> <span class="re0">indexed</span>=<span class="st0">&quot;true&quot;</span> <span class="re0">stored</span>=<span class="st0">&quot;true&quot;</span> <span class="re0">required</span>=<span class="st0">&quot;true&quot;</span><span class="re2">/&gt;</span></span>
&nbsp;
  <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">name</span>=<span class="st0">&quot;title&quot;</span>     <span class="re0">type</span>=<span class="st0">&quot;string&quot;</span>     <span class="re0">indexed</span>=<span class="st0">&quot;false&quot;</span> <span class="re0">stored</span>=<span class="st0">&quot;true&quot;</span><span class="re2">/&gt;</span></span>
  <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">name</span>=<span class="st0">&quot;search_title&quot;</span>     <span class="re0">type</span>=<span class="st0">&quot;text_fr&quot;</span>     <span class="re0">indexed</span>=<span class="st0">&quot;true&quot;</span> <span class="re0">stored</span>=<span class="st0">&quot;false&quot;</span><span class="re2">/&gt;</span></span>
  <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">name</span>=<span class="st0">&quot;body&quot;</span>    <span class="re0">type</span>=<span class="st0">&quot;text_fr&quot;</span>    <span class="re0">indexed</span>=<span class="st0">&quot;true&quot;</span> <span class="re0">stored</span>=<span class="st0">&quot;true&quot;</span> <span class="re0">termVectors</span>=<span class="st0">&quot;true&quot;</span><span class="re2">/&gt;</span></span>
&nbsp;
  <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">name</span>=<span class="st0">&quot;revision&quot;</span>   <span class="re0">type</span>=<span class="st0">&quot;sint&quot;</span>    <span class="re0">indexed</span>=<span class="st0">&quot;true&quot;</span> <span class="re0">stored</span>=<span class="st0">&quot;true&quot;</span><span class="re2">/&gt;</span></span>
  <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">name</span>=<span class="st0">&quot;user&quot;</span>        <span class="re0">type</span>=<span class="st0">&quot;string&quot;</span>  <span class="re0">indexed</span>=<span class="st0">&quot;true&quot;</span> <span class="re0">stored</span>=<span class="st0">&quot;true&quot;</span><span class="re2">/&gt;</span></span>
  <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">name</span>=<span class="st0">&quot;userId&quot;</span>     <span class="re0">type</span>=<span class="st0">&quot;int&quot;</span> <span class="re0">indexed</span>=<span class="st0">&quot;true&quot;</span> <span class="re0">stored</span>=<span class="st0">&quot;true&quot;</span><span class="re2">/&gt;</span></span>
  <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">name</span>=<span class="st0">&quot;timestamp&quot;</span> <span class="re0">type</span>=<span class="st0">&quot;date&quot;</span>    <span class="re0">indexed</span>=<span class="st0">&quot;true&quot;</span> <span class="re0">stored</span>=<span class="st0">&quot;true&quot;</span><span class="re2">/&gt;</span></span>
 <span class="sc3"><span class="re1">&lt;/fields<span class="re2">&gt;</span></span></span>
&nbsp;
 <span class="sc3"><span class="re1">&lt;uniqueKey<span class="re2">&gt;</span></span></span>id<span class="sc3"><span class="re1">&lt;/uniqueKey<span class="re2">&gt;</span></span></span>
 <span class="sc3"><span class="re1">&lt;defaultSearchField<span class="re2">&gt;</span></span></span>search_title<span class="sc3"><span class="re1">&lt;/defaultSearchField<span class="re2">&gt;</span></span></span>
 <span class="sc3"><span class="re1">&lt;copyField</span> <span class="re0">source</span>=<span class="st0">&quot;title&quot;</span> <span class="re0">dest</span>=<span class="st0">&quot;search_title&quot;</span><span class="re2">/&gt;</span></span></pre></div></div>

<p>Notez que l&#8217;on stocke le corps de l&#8217;article. C&#8217;est parce que nous allons utiliser les <em>results highlighting</em>. Si vous n&#8217;avez pas besoin de cette fonctionnalit&eacute;, remplacez &laquo;&nbsp;stored=true&nbsp;&raquo; par &laquo;&nbsp;stored=false&nbsp;&raquo;.</p>
<h2>Et on importe</h2>
<p>Nous aurions pu d&eacute;cider de convertir le fichier xml de wikid&eacute;dia en sql, de l&#8217;importer dans une base, et d&#8217;utiliser un <em>sql import handler</em>. Mais pourquoi se compliquer la t&acirc;che<span class="fine">&nbsp;</span>? Solr peut importer directement du xml. Configurons notre import de donn&eacute;es dans le fichier data-config.xml&nbsp;:</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;"><span class="sc3"><span class="re1">&lt;dataConfig<span class="re2">&gt;</span></span></span>
    <span class="sc3"><span class="re1">&lt;dataSource</span> <span class="re0">type</span>=<span class="st0">&quot;FileDataSource&quot;</span> <span class="re0">encoding</span>=<span class="st0">&quot;UTF-8&quot;</span> <span class="re2">/&gt;</span></span>
    <span class="sc3"><span class="re1">&lt;document<span class="re2">&gt;</span></span></span>
    <span class="sc3"><span class="re1">&lt;entity</span> <span class="re0">name</span>=<span class="st0">&quot;page&quot;</span></span>
<span class="sc3">        <span class="re0">processor</span>=<span class="st0">&quot;XPathEntityProcessor&quot;</span></span>
<span class="sc3">        <span class="re0">stream</span>=<span class="st0">&quot;true&quot;</span></span>
<span class="sc3">        <span class="re0">forEach</span>=<span class="st0">&quot;/mediawiki/page/&quot;</span></span>
<span class="sc3">        <span class="re0">url</span>=<span class="st0">&quot;/var/www/solrdemo/dumps/frwiki-latest-pages-articles.xml&quot;</span></span>
<span class="sc3">        <span class="re0">transformer</span>=<span class="st0">&quot;RegexTransformer,DateFormatTransformer&quot;</span></span>
<span class="sc3">        <span class="re2">&gt;</span></span>
        <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">column</span>=<span class="st0">&quot;id&quot;</span>    <span class="re0">xpath</span>=<span class="st0">&quot;/mediawiki/page/id&quot;</span> <span class="re2">/&gt;</span></span>
        <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">column</span>=<span class="st0">&quot;title&quot;</span>     <span class="re0">xpath</span>=<span class="st0">&quot;/mediawiki/page/title&quot;</span> <span class="re2">/&gt;</span></span>
        <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">column</span>=<span class="st0">&quot;body&quot;</span>      <span class="re0">xpath</span>=<span class="st0">&quot;/mediawiki/page/revision/text&quot;</span> <span class="re2">/&gt;</span></span>
        <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">column</span>=<span class="st0">&quot;revision&quot;</span>  <span class="re0">xpath</span>=<span class="st0">&quot;/mediawiki/page/revision/id&quot;</span> <span class="re2">/&gt;</span></span>
        <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">column</span>=<span class="st0">&quot;user&quot;</span>      <span class="re0">xpath</span>=<span class="st0">&quot;/mediawiki/page/revision/contributor/username&quot;</span> <span class="re2">/&gt;</span></span>
        <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">column</span>=<span class="st0">&quot;userId&quot;</span>    <span class="re0">xpath</span>=<span class="st0">&quot;/mediawiki/page/revision/contributor/id&quot;</span> <span class="re2">/&gt;</span></span>
        <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">column</span>=<span class="st0">&quot;timestamp&quot;</span> <span class="re0">xpath</span>=<span class="st0">&quot;/mediawiki/page/revision/timestamp&quot;</span> <span class="re0">dateTimeFormat</span>=<span class="st0">&quot;yyyy-MM-dd'T'hh:mm:ss'Z'&quot;</span> <span class="re2">/&gt;</span></span>
        <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">column</span>=<span class="st0">&quot;$skipDoc&quot;</span>  <span class="re0">regex</span>=<span class="st0">&quot;^(?i)#redirect.*&quot;</span> <span class="re0">replaceWith</span>=<span class="st0">&quot;true&quot;</span> <span class="re0">sourceColName</span>=<span class="st0">&quot;text&quot;</span><span class="re2">/&gt;</span></span>
       <span class="sc3"><span class="re1">&lt;/entity<span class="re2">&gt;</span></span></span>
    <span class="sc3"><span class="re1">&lt;/document<span class="re2">&gt;</span></span></span>
<span class="sc3"><span class="re1">&lt;/dataConfig<span class="re2">&gt;</span></span></span></pre></div></div>

<p>Red&eacute;marrez Solr, lancez l&#8217;indexation, attendez (une heure ou deux), et paf<span class="fine">&nbsp;</span>! 2400000 document index&eacute;s, ce qui vous en conviendrez est plus que suffisant pour s&#8217;amuser.</p>
<h2>Un peu de result highlighting</h2>
<p>&Eacute;tant donn&eacute; que nous disposons d&#8217;un sacr&eacute; paquet de texte, autant en profiter un peu, non<span class="fine">&nbsp;</span>? (oui, j&#8217;ai des loisirs de geeks). Au hasard, je vous propose de mettre en place un peu de <em>result highlighting</em><sup><a href="#footnote-1-510" id="footnote-link-1-510" title="Voir la note.">[1]</a></sup> .</p>
<p>Bon, alors pour ceux qui aiment bien avoir un retour visuel, &ccedil;a pourrait ressembler &agrave; &ccedil;a&nbsp;:</p>
<div class="postimg">
<img src="http://farm2.static.flickr.com/1149/5114959190_da8ca1d01c.jpg" alt="D&eacute;mo Result highlighting" />
</div>
<p>Pour ce faire, nous allons <a href="http://wiki.apache.org/solr/HighlightingParameters">utiliser les param&egrave;tres qui vont bien</a>, et que je vous propose ci-dessous sous forme de tableau php (et tant pis pour les pythoneux, faudra s&#8217;en contenter<sup><a href="#footnote-2-510" id="footnote-link-2-510" title="Voir la note.">[2]</a></sup> ).</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;"><span class="re0">$req</span> <span class="sy0">=</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span>
  <span class="st_h">'q'</span> <span class="sy0">=&gt;</span> <span class="st_h">'Ma recherche'</span><span class="sy0">,</span>
  <span class="st_h">'qt'</span> <span class="sy0">=&gt;</span> <span class="st_h">'dismax'</span><span class="sy0">,</span> <span class="co1">// Nous envoyons directement le contenu du formulaire à Solr, par conséquent dismax est plus adapté</span>
  <span class="st_h">'qf'</span> <span class="sy0">=&gt;</span> <span class="st_h">'title^2 body'</span><span class="sy0">,</span> <span class="co1">// On cherche dans title et body, avec une priorité plus importante pour le champ title</span>
  <span class="st_h">'hl'</span> <span class="sy0">=&gt;</span> <span class="st_h">'true'</span><span class="sy0">,</span> <span class="co1">// Activitation de l'highlighting</span>
  <span class="st_h">'hl.fl'</span> <span class="sy0">=&gt;</span> <span class="st_h">'title,body'</span><span class="sy0">,</span>  <span class="co1">// Seuls ces champs seront pris en compte pour la surbrillance</span>
  <span class="st_h">'f.body.hl.alternateField'</span> <span class="sy0">=&gt;</span> <span class="st_h">'body'</span><span class="sy0">,</span>  <span class="co1">// Si aucun snippet n'est trouvé dans le champ body, on renvoie le champ complet</span>
  <span class="st_h">'hl.fragsize'</span> <span class="sy0">=&gt;</span> <span class="nu0">150</span><span class="sy0">,</span>  <span class="co1">// Les snippets font 150 caractères…</span>
  <span class="st_h">'hl.snippets'</span> <span class="sy0">=&gt;</span> <span class="nu0">3</span><span class="sy0">,</span>  <span class="co1">// … et on renvoie 3 snippets maxi </span>
  <span class="st_h">'hl.maxAlternateFieldLength'</span> <span class="sy0">=&gt;</span> <span class="nu0">200</span><span class="sy0">,</span>  <span class="co1">// Si on renvoie le champ body comple, on limite à 200 caractères</span>
  <span class="st_h">'hl.simple.pre'</span> <span class="sy0">=&gt;</span> <span class="st_h">'&lt;strong&gt;'</span><span class="sy0">,</span>  <span class="co1">// On veut que notre surbrillance soit encadrée par des balises 'strong'</span>
  <span class="st_h">'hl.simple.post'</span> <span class="sy0">=&gt;</span> <span class="st_h">'&lt;/strong&gt;'</span><span class="sy0">,</span>
<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span></pre></div></div>

<p>Si vous ex&eacute;cutez une requ&ecirc;te contenant ces param&egrave;tres, vous noterez que la r&eacute;ponse est s&eacute;par&eacute;e en deux parties&nbsp;: d&#8217;un c&ocirc;t&eacute;, les r&eacute;sultats, et de l&#8217;autre, les <em>snippets</em> g&eacute;n&eacute;r&eacute;s. Vous remarquerez &eacute;galement que les snippets en question sont a peu pr&egrave;s illisibles &agrave; l&#8217;&oelig;il nu, mais &ccedil;a, c&#8217;est une autre histoire.</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;"><span class="sc3"><span class="re1">&lt;?xml</span> <span class="re0">version</span>=<span class="st0">&quot;1.0&quot;</span> <span class="re0">encoding</span>=<span class="st0">&quot;UTF-8&quot;</span><span class="re2">?&gt;</span></span>
<span class="sc3"><span class="re1">&lt;response<span class="re2">&gt;</span></span></span>
<span class="sc3"><span class="re1">&lt;responseHeader<span class="re2">&gt;</span></span></span>
  <span class="sc3"><span class="re1">&lt;bla<span class="re2">&gt;</span></span></span>bla<span class="sc3"><span class="re1">&lt;/bla<span class="re2">&gt;</span></span></span>
<span class="sc3"><span class="re1">&lt;/responseHeader<span class="re2">&gt;</span></span></span>
<span class="sc3"><span class="re1">&lt;result</span> <span class="re0">name</span>=<span class="st0">&quot;response&quot;</span> <span class="re0">numFound</span>=<span class="st0">&quot;50&quot;</span> <span class="re0">start</span>=<span class="st0">&quot;0&quot;</span><span class="re2">&gt;</span></span>
  <span class="sc3"><span class="re1">&lt;doc<span class="re2">&gt;</span></span></span>
    <span class="sc3"><span class="re1">&lt;str</span> <span class="re0">name</span>=<span class="st0">&quot;id&quot;</span><span class="re2">&gt;</span></span>9<span class="sc3"><span class="re1">&lt;/str<span class="re2">&gt;</span></span></span>
    <span class="sc3"><span class="re1">&lt;int</span> <span class="re0">name</span>=<span class="st0">&quot;revision&quot;</span><span class="re2">&gt;</span></span>2338009<span class="sc3"><span class="re1">&lt;/int<span class="re2">&gt;</span></span></span>
    <span class="sc3"><span class="re1">&lt;date</span> <span class="re0">name</span>=<span class="st0">&quot;timestamp&quot;</span><span class="re2">&gt;</span></span>2002-10-31T09:16:01Z<span class="sc3"><span class="re1">&lt;/date<span class="re2">&gt;</span></span></span>
    <span class="sc3"><span class="re1">&lt;str</span> <span class="re0">name</span>=<span class="st0">&quot;title&quot;</span><span class="re2">&gt;</span></span>Algèbre de boole<span class="sc3"><span class="re1">&lt;/str<span class="re2">&gt;</span></span></span>
  <span class="sc3"><span class="re1">&lt;/doc<span class="re2">&gt;</span></span></span>
…
<span class="sc3"><span class="re1">&lt;/result<span class="re2">&gt;</span></span></span>
<span class="sc3"><span class="re1">&lt;lst</span> <span class="re0">name</span>=<span class="st0">&quot;highlighting&quot;</span><span class="re2">&gt;</span></span>
  <span class="sc3"><span class="re1">&lt;lst</span> <span class="re0">name</span>=<span class="st0">&quot;9&quot;</span><span class="re2">&gt;</span></span>
    <span class="sc3"><span class="re1">&lt;arr</span> <span class="re0">name</span>=<span class="st0">&quot;body&quot;</span><span class="re2">&gt;</span></span>
      <span class="sc3"><span class="re1">&lt;str<span class="re2">&gt;</span></span></span>
L' <span class="sc1">&amp;lt;</span>em<span class="sc1">&amp;gt;</span>alg<span class="sc1">&amp;amp;</span>#232;bre<span class="sc1">&amp;lt;</span>/em<span class="sc1">&amp;gt;</span> g<span class="sc1">&amp;amp;</span>#233;n<span class="sc1">&amp;amp;</span>#233;rale, ou <span class="sc1">&amp;lt;</span>em<span class="sc1">&amp;gt;</span>alg<span class="sc1">&amp;amp;</span>#232;bre<span class="sc1">&amp;lt;</span>/em<span class="sc1">&amp;gt;</span> abstraite, est la branche des math<span class="sc1">&amp;amp;</span>#233;matiques qui porte principalement sur l'<span class="sc1">&amp;amp;</span>#233;tude des structures <span class="sc1">&amp;lt;</span>em<span class="sc1">&amp;gt;</span>alg<span class="sc1">&amp;amp;</span>#233;briques<span class="sc1">&amp;lt;</span>/em<span class="sc1">&amp;gt;</span> et de leurs relations. L'appellation <span class="sc1">&amp;lt;</span>em<span class="sc1">&amp;gt;</span>alg<span class="sc1">&amp;amp;</span>#232;bre<span class="sc1">&amp;lt;</span>/em<span class="sc1">&amp;gt;</span> g<span class="sc1">&amp;amp;</span>#233;n<span class="sc1">&amp;amp;</span>#233;rale s'oppose <span class="sc1">&amp;amp;</span>#224; celle dalg<span class="sc1">&amp;amp;</span>#232;bre <span class="sc1">&amp;amp;</span>#233;l<span class="sc1">&amp;amp;</span>#233;mentaire ; cette derni<span class="sc1">&amp;amp;</span>#232;re enseigne le calcul <span class="sc1">&amp;lt;</span>em<span class="sc1">&amp;gt;</span>alg<span class="sc1">&amp;amp;</span>#233;brique<span class="sc1">&amp;lt;</span>/em<span class="sc1">&amp;gt;</span>, c'est-<span class="sc1">&amp;amp;</span>#224;-dire les r<span class="sc1">&amp;amp;</span>#232;gles de manipulation des formules et des expressions <span class="sc1">&amp;lt;</span>em<span class="sc1">&amp;gt;</span>alg<span class="sc1">&amp;amp;</span>#233;briques<span class="sc1">&amp;lt;</span>/em<span class="sc1">&amp;gt;</span>.Historiquement, les structures <span class="sc1">&amp;lt;</span>em<span class="sc1">&amp;gt;</span>alg<span class="sc1">&amp;amp;</span>#233;briques<span class="sc1">&amp;lt;</span>/em<span class="sc1">&amp;gt;</span> sont apparues dans diff<span class="sc1">&amp;amp;</span>#233;rents<span class="sc3"><span class="re1">&lt;/str<span class="re2">&gt;</span></span></span>
    <span class="sc3"><span class="re1">&lt;/arr<span class="re2">&gt;</span></span></span>
  <span class="sc3"><span class="re1">&lt;/lst<span class="re2">&gt;</span></span></span>
…</pre></div></div>

<p>Parser la r&eacute;ponse sera finalement assez simple. Allez, je vous donne le code que j&#8217;utilise (pour les curieux, <a href="http://www.twig-project.org/">c&#8217;est du twig</a>, mais ce serait pareil avec n&#8217;importe quel autre moteur de template).</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;"><span class="sc3"><span class="re1">&lt;section</span> <span class="re0">id</span>=<span class="st0">&quot;results&quot;</span><span class="re2">&gt;</span></span>
  {% block results %}
    <span class="sc3"><span class="re1">&lt;h3<span class="re2">&gt;</span></span></span>{{ results.numFound }} résultats trouvés<span class="sc3"><span class="re1">&lt;/h3<span class="re2">&gt;</span></span></span>
    <span class="sc3"><span class="re1">&lt;ol<span class="re2">&gt;</span></span></span>
    {% for doc in results.docs %}
      {% block doc %}
        <span class="sc3"><span class="re1">&lt;li<span class="re2">&gt;</span></span></span>
          <span class="sc3"><span class="re1">&lt;a</span> <span class="re0">href</span>=<span class="st0">&quot;http://fr.wikipedia.org/wiki/{{ doc.title }}&quot;</span> <span class="re2">/&gt;</span></span>{{ doc.title }}<span class="sc3"><span class="re1">&lt;/a<span class="re2">&gt;</span></span></span>
          <span class="sc3"><span class="re1">&lt;p<span class="re2">&gt;</span></span></span>
          {% for snippet in highlighting[doc.id].body %}
            {{ snippet }}…
          {% endfor %}
          <span class="sc3"><span class="re1">&lt;/p<span class="re2">&gt;</span></span></span>
        <span class="sc3"><span class="re1">&lt;/li<span class="re2">&gt;</span></span></span>
      {% endblock %}
    {% endfor %}
    <span class="sc3"><span class="re1">&lt;/ol<span class="re2">&gt;</span></span></span>
  {% endblock %}
<span class="sc3"><span class="re1">&lt;/section<span class="re2">&gt;</span></span></span>
{% endif %}
<span class="sc3"><span class="re1">&lt;/section<span class="re2">&gt;</span></span></span></pre></div></div>

<h2>Mais&hellip; Mais&hellip; Attendez<span class="fine">&nbsp;</span>! C&#8217;est tout crade<span class="fine">&nbsp;</span>!</h2>
<p>Ok, j&#8217;avoue, si vous avez vous m&ecirc;me test&eacute; tout &ccedil;a jusqu&#8217;ici, vous avez remarqu&eacute; que le r&eacute;sultat n&#8217;est pas vraiment exploitable. Le texte que nous indexons, en effet, n&#8217;est pas du texte brut&nbsp;: il contient toutes les balises de formattage sp&eacute;cifiques du langage wiki de Wikip&eacute;dia.</p>
<p>Dans notre cas, nous n&#8217;aurons jamais besoin de ces informations aussi l&#8217;id&eacute;al serait de pouvoir filtrer ces balises d&eacute;s l&#8217;import des donn&eacute;es.</p>
<p>Si vous aussi, vous lisez la documentation de Solr en famille le soir au coin du feu<sup><a href="#footnote-3-510" id="footnote-link-3-510" title="Voir la note.">[3]</a></sup>, vous savez d&eacute;j&agrave; que <a href="http://wiki.apache.org/solr/DataImportHandler#Transformer">Solr propose des <em>transformers</em></a> (rien &agrave; voir avec les robots), qui permettent de filtrer les donn&eacute;es lors de l&#8217;import.</p>
<p>D&#8217;ailleurs, si vous regardez le code du fichier <em>data-config.xml</em> que nous avons utilis&eacute;, il utilise d&eacute;j&agrave; deux <em>transformers</em>. Tout ce que nous allons faire, c&#8217;est cr&eacute;er notre <em>transformer custom</em>. Allez hop<span class="fine">&nbsp;</span>! Un peu de java<span class="fine">&nbsp;</span>! Cr&eacute;ez un fichier WikiTransformer.java</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;"><span class="kw1">import</span> <span class="co2">java.util.*</span><span class="sy0">;</span>
<span class="kw1">import</span> <span class="co2">java.io.*</span><span class="sy0">;</span>
<span class="kw1">import</span> <span class="co2">info.bliki.wiki.filter.PlainTextConverter</span><span class="sy0">;</span>
<span class="kw1">import</span> <span class="co2">info.bliki.wiki.model.WikiModel</span><span class="sy0">;</span>
&nbsp;
<span class="kw1">public</span> <span class="kw1">class</span> WikiTransformerAlt <span class="br0">&#123;</span>
  <span class="kw1">public</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Aobject+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">Object</span></a> transformRow<span class="br0">&#40;</span>Map<span class="sy0">&lt;</span>String, Object<span class="sy0">&gt;</span> row<span class="br0">&#41;</span> <span class="br0">&#123;</span>
    <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">String</span></a> body <span class="sy0">=</span> <span class="br0">&#40;</span><a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">String</span></a><span class="br0">&#41;</span>row.<span class="me1">get</span><span class="br0">&#40;</span><span class="st0">&quot;body&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
    <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astringwriter+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">StringWriter</span></a> writer <span class="sy0">=</span> <span class="kw1">new</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astringwriter+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">StringWriter</span></a><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
    WikiModel wikiModel <span class="sy0">=</span> <span class="kw1">new</span> WikiModel<span class="br0">&#40;</span><span class="st0">&quot;http://www.mywiki.com/wiki/${image}&quot;</span>, <span class="st0">&quot;http://www.mywiki.com/wiki/${title}&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">String</span></a> plainStr <span class="sy0">=</span> wikiModel.<span class="me1">render</span><span class="br0">&#40;</span><span class="kw1">new</span> PlainTextConverter<span class="br0">&#40;</span><span class="br0">&#41;</span>, body<span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
    row.<span class="me1">put</span><span class="br0">&#40;</span><span class="st0">&quot;body&quot;</span>, plainStr<span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
    <span class="kw1">return</span> row<span class="sy0">;</span>
  <span class="br0">&#125;</span>
<span class="br0">&#125;</span></pre></div></div>

<p>Deux choses &agrave; noter&nbsp;: ce transformer n&#8217;est pas optimal, le nom du champ &agrave; parser (body) est cod&eacute; en dur. Mais bon, &ccedil;a ira pour cette fois (mais ne recommencez pas). Deuxi&egrave;me chose, j&#8217;utilise la <a href="http://code.google.com/p/gwtwiki/">librairie java gwtwiki</a> pour faire le boulot de traduction wiki -> texte brut. Cette librairie est pour le moment lacunaire (ou alors je m&#8217;en sert mal), et le r&eacute;sultat ne sera pas parfait. Il faudra faire avec.</p>
<p>La compilation du fichier en .jar et son installation sortent du scope de cet article, aussi je vous laisse utiliser votre moteur de recherche favori&hellip; Bon, ok, je vous file les commandes&nbsp;:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;">javac <span class="re5">-cp</span> <span class="st0">&quot;/path/vers/bliki/info.bliki.wiki/bliki-core/target/*&quot;</span> WikiTransformer.java
jar <span class="re5">-cf</span> WikiTransformer.jar WikiTransformer.class
<span class="kw2">cp</span> WikiTransformer.jar path<span class="sy0">/</span>vers<span class="sy0">/</span>solr<span class="sy0">/</span>work<span class="sy0">/</span>Jetty_0_0_0_0_8983_solr.war__solr__k1kf17<span class="sy0">/</span>webapp<span class="sy0">/</span>WEB-INF<span class="sy0">/</span>lib<span class="sy0">/</span></pre></div></div>

<p>Notez le chemin de destination pas tr&eacute;s conventionnel&nbsp;: c&#8217;est le seul endroit ou l&#8217;autoload semble capter le jar. Si un expert java passe par l&agrave; et peut m&#8217;expliquer&hellip;</p>
<p>Il ne nous reste plus qu&#8217;&agrave; mettre &agrave; jour notre fichier de configuration d&#8217;import, et &agrave; relancer l&#8217;indexation&nbsp;:</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;"><span class="sc3"><span class="re1">&lt;dataConfig<span class="re2">&gt;</span></span></span>
    <span class="sc3"><span class="re1">&lt;dataSource</span> <span class="re0">type</span>=<span class="st0">&quot;FileDataSource&quot;</span> <span class="re0">encoding</span>=<span class="st0">&quot;UTF-8&quot;</span> <span class="re2">/&gt;</span></span>
    <span class="sc3"><span class="re1">&lt;document<span class="re2">&gt;</span></span></span>
    <span class="sc3"><span class="re1">&lt;entity</span> <span class="re0">name</span>=<span class="st0">&quot;page&quot;</span></span>
<span class="sc3">        <span class="re0">processor</span>=<span class="st0">&quot;XPathEntityProcessor&quot;</span></span>
<span class="sc3">        <span class="re0">stream</span>=<span class="st0">&quot;true&quot;</span></span>
<span class="sc3">        <span class="re0">forEach</span>=<span class="st0">&quot;/mediawiki/page/&quot;</span></span>
<span class="sc3">        <span class="re0">url</span>=<span class="st0">&quot;/var/www/solrdemo/dumps/frwiki-latest-pages-articles.xml&quot;</span></span>
<span class="sc3">        <span class="re0">transformer</span>=<span class="st0">&quot;RegexTransformer,DateFormatTransformer,WikiTransformer&quot;</span></span>
<span class="sc3">        <span class="re2">&gt;</span></span>
        <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">column</span>=<span class="st0">&quot;id&quot;</span>    <span class="re0">xpath</span>=<span class="st0">&quot;/mediawiki/page/id&quot;</span> <span class="re2">/&gt;</span></span>
        <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">column</span>=<span class="st0">&quot;title&quot;</span>     <span class="re0">xpath</span>=<span class="st0">&quot;/mediawiki/page/title&quot;</span> <span class="re2">/&gt;</span></span>
        <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">column</span>=<span class="st0">&quot;body&quot;</span>      <span class="re0">xpath</span>=<span class="st0">&quot;/mediawiki/page/revision/text&quot;</span> <span class="re2">/&gt;</span></span>
        <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">column</span>=<span class="st0">&quot;revision&quot;</span>  <span class="re0">xpath</span>=<span class="st0">&quot;/mediawiki/page/revision/id&quot;</span> <span class="re2">/&gt;</span></span>
        <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">column</span>=<span class="st0">&quot;user&quot;</span>      <span class="re0">xpath</span>=<span class="st0">&quot;/mediawiki/page/revision/contributor/username&quot;</span> <span class="re2">/&gt;</span></span>
        <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">column</span>=<span class="st0">&quot;userId&quot;</span>    <span class="re0">xpath</span>=<span class="st0">&quot;/mediawiki/page/revision/contributor/id&quot;</span> <span class="re2">/&gt;</span></span>
        <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">column</span>=<span class="st0">&quot;timestamp&quot;</span> <span class="re0">xpath</span>=<span class="st0">&quot;/mediawiki/page/revision/timestamp&quot;</span> <span class="re0">dateTimeFormat</span>=<span class="st0">&quot;yyyy-MM-dd'T'hh:mm:ss'Z'&quot;</span> <span class="re2">/&gt;</span></span>
        <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">column</span>=<span class="st0">&quot;$skipDoc&quot;</span>  <span class="re0">regex</span>=<span class="st0">&quot;^(?i)#redirect.*&quot;</span> <span class="re0">replaceWith</span>=<span class="st0">&quot;true&quot;</span> <span class="re0">sourceColName</span>=<span class="st0">&quot;body&quot;</span><span class="re2">/&gt;</span></span>
       <span class="sc3"><span class="re1">&lt;/entity<span class="re2">&gt;</span></span></span>
    <span class="sc3"><span class="re1">&lt;/document<span class="re2">&gt;</span></span></span>
<span class="sc3"><span class="re1">&lt;/dataConfig<span class="re2">&gt;</span></span></span></pre></div></div>

<p>Et voil&agrave;, vous disposez de votre propre moteur de recherche Wikipedia. Les raffinements possibles sont nombreux, je laisse votre imagination vous guider. En attendant, rendez-vous au prochain SudWeb.</p>
<h4>Notes&nbsp;:</h4><ol class="footnotes"><li id="footnote-1-510"> Pour les francophones acharn&eacute;s, <em>surbrillance des r&eacute;sultats</em>, mais c&#8217;est moche   [<a href="#footnote-link-1-510">retour</a>]</li><li id="footnote-2-510">Notez comme s&#8217;ext&eacute;riorise ma haine et ma jalousie envers les gens qui ont la chance de travailler avec un vrai langage de programmation  [<a href="#footnote-link-2-510">retour</a>]</li><li id="footnote-3-510">Allez, avouez, je sais que vous le faites  [<a href="#footnote-link-3-510">retour</a>]</li></ol>]]></content:encoded>
			<wfw:commentRss>http://www.miximum.fr/methodes-et-outils/510-indexer-wikipedia-dans-solr/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Autocomplete avec Solr</title>
		<link>http://www.miximum.fr/methodes-et-outils/499-autocomplete-avec-solr</link>
		<comments>http://www.miximum.fr/methodes-et-outils/499-autocomplete-avec-solr#comments</comments>
		<pubDate>Mon, 27 Sep 2010 13:22:17 +0000</pubDate>
		<dc:creator>thibault</dc:creator>
				<category><![CDATA[Méthodes et outils]]></category>
		<category><![CDATA[autocomplete]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[jquery]]></category>
		<category><![CDATA[solr]]></category>

		<guid isPermaLink="false">http://www.miximum.fr/?p=499</guid>
		<description><![CDATA[photo credit&#160;: Thibault Jouannic Voil&#224; la reprise, les premiers froids, les feuilles qui tombent, la nostalgie des vacances, etc. Mais la rentr&#233;e est &#233;galement pour moi l&#8217;opportunit&#233; de d&#233;poussi&#233;rer un peu mon cerveau et ce blog, avec du temps consacr&#233; &#224; l&#8217;indispensable&#8230; Veille techno. Parce que la veille, c&#8217;est comme le sport. Quand on ne [...]]]></description>
			<content:encoded><![CDATA[<div class="postimg alignright"><a href="http://www.flickr.com/photos/24469297@N05/5005748830/" title="Purple sunset in Ko Tao" target="_blank"><img src="http://farm5.static.flickr.com/4113/5005748830_ccfd81aa54_m.jpg" alt="Purple sunset in Ko Tao" border="0" /></a><br /><small><a href="http://creativecommons.org/licenses/by-nc-nd/2.0/" title="Attribution-NonCommercial-NoDerivs License" target="_blank"><img src="http://www.miximum.fr/wp-content/plugins/photo-dropper/images/cc.png" alt="Creative Commons License" border="0" width="16" height="16" align="absmiddle" /></a> <a href="http://www.photodropper.com/photos/" target="_blank">photo</a> credit&nbsp;: <a href="http://www.flickr.com/photos/24469297@N05/" title="Thibault Jouannic Photo" target="_blank">Thibault Jouannic</a></small></div>
<p>Voil&agrave; la reprise, les premiers froids, les feuilles qui tombent, la nostalgie des vacances, etc. Mais la rentr&eacute;e est &eacute;galement pour moi l&#8217;opportunit&eacute; de d&eacute;poussi&eacute;rer un peu mon cerveau et ce blog, avec du temps consacr&eacute; &agrave; l&#8217;indispensable&hellip; Veille techno. Parce que la veille, c&#8217;est comme le sport. Quand on ne pratique pas, on s&#8217;encrasse vite. <a href="http://thibault.jouannic.fr" title="D&eacute;veloppeur web freelance">Surtout quand on est freelance</a>.</p>
<p>Bref, dans cet article, nous allons utiliser <a href="http://www.miximum.fr/tag/solr" title="Solr, search engine">Solr, excellent moteur de recherche</a> dont je vous ai d&eacute;j&agrave; parl&eacute;, et impl&eacute;menter <strong>l&#8217;autocompl&eacute;tion de la recherche</strong>.</p>
<h2>Solr pour l&#8217;autocompl&eacute;tion, ou sortir la Grosse Bertha pour tuer une mite</h2>
<p>Les plus attentifs d&#8217;entre vous se demanderont sans doute pourquoi utiliser Solr, puissant moteur de recherche full-text en java, pour une b&ecirc;te autocompl&eacute;tion. Et effectivement, l&#8217;outil serait disproportionn&eacute; si nous n&#8217;&eacute;tions pas dans un des cas suivants&nbsp;:</p>
<ol>
<li>Vous utilisez d&eacute;j&agrave; Solr pour votre moteur de recherche. Dans ce cas, l&#8217;utiliser pour l&#8217;autocompl&eacute;tion ne rajoutera pas une grosse charge&nbsp;<span class="fine">&nbsp;</span>;</li>
<li>Vous souhaitez mettre en place une autocompl&eacute;tion un peu avanc&eacute;e, avec s&eacute;paration par facettes, etc&nbsp;<span class="fine">&nbsp;</span>;</li>
</ol>
<p>Solr, depuis la version 1.4, propose un <a href="http://wiki.apache.org/solr/TermsComponent">nouveau module de recherche&nbsp;: Terms Component</a>. Alors que Solr est g&eacute;n&eacute;ralement utilis&eacute; pour effectuer des recherches au niveau d&#8217;un document, ce module permet d&#8217;acc&eacute;der au infos au niveau des termes pr&eacute;sents dans les champs, permettant de r&eacute;pondre &agrave; la requ&ecirc;te&nbsp;: &laquo;&nbsp;Quels sont les termes pr&eacute;sent dans tel(s) champ(s), et &agrave; combien de document correspondent-ils<span class="fine">&nbsp;</span>?&nbsp;&raquo;.</p>
<p>Par ailleurs, notez que nous allons cr&eacute;er une autocompl&eacute;tion, et pas une autosuggestion. Pour bien cerner la diff&eacute;rence, je vous recommande la lecture de cet <a href="http://blog.twigkit.com/search-suggestions-part-1/">excellent article sur les diff&eacute;rents types d&#8217;assistance &agrave; la recherche</a>.</p>
<div class="postimg alignleft"><a href="http://www.flickr.com/photos/24469297@N05/5029647182/" title="autocomplete by teeboo2734, on Flickr"><img src="http://farm5.static.flickr.com/4110/5029647182_b6d21d67f0_m.jpg" width="196" height="240" alt="autocomplete" /></a></div>
<p>Pour &ecirc;tre pr&eacute;cis, nous allons construire &ccedil;a. Ceux qui lisent via un lecteur rss et qui n&#8217;auraient pas l&#8217;image, vous n&#8217;avez qu&#8217;&agrave; aller sur le site.</p>
<p>Pour les autres, vous remarquerez un b&ecirc;te champ de recherche tout ce qu&#8217;il y a de plus classique. L&#8217;autocompl&eacute;tion, en revanche, est un tantinet &eacute;volu&eacute;e, puisqu&#8217;elle s&#8217;effectue sur deux champs diff&eacute;rents. Vous &ecirc;tes pr&ecirc;ts<span class="fine">&nbsp;</span>? C&#8217;est parti<span class="fine">&nbsp;</span>!</p>
<h2>Choisir les bons outils</h2>
<p>&Agrave; l&#8217;heure ou j&#8217;&eacute;cris, la version stable de Solr est la 1.4.1. Elle pr&eacute;sente toutefois un bug dans le formatage json des r&eacute;sultats. Nous utiliserons donc Solr dans sa version nightly build.</p>
<p>L&#8217;autocomplete sera assur&eacute; par <a href="http://jquery.com/">jQuery, librairie javascript que l&#8217;on ne pr&eacute;sente plus</a>, et par son tr&eacute;s bon compl&eacute;ment <a href="http://jqueryui.com/demos/autocomplete/">jQuery UI</a>.</p>
<p>Notez l&#8217;existance d&#8217;une tr&eacute;s compl&egrave;te (mais assez complexe) <a href="http://github.com/evolvingweb/ajax-solr">librairie ajax pour Solr</a>. Elle constitue pratiquement un framework &agrave; elle toute seule, et pour le coup, nous la laisserons de c&ocirc;t&eacute;.</p>
<h2>Le code<span class="fine">&nbsp;</span>! Le code<span class="fine">&nbsp;</span>!</h2>
<p>Commen&ccedil;ons par le HTML. Ici, rien que du classique.</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;"><span class="sc0">&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Transitional//EN&quot; &quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&quot;&gt;</span>
<span class="sc3"><span class="re1">&lt;html</span> <span class="re0">xmlns</span>=<span class="st0">&quot;http://www.w3.org/1999/xhtml&quot;</span> <span class="re0">xml:lang</span>=<span class="st0">&quot;fr&quot;</span><span class="re2">&gt;</span></span>
  <span class="sc3"><span class="re1">&lt;head<span class="re2">&gt;</span></span></span>
    <span class="sc3"><span class="re1">&lt;script</span> <span class="re0">type</span>=<span class="st0">&quot;text/javascript&quot;</span> <span class="re0">src</span>=<span class="st0">&quot;./js/jquery-1.4.2.min.js&quot;</span><span class="re2">&gt;</span><span class="re1">&lt;/script<span class="re2">&gt;</span></span></span>
    <span class="sc3"><span class="re1">&lt;script</span> <span class="re0">type</span>=<span class="st0">&quot;text/javascript&quot;</span> <span class="re0">src</span>=<span class="st0">&quot;./js/jquery-ui-1.8.5.custom.min.js&quot;</span><span class="re2">&gt;</span><span class="re1">&lt;/script<span class="re2">&gt;</span></span></span>
    <span class="sc3"><span class="re1">&lt;script</span> <span class="re0">type</span>=<span class="st0">&quot;text/javascript&quot;</span> <span class="re0">src</span>=<span class="st0">&quot;./js/solr.js&quot;</span><span class="re2">&gt;</span><span class="re1">&lt;/script<span class="re2">&gt;</span></span></span>
&nbsp;
    <span class="sc3"><span class="re1">&lt;link</span> <span class="re0">rel</span>=<span class="st0">&quot;stylesheet&quot;</span> <span class="re0">type</span>=<span class="st0">&quot;text/css&quot;</span> <span class="re0">media</span>=<span class="st0">&quot;screen&quot;</span> <span class="re0">href</span>=<span class="st0">&quot;./css/ui-lightness/jquery-ui-1.8.5.custom.css&quot;</span> <span class="re2">/&gt;</span></span>
&nbsp;
  <span class="sc3"><span class="re1">&lt;/head<span class="re2">&gt;</span></span></span>
  <span class="sc3"><span class="re1">&lt;body<span class="re2">&gt;</span></span></span>
    <span class="sc3"><span class="re1">&lt;form</span> <span class="re0">action</span>=<span class="st0">&quot;&quot;</span> <span class="re0">method</span>=<span class="st0">&quot;get&quot;</span><span class="re2">&gt;</span></span>
      <span class="sc3"><span class="re1">&lt;input</span> <span class="re0">type</span>=<span class="st0">&quot;text&quot;</span> <span class="re0">id</span>=<span class="st0">&quot;search&quot;</span> <span class="re0">name</span>=<span class="st0">&quot;q&quot;</span> <span class="re2">/&gt;</span></span>
      <span class="sc3"><span class="re1">&lt;input</span> <span class="re0">type</span>=<span class="st0">&quot;submit&quot;</span> <span class="re0">value</span>=<span class="st0">&quot;Search&quot;</span> <span class="re2">/&gt;</span></span>
    <span class="sc3"><span class="re1">&lt;/form<span class="re2">&gt;</span></span></span>
&nbsp;
    <span class="sc3"><span class="re1">&lt;div</span> <span class="re0">id</span>=<span class="st0">&quot;result&quot;</span><span class="re2">&gt;</span></span>
      <span class="sc3"><span class="re1">&lt;p<span class="re2">&gt;</span></span></span>Results go here<span class="sc3"><span class="re1">&lt;/p<span class="re2">&gt;</span></span></span>
    <span class="sc3"><span class="re1">&lt;/div<span class="re2">&gt;</span></span></span>
  <span class="sc3"><span class="re1">&lt;/body<span class="re2">&gt;</span></span></span>
<span class="sc3"><span class="re1">&lt;/html<span class="re2">&gt;</span></span></span></pre></div></div>

<p>Un banal champ texte, l&#8217;inclusion des scripts n&eacute;cessaires, et c&#8217;est tout. Circulez, ya rien &agrave; voir<span class="fine">&nbsp;</span>!</p>
<p>La configuration Solr n&#8217;est pas tr&eacute;s int&eacute;ressante non plus. J&#8217;ai pris la premi&egrave;re install de Solr qui m&#8217;est pass&eacute;e sous la main. Vous pouvez vous r&eacute;ferer au schema.xml d&#8217;un pr&eacute;c&eacute;dent article.</p>
<p>Le seul fichier vraiment int&eacute;ressant est le javascript&nbsp;:</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;">$<span class="br0">&#40;</span>document<span class="br0">&#41;</span>.<span class="me1">ready</span><span class="br0">&#40;</span><span class="kw2">function</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
  $<span class="br0">&#40;</span><span class="st0">'#search'</span><span class="br0">&#41;</span>.<span class="me1">autocomplete</span><span class="br0">&#40;</span><span class="br0">&#123;</span>
    source<span class="sy0">:</span> <span class="kw2">function</span><span class="br0">&#40;</span>request<span class="sy0">,</span> response<span class="br0">&#41;</span> <span class="br0">&#123;</span>
      $.<span class="me1">ajax</span><span class="br0">&#40;</span><span class="br0">&#123;</span>
        url<span class="sy0">:</span> <span class="st0">'http://localhost:8983/solr/terms?terms.fl=name'</span><span class="sy0">,</span>
        dataType<span class="sy0">:</span> <span class="st0">'jsonp'</span><span class="sy0">,</span>
        data<span class="sy0">:</span> <span class="br0">&#123;</span>
          wt<span class="sy0">:</span> <span class="st0">'json'</span><span class="sy0">,</span>
          <span class="st0">'json.nl'</span><span class="sy0">:</span> <span class="st0">'arrarr'</span><span class="sy0">,</span>
          <span class="st0">'terms.prefix'</span><span class="sy0">:</span> request.<span class="me1">term</span><span class="sy0">,</span>
          <span class="st0">'terms.sort'</span><span class="sy0">:</span> <span class="st0">'index'</span><span class="sy0">,</span>
          <span class="st0">'terms.limit'</span><span class="sy0">:</span> <span class="nu0">5</span><span class="sy0">,</span>
          omitHeader<span class="sy0">:</span> <span class="st0">'true'</span>
        <span class="br0">&#125;</span><span class="sy0">,</span>
        jsonp<span class="sy0">:</span> <span class="st0">'json.wrf'</span><span class="sy0">,</span>
        success<span class="sy0">:</span> <span class="kw2">function</span><span class="br0">&#40;</span>data<span class="br0">&#41;</span> <span class="br0">&#123;</span>
          response<span class="br0">&#40;</span>$.<span class="me1">map</span><span class="br0">&#40;</span>data.<span class="me1">terms</span>.<span class="kw3">name</span><span class="sy0">,</span> <span class="kw2">function</span><span class="br0">&#40;</span><span class="kw1">item</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
            <span class="kw1">return</span> <span class="br0">&#123;</span>
              label<span class="sy0">:</span> <span class="kw1">item</span><span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span> <span class="sy0">+</span> <span class="st0">' ('</span> <span class="sy0">+</span> <span class="kw1">item</span><span class="br0">&#91;</span><span class="nu0">1</span><span class="br0">&#93;</span> <span class="sy0">+</span> <span class="st0">')'</span><span class="sy0">,</span>
              value<span class="sy0">:</span> <span class="kw1">item</span><span class="br0">&#91;</span><span class="nu0">1</span><span class="br0">&#93;</span>
            <span class="br0">&#125;</span><span class="sy0">;</span>
          <span class="br0">&#125;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
        <span class="br0">&#125;</span>
      <span class="br0">&#125;</span><span class="br0">&#41;</span>
    <span class="br0">&#125;</span>
  <span class="br0">&#125;</span><span class="br0">&#41;</span><span class="sy0">;</span>
<span class="br0">&#125;</span><span class="br0">&#41;</span><span class="sy0">;</span></pre></div></div>

<p>Quelques explications. Dans l&#8217;url utilis&eacute;e par le widget d&#8217;autocompl&eacute;tion, <em>terms.fl</em> d&eacute;signe le champ qui sera utilis&eacute; pour la requ&ecirc;te (ici&nbsp;: &laquo;&nbsp;name&nbsp;&raquo;).</p>
<p>Notez les options &laquo;&nbsp;datatype&nbsp;: jsonp&nbsp;&raquo;, &laquo;&nbsp;wt&nbsp;: json&nbsp;&raquo;, &laquo;&nbsp;json.nl&nbsp;: arrarr&nbsp;&raquo;, &laquo;&nbsp;jsonp&nbsp;: wrf&nbsp;&raquo;. Elles permettent de faire fonctionner l&#8217;appel ajax en cross-domain (via jsonp au lieur de json), et d&#8217;obtenir un formatage correct du r&eacute;sultat de la part de Solr.</p>
<p>Enfin, dans le callback &laquo;&nbsp;result&nbsp;&raquo;, nous formattons le r&eacute;sultat en utilisant la <a href="http://api.jquery.com/jQuery.map"/>fonction $.map de jquery</a>.</p>
<p>Nous avons maintenant un widget de recherche qui r&eacute;alise une autocompl&eacute;tion sur le champ &laquo;&nbsp;name&nbsp;&raquo;. C&#8217;est pas mal, mais nous souhaitions une autocompl&eacute;tion &agrave; facette sur diff&eacute;rents champs.</p>
<h2>L&#8217;autocompl&eacute;tion &agrave; facette</h2>
<p>Pour ce faire, nous allons modifier deux choses. D&#8217;abord, il va falloir d&eacute;finir un template de widget sp&eacute;cifique pour afficher le champ recherch&eacute;. Ensuite, la fonction qui parse le r&eacute;sultat renvoy&eacute; par Solr va devoir prendre en compte les diff&eacute;rents champs.</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;">$<span class="br0">&#40;</span>document<span class="br0">&#41;</span>.<span class="me1">ready</span><span class="br0">&#40;</span><span class="kw2">function</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp;
  <span class="co1">// Widget autocomplete spécifique</span>
  <span class="co1">// cf. http://jqueryui.com/demos/autocomplete/#categories</span>
  $.<span class="me1">widget</span><span class="br0">&#40;</span> <span class="st0">&quot;custom.catcomplete&quot;</span><span class="sy0">,</span> $.<span class="me1">ui</span>.<span class="me1">autocomplete</span><span class="sy0">,</span> <span class="br0">&#123;</span>
    _renderMenu<span class="sy0">:</span> <span class="kw2">function</span><span class="br0">&#40;</span> ul<span class="sy0">,</span> items <span class="br0">&#41;</span> <span class="br0">&#123;</span>
      <span class="kw2">var</span> self <span class="sy0">=</span> <span class="kw1">this</span><span class="sy0">,</span>
        currentCategory <span class="sy0">=</span> <span class="st0">&quot;&quot;</span><span class="sy0">;</span>
      $.<span class="me1">each</span><span class="br0">&#40;</span> items<span class="sy0">,</span> <span class="kw2">function</span><span class="br0">&#40;</span> index<span class="sy0">,</span> <span class="kw1">item</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span>
        <span class="kw1">if</span> <span class="br0">&#40;</span> <span class="kw1">item</span>.<span class="me1">category</span> <span class="sy0">!=</span> currentCategory <span class="br0">&#41;</span> <span class="br0">&#123;</span>
          ul.<span class="me1">append</span><span class="br0">&#40;</span> <span class="st0">&quot;&lt;li class='ui-autocomplete-category'&gt;&quot;</span> <span class="sy0">+</span> <span class="kw1">item</span>.<span class="me1">category</span> <span class="sy0">+</span> <span class="st0">&quot;&lt;/li&gt;&quot;</span> <span class="br0">&#41;</span><span class="sy0">;</span>
          currentCategory <span class="sy0">=</span> <span class="kw1">item</span>.<span class="me1">category</span><span class="sy0">;</span>
        <span class="br0">&#125;</span>
        self._renderItem<span class="br0">&#40;</span> ul<span class="sy0">,</span> <span class="kw1">item</span> <span class="br0">&#41;</span><span class="sy0">;</span>
      <span class="br0">&#125;</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="br0">&#125;</span>
  <span class="br0">&#125;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
  $<span class="br0">&#40;</span><span class="st0">'#search'</span><span class="br0">&#41;</span>.<span class="me1">catcomplete</span><span class="br0">&#40;</span><span class="br0">&#123;</span>
    source<span class="sy0">:</span> <span class="kw2">function</span><span class="br0">&#40;</span>request<span class="sy0">,</span> response<span class="br0">&#41;</span> <span class="br0">&#123;</span>
      $.<span class="me1">ajax</span><span class="br0">&#40;</span><span class="br0">&#123;</span>
        url<span class="sy0">:</span> <span class="st0">'http://localhost:8983/solr/terms?terms.fl=name&amp;terms.fl=tag_fr'</span><span class="sy0">,</span>
        dataType<span class="sy0">:</span> <span class="st0">'jsonp'</span><span class="sy0">,</span>
        data<span class="sy0">:</span> <span class="br0">&#123;</span>
          wt<span class="sy0">:</span> <span class="st0">'json'</span><span class="sy0">,</span>
          <span class="st0">'json.nl'</span><span class="sy0">:</span> <span class="st0">'arrarr'</span><span class="sy0">,</span>
          <span class="st0">'terms.prefix'</span><span class="sy0">:</span> request.<span class="me1">term</span><span class="sy0">,</span>
          <span class="st0">'terms.sort'</span><span class="sy0">:</span> <span class="st0">'index'</span><span class="sy0">,</span>
          <span class="st0">'terms.limit'</span><span class="sy0">:</span> <span class="nu0">5</span><span class="sy0">,</span>
          omitHeader<span class="sy0">:</span> <span class="st0">'true'</span>
        <span class="br0">&#125;</span><span class="sy0">,</span>
        jsonp<span class="sy0">:</span> <span class="st0">'json.wrf'</span><span class="sy0">,</span>
        success<span class="sy0">:</span> <span class="kw2">function</span><span class="br0">&#40;</span>data<span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp;
          answer <span class="sy0">=</span> <span class="kw2">new</span> Array<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
          $.<span class="me1">each</span><span class="br0">&#40;</span>data.<span class="me1">terms</span><span class="sy0">,</span> <span class="kw2">function</span><span class="br0">&#40;</span>facet<span class="sy0">,</span> terms<span class="br0">&#41;</span> <span class="br0">&#123;</span>
            answer <span class="sy0">=</span> answer.<span class="me1">concat</span><span class="br0">&#40;</span>$.<span class="me1">map</span><span class="br0">&#40;</span>terms<span class="sy0">,</span> <span class="kw2">function</span><span class="br0">&#40;</span><span class="kw1">item</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
              <span class="kw1">return</span> <span class="br0">&#123;</span>
                label<span class="sy0">:</span> <span class="kw1">item</span><span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span> <span class="sy0">+</span> <span class="st0">' ('</span> <span class="sy0">+</span> <span class="kw1">item</span><span class="br0">&#91;</span><span class="nu0">1</span><span class="br0">&#93;</span> <span class="sy0">+</span> <span class="st0">')'</span><span class="sy0">,</span>
                value<span class="sy0">:</span> <span class="kw1">item</span><span class="br0">&#91;</span><span class="nu0">1</span><span class="br0">&#93;</span><span class="sy0">,</span>
                category<span class="sy0">:</span> facet
              <span class="br0">&#125;</span><span class="sy0">;</span>
            <span class="br0">&#125;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
          <span class="br0">&#125;</span><span class="br0">&#41;</span><span class="sy0">;</span>
          response<span class="br0">&#40;</span>answer<span class="br0">&#41;</span><span class="sy0">;</span>
        <span class="br0">&#125;</span>
      <span class="br0">&#125;</span><span class="br0">&#41;</span>
    <span class="br0">&#125;</span>
  <span class="br0">&#125;</span><span class="br0">&#41;</span><span class="sy0">;</span>
<span class="br0">&#125;</span><span class="br0">&#41;</span><span class="sy0">;</span></pre></div></div>

<p>Notez l&#8217;url utilis&eacute;e dans le widget autocomplete&nbsp;: il y a maintenant deux options &laquo;&nbsp;terms.fl&nbsp;&raquo;, mais il pourrait y en avoir beaucoup plus.</p>
<p>La fonction d&#8217;analyse des r&eacute;sultats est un peu plus complexe. Pour chaque champ renvoy&eacute; par solr, elle construit un tableau de termes, en y adjoignant la cat&eacute;gorie, c&#8217;est &agrave; dire le champ courant. Tous les tableaux sont ensuite concat&eacute;n&eacute;s, en renvoy&eacute;s en r&eacute;ponse.</p>
<p>La cat&eacute;gorie est utilis&eacute;e par le template de rendu du widget, pour &ecirc;tre affich&eacute;e dans le menu d&#8217;autocompl&eacute;tion.</p>
<p>Dans nos styles, il faudra ajouter ceci&nbsp;:</p>

<div class="wp_syntax"><div class="code"><pre class="css" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;"><span class="re1">.ui-autocomplete-category</span> <span class="br0">&#123;</span>
  <span class="kw1">font-weight</span><span class="sy0">:</span> <span class="kw2">bold</span><span class="sy0">;</span>
  <span class="kw1">padding</span><span class="sy0">:</span> <span class="re3">.2em</span> <span class="re3">.4em</span><span class="sy0">;</span>
  <span class="kw1">margin</span><span class="sy0">:</span> <span class="re3">.8em</span> <span class="nu0">0</span> <span class="re3">.2em</span><span class="sy0">;</span>
  <span class="kw1">line-height</span><span class="sy0">:</span> <span class="nu0">1.5</span><span class="sy0">;</span>
<span class="br0">&#125;</span></pre></div></div>

<p>Et voil&agrave;<span class="fine">&nbsp;</span>! Un widget d&#8217;autocompl&eacute;tion un poil moins que basique. Partant de cette base, je vous laisse imaginer les am&eacute;liorations les plus raffin&eacute;es. Si vous avez des id&eacute;es de d&eacute;mo, je suis preneur.</p>
<p>&#8211; Edit &#8211;</p>
<p>J&#8217;ai oubli&eacute; de mentionner le probl&egrave;me de la s&eacute;curit&eacute;. Bien entendu, c&#8217;est une tr&eacute;s mauvaise id&eacute;e de laisser Solr en acc&egrave;s libre depuis l&#8217;ext&eacute;rieur. Donc ou bien vous cr&eacute;ez un proxy, ou bien vous cr&eacute;ez un <em>requesthandler</em> sp&eacute;cifique en lecture seule. C&#8217;est tout.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.miximum.fr/methodes-et-outils/499-autocomplete-avec-solr/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Naissance d&#8217;un plugin Solr pour Symfony</title>
		<link>http://www.miximum.fr/actus/413-naissance-dun-plugin-solr-pour-symfony</link>
		<comments>http://www.miximum.fr/actus/413-naissance-dun-plugin-solr-pour-symfony#comments</comments>
		<pubDate>Wed, 30 Dec 2009 16:05:13 +0000</pubDate>
		<dc:creator>thibault</dc:creator>
				<category><![CDATA[Actus]]></category>
		<category><![CDATA[doctrine]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[solr]]></category>
		<category><![CDATA[symfony]]></category>

		<guid isPermaLink="false">http://www.miximum.fr/?p=413</guid>
		<description><![CDATA[photo credit&#160;: B Tal Salut la compagnie. Ce billet (vraissemblablement le dernier de l&#8217;ann&#233;e) est destin&#233; &#224; faire passer une annonce (et aussi &#224; ramener un peu de traffic, j&#8217;avoue). Si vous n&#8217;&#234;tes pas abonn&#233; &#224; mon twitter, vous ne savez peut-&#234;tre pas encore que je viens de l&#226;cher dans la nature un nouveau plugin [...]]]></description>
			<content:encoded><![CDATA[<div class="postimg alignleft"><a href="http://www.flickr.com/photos/68634595@N00/116220689/" title="Our Direction" target="_blank"><img src="http://farm1.static.flickr.com/36/116220689_438039ddb3_m.jpg" alt="Our Direction" border="0" /></a><br /><small><a href="http://creativecommons.org/licenses/by-nc/2.0/" title="Attribution-NonCommercial License" target="_blank"><img src="http://www.miximum.fr/wp-content/plugins/photo-dropper/images/cc.png" alt="Creative Commons License" border="0" width="16" height="16" align="absmiddle" /></a> <a href="http://www.photodropper.com/photos/" target="_blank">photo</a> credit&nbsp;: <a href="http://www.flickr.com/photos/68634595@N00/116220689/" title="B Tal" target="_blank">B Tal</a></small></div>
<p>Salut la compagnie. Ce billet (vraissemblablement le dernier de l&#8217;ann&eacute;e) est destin&eacute; &agrave; faire passer une annonce (et aussi &agrave; ramener un peu de traffic, j&#8217;avoue).</p>
<p>Si vous n&#8217;&ecirc;tes pas <a href="http://twitter.com/thibaultj">abonn&eacute; &agrave; mon twitter</a>, vous ne savez peut-&ecirc;tre pas encore que je viens de l&acirc;cher dans la nature un <a href="http://www.symfony-project.org/plugins/tjSolrDoctrineBehaviorPlugin">nouveau plugin pour Symfony, qui porte le doux nom de <strong>tjSolrDoctrineBehaviorPlugin</strong></a>.</p>
<p>Ce plugin, comme son nom l&#8217;indique, permet de coupler tr&eacute;s simplement le <a href="http://www.symfony-project.org">framework Symfony</a> et le <a href="http://www.symfony-project.org/plugins/tjSolrDoctrineBehaviorPlugin">moteur de recherche Solr</a>. Ainsi, vous pouvez b&eacute;n&eacute;ficier dans vos projets Symfony d&#8217;un moteur de recherche au top, m&ecirc;me si vous n&#8217;&ecirc;tes pas familier avec Solr.</p>
<p>Il s&#8217;agit d&#8217;une version beta, ce qui signifie que je suis preneur de toutes remarques ou commentaires sur le sujet. Je n&#8217;en dit pas plus, la <a href="http://www.symfony-project.org/plugins/tjSolrDoctrineBehaviorPlugin/0_9_0?tab=plugin_readme">documentation du plugin</a> est suffisamment d&eacute;taill&eacute;e comme &ccedil;a.</p>
<p>C&#8217;est tout. Je m&#8217;en vais maintenant prendre un repos bien m&eacute;rit&eacute;, et d&eacute;guster de d&eacute;licieux chaussons aux pommes maison (tout le monde s&#8217;en fout, mais j&#8217;aime bien qu&#8217;on sache que j&#8217;appr&eacute;cie mes vacances).</p>
<p>Bonnes f&ecirc;tes &agrave; tous.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.miximum.fr/actus/413-naissance-dun-plugin-solr-pour-symfony/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Recherche à facette sous Solr</title>
		<link>http://www.miximum.fr/tutos/347-recherche-a-facette-sous-solr</link>
		<comments>http://www.miximum.fr/tutos/347-recherche-a-facette-sous-solr#comments</comments>
		<pubDate>Sun, 06 Dec 2009 13:16:53 +0000</pubDate>
		<dc:creator>thibault</dc:creator>
				<category><![CDATA[Tutos]]></category>
		<category><![CDATA[solr]]></category>

		<guid isPermaLink="false">http://www.miximum.fr/?p=347</guid>
		<description><![CDATA[photo credit&#160;: Joseph Robertson Aujourd&#8217;hui, je vous propose de poursuivre nos articles sur les technologies de moteur de recherche avec un nouveau tutoriel pour Solr. Au menu&#160;: comment mettre en place une recherche &#224; facette. Avec pour d&#233;marrer un rappel du principe de la recherche &#224; facette, et ensuite, la config de Solr proprement dite. [...]]]></description>
			<content:encoded><![CDATA[<div class="postimg alignleft"><a href="http://www.flickr.com/photos/50502690@N00/94646890/" title="" target="_blank"><img src="http://farm1.static.flickr.com/40/94646890_8d9f71f9ee_m.jpg" alt="" border="0" /></a><br /><small><a href="http://creativecommons.org/licenses/by-nc-sa/2.0/" title="Attribution-NonCommercial-ShareAlike License" target="_blank"><img src="http://www.miximum.fr/wp-content/plugins/photo-dropper/images/cc.png" alt="Creative Commons License" border="0" width="16" height="16" align="absmiddle" /></a> <a href="http://www.photodropper.com/photos/" target="_blank">photo</a> credit&nbsp;: <a href="http://www.flickr.com/photos/50502690@N00/94646890/" title="Joseph Robertson" target="_blank">Joseph Robertson</a></small></div>
<p>Aujourd&#8217;hui, je vous propose de poursuivre nos articles sur les <a href="http://www.miximum.fr/tag/solr">technologies de moteur de recherche</a> avec un nouveau tutoriel pour Solr. Au menu&nbsp;: comment mettre en place une <strong>recherche &agrave; facette</strong>. Avec pour d&eacute;marrer un rappel du principe de la recherche &agrave; facette, et ensuite, la config de Solr proprement dite.</p>
<h2>Facette<span class="fine">&nbsp;</span>? K&eacute;sako<span class="fine">&nbsp;</span>?</h2>
<p>Commen&ccedil;ons par un petit rappel historique (&ccedil;a donne un c&ocirc;t&eacute; intellectuel &agrave; l&#8217;article)&nbsp;: dans la br&egrave;ve mais fulgurante histoire du web, deux paradigmes de recherche se sont principalement impos&eacute;s&nbsp;:</p>
<ol>
<li>D&#8217;abord, la <strong>recherche navigationnelle dans une taxonomie</strong><sup><a href="#footnote-1-347" id="footnote-link-1-347" title="Voir la note.">[1]</a></sup> (ex&nbsp;: Dmoz). Le principe est simple&nbsp;: on pr&eacute;sente &agrave; l&#8217;internaute l&#8217;int&eacute;gralit&eacute; du contenu disponible, tri&eacute; par cat&eacute;gories, sous-cat&eacute;gories, sous-sous-cat&eacute;gories, etc. et dans lequel il devra naviguer jusqu&#8217;&agrave; trouver ce qui l&#8217;int&eacute;resse.</p>
<p>Ce mod&egrave;le n&#8217;est plus qu&#8217;occasionnellement utilis&eacute;, car une simple recherche de contenu peut parfois se transformer en v&eacute;ritable exp&eacute;dition sp&eacute;l&eacute;ologique, apte &agrave; d&eacute;courager m&ecirc;me les plus t&eacute;m&eacute;raires.
</li>
<li>Ensuite naquit la <strong>recherche directe par requ&ecirc;tes sous formes de mots-cl&eacute;s</strong>, qui prit son essort lorsque le Dieu Google d&eacute;montra qu&#8217;il &eacute;tait possible de la mettre en place &agrave; l&#8217;&eacute;chelle du web entier. Simple, direct, id&eacute;ale pour l&#8217;internaute press&eacute; qui sait ce qu&#8217;il veut.</li>
</ol>
<p>Chaque m&eacute;thode pr&eacute;sente ses avantages et des inconv&eacute;nients. La recherche par facette vise &agrave; <strong>combiner le meilleur des deux mondes</strong>. Elle offre &agrave; l&#8217;utilisateur la possibilit&eacute; d&#8217;affiner une recherche directe en navigant dans une liste de crit&egrave;res contextuels et ind&eacute;pendants.</p>
<p>Un petit dessin vaut mieux qu&#8217;un long discours, voici un mini-mockup (r&eacute;alis&eacute; gr&acirc;ce &agrave; <a href="http://www.evolus.vn/Pencil/Screenshots.html">l&#8217;excellent Pencil</a>) qui vous permettra de vous faire une id&eacute;e d&#8217;un coup d&#8217;&oelig;il.</p>
<div class="postimg">
<img src="http://farm4.static.flickr.com/3522/3970936589_3b0f217baa.jpg" alt="interface solr recherche &agrave; facette" class="aligncenter"/></p>
<ol>
<li>&laquo;&nbsp;&Eacute;cran&nbsp;&raquo; repr&eacute;sente une facette de recherche.</li>
<li>&laquo;&nbsp;Bureautique&nbsp;&raquo; est un crit&egrave;re qui permet d&#8217;appliquer une contrainte pour une facette particuli&egrave;re.</li>
<li>Le &laquo;&nbsp;15&nbsp;&raquo; &agrave; c&ocirc;t&eacute; du crit&egrave;re &laquo;&nbsp;500Go&nbsp;&raquo; indique combien de r&eacute;sultats correspondent &agrave; cette contrainte particuli&egrave;re.</li>
<li>Le fil d&#8217;ariane permet d&#8217;afficher les contraintes d&eacute;j&agrave; appliqu&eacute;es, et de les supprimer.</li>
</ol>
</div>
<p>Le principe est simple&nbsp;: une <strong>zone de texte pour les requ&ecirc;tes directes</strong>, et en fonction des r&eacute;sultats renvoy&eacute;s, on pr&eacute;sentera &agrave; l&#8217;internaute diff&eacute;rents crit&egrave;res, organis&eacute;s par facettes, qui lui permettront de <strong>raffiner sa recherche en appliquant des contraintes</strong> sur les r&eacute;sultats.</p>
<p>Bon, je r&eacute;sume un peu, mais il existe <a href="http://mondeca.wordpress.com/2007/10/07/les-taxonomies-de-navigation-la-recherche-a-facettes-definition-utilisation-objectifs-mise-en-oeuvre/">de tr&eacute;s bonnes ressources pour se renseigner sur le principe des recherches &agrave; facettes</a>.</p>
<p>Maintenant que la th&eacute;orie est derri&egrave;re nous, laissons place &agrave; la pratique.</p>
<h2>Configurer Solr</h2>
<p>Pour l&#8217;exemple, comme je n&#8217;ai pas envie de travailler sur le sempiternel site de e-commerce, nous allons refondre le moteur du site du c&eacute;l&egrave;bre (mais pas tr&eacute;s beau) marmiton.org. Notre moteur renverra donc des recettes en guise de r&eacute;sultats.</p>
<div class="postimg alignright">
<img src="http://farm4.static.flickr.com/3478/3970977037_af012a7327_o.png" alt="criteres de recherche chez dell" title="Choix de crit&egrave;res de recherche malheureux chez Dell" />
</div>
<p>La premi&egrave;re &eacute;tape est de d&eacute;cider des crit&egrave;res de recherche que nous allons mettre en place. Ne faites pas comme chez Dell, choisissez-les avec parcimonie, sous peine de voir l&#8217;exp&eacute;rience utilisateur se d&eacute;grader rapidement.</p>
<p>Voici les crit&egrave;res de recherche que nous allons mettre en place&nbsp;:</p>
<table>
<thead>
<tr>
<td>Crit&egrave;re</td>
<td>Valeurs</td>
</tr>
</thead>
<tbody>
<tr>
<td>Repas</td>
<td>Petit-d&eacute;jeuner, d&eacute;jeuner, diner, go&ucirc;ter, diner</td>
</tr>
<tr>
<td>Plat</td>
<td>Entr&eacute;e, ap&eacute;ritif, plat principal, dessert, sauce</td>
</tr>
<tr>
<td>Difficult&eacute;</td>
<td>D&eacute;butant, confirm&eacute;, expert</td>
</tr>
<tr>
<td>Budget</td>
<td>1&euro;-5&euro;, 5&euro;-10&euro;, 10&euro;-15&euro;, 15&euro;+</td>
</tr>
<tr>
<td>Saison</td>
<td>Printemps, &eacute;t&eacute;, automne, hiver</td>
</tr>
</tbody>
</table>
<p>Ces crit&egrave;res vont d&eacute;finir la mani&egrave;re dont nous allons indexer nos donn&eacute;es. Voici la portion int&eacute;ressante du <em>schema.xml</em> correspondant.</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;">  <span class="sc3"><span class="re1">&lt;field<span class="re2">&gt;</span></span></span>
   <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">name</span>=<span class="st0">&quot;id&quot;</span> <span class="re0">type</span>=<span class="st0">&quot;string&quot;</span> <span class="re0">indexed</span>=<span class="st0">&quot;true&quot;</span> <span class="re0">stored</span>=<span class="st0">&quot;true&quot;</span> <span class="re0">required</span>=<span class="st0">&quot;true&quot;</span> <span class="re2">/&gt;</span></span> 
   <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">name</span>=<span class="st0">&quot;nom&quot;</span> <span class="re0">type</span>=<span class="st0">&quot;text&quot;</span> <span class="re0">indexed</span>=<span class="st0">&quot;true&quot;</span> <span class="re0">stored</span>=<span class="st0">&quot;true&quot;</span> <span class="re0">required</span>=<span class="st0">&quot;true&quot;</span> <span class="re2">/&gt;</span></span> 
   <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">name</span>=<span class="st0">&quot;repas&quot;</span> <span class="re0">type</span>=<span class="st0">&quot;string&quot;</span> <span class="re0">indexed</span>=<span class="st0">&quot;true&quot;</span> <span class="re0">stored</span>=<span class="st0">&quot;false&quot;</span><span class="re2">/&gt;</span></span>
   <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">name</span>=<span class="st0">&quot;plat&quot;</span> <span class="re0">type</span>=<span class="st0">&quot;string&quot;</span> <span class="re0">indexed</span>=<span class="st0">&quot;true&quot;</span> <span class="re0">stored</span>=<span class="st0">&quot;false&quot;</span><span class="re2">/&gt;</span></span>
   <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">name</span>=<span class="st0">&quot;difficulte&quot;</span> <span class="re0">type</span>=<span class="st0">&quot;string&quot;</span> <span class="re0">indexed</span>=<span class="st0">&quot;true&quot;</span> <span class="re0">stored</span>=<span class="st0">&quot;false&quot;</span><span class="re2">/&gt;</span></span>
   <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">name</span>=<span class="st0">&quot;prix&quot;</span> <span class="re0">type</span>=<span class="st0">&quot;sfloat&quot;</span> <span class="re0">indexed</span>=<span class="st0">&quot;true&quot;</span> <span class="re0">stored</span>=<span class="st0">&quot;false&quot;</span><span class="re2">/&gt;</span></span>
   <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">name</span>=<span class="st0">&quot;saison&quot;</span> <span class="re0">type</span>=<span class="st0">&quot;string&quot;</span> <span class="re0">indexed</span>=<span class="st0">&quot;true&quot;</span> <span class="re0">stored</span>=<span class="st0">&quot;false&quot;</span><span class="re2">/&gt;</span></span>
  <span class="sc3"><span class="re1">&lt;/field<span class="re2">&gt;</span></span></span></pre></div></div>

<p>Vous remarquerez la d&eacute;plorable optimisation des noms et des types des champs, ainsi que l&#8217;excessive simplification de la d&eacute;finition du sch&eacute;ma. Cela dit, on s&#8217;en fout, c&#8217;est juste pour la d&eacute;mo.</p>
<p>Pour les fain&eacute;ants, voici &eacute;galement quelques donn&eacute;es de tests &agrave; inclure directement.</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;"><span class="sc3"><span class="re1">&lt;add<span class="re2">&gt;</span></span></span>
    <span class="sc3"><span class="re1">&lt;doc<span class="re2">&gt;</span></span></span>
        <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">name</span>=<span class="st0">&quot;id&quot;</span><span class="re2">&gt;</span></span>1<span class="sc3"><span class="re1">&lt;/field<span class="re2">&gt;</span></span></span>
        <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">name</span>=<span class="st0">&quot;nom&quot;</span><span class="re2">&gt;</span></span>Soufflé aux crevettes<span class="sc3"><span class="re1">&lt;/field<span class="re2">&gt;</span></span></span>
        <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">name</span>=<span class="st0">&quot;repas&quot;</span><span class="re2">&gt;</span></span>Dîner<span class="sc3"><span class="re1">&lt;/field<span class="re2">&gt;</span></span></span>
        <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">name</span>=<span class="st0">&quot;plat&quot;</span><span class="re2">&gt;</span></span>Plat principal<span class="sc3"><span class="re1">&lt;/field<span class="re2">&gt;</span></span></span>
        <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">name</span>=<span class="st0">&quot;difficulte&quot;</span><span class="re2">&gt;</span></span>Expérimenté<span class="sc3"><span class="re1">&lt;/field<span class="re2">&gt;</span></span></span>
        <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">name</span>=<span class="st0">&quot;prix&quot;</span><span class="re2">&gt;</span></span>5<span class="sc3"><span class="re1">&lt;/field<span class="re2">&gt;</span></span></span>
        <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">name</span>=<span class="st0">&quot;saison&quot;</span><span class="re2">&gt;</span></span>Automne<span class="sc3"><span class="re1">&lt;/field<span class="re2">&gt;</span></span></span>
        <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">name</span>=<span class="st0">&quot;created_at_dt&quot;</span><span class="re2">&gt;</span></span>2009-01-02T00:00:00.000Z<span class="sc3"><span class="re1">&lt;/field<span class="re2">&gt;</span></span></span>
    <span class="sc3"><span class="re1">&lt;/doc<span class="re2">&gt;</span></span></span>
    <span class="sc3"><span class="re1">&lt;doc<span class="re2">&gt;</span></span></span>
        <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">name</span>=<span class="st0">&quot;id&quot;</span><span class="re2">&gt;</span></span>2<span class="sc3"><span class="re1">&lt;/field<span class="re2">&gt;</span></span></span>
        <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">name</span>=<span class="st0">&quot;nom&quot;</span><span class="re2">&gt;</span></span>Charlottes aux groseilles<span class="sc3"><span class="re1">&lt;/field<span class="re2">&gt;</span></span></span>
        <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">name</span>=<span class="st0">&quot;repas&quot;</span><span class="re2">&gt;</span></span>Déjeuner<span class="sc3"><span class="re1">&lt;/field<span class="re2">&gt;</span></span></span>
        <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">name</span>=<span class="st0">&quot;plat&quot;</span><span class="re2">&gt;</span></span>Dessert<span class="sc3"><span class="re1">&lt;/field<span class="re2">&gt;</span></span></span>
        <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">name</span>=<span class="st0">&quot;difficulte&quot;</span><span class="re2">&gt;</span></span>Débutant<span class="sc3"><span class="re1">&lt;/field<span class="re2">&gt;</span></span></span>
        <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">name</span>=<span class="st0">&quot;prix&quot;</span><span class="re2">&gt;</span></span>7<span class="sc3"><span class="re1">&lt;/field<span class="re2">&gt;</span></span></span>
        <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">name</span>=<span class="st0">&quot;saison&quot;</span><span class="re2">&gt;</span></span>Été<span class="sc3"><span class="re1">&lt;/field<span class="re2">&gt;</span></span></span>
        <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">name</span>=<span class="st0">&quot;created_at_dt&quot;</span><span class="re2">&gt;</span></span>2009-01-05T00:00:00.000Z<span class="sc3"><span class="re1">&lt;/field<span class="re2">&gt;</span></span></span>
    <span class="sc3"><span class="re1">&lt;/doc<span class="re2">&gt;</span></span></span>
    <span class="sc3"><span class="re1">&lt;doc<span class="re2">&gt;</span></span></span>
        <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">name</span>=<span class="st0">&quot;id&quot;</span><span class="re2">&gt;</span></span>3<span class="sc3"><span class="re1">&lt;/field<span class="re2">&gt;</span></span></span>
        <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">name</span>=<span class="st0">&quot;nom&quot;</span><span class="re2">&gt;</span></span>Gloubigoulba<span class="sc3"><span class="re1">&lt;/field<span class="re2">&gt;</span></span></span>
        <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">name</span>=<span class="st0">&quot;repas&quot;</span><span class="re2">&gt;</span></span>Petit-déjeuner<span class="sc3"><span class="re1">&lt;/field<span class="re2">&gt;</span></span></span>
        <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">name</span>=<span class="st0">&quot;plat&quot;</span><span class="re2">&gt;</span></span>Plat principal<span class="sc3"><span class="re1">&lt;/field<span class="re2">&gt;</span></span></span>
        <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">name</span>=<span class="st0">&quot;difficulte&quot;</span><span class="re2">&gt;</span></span>Astronomique<span class="sc3"><span class="re1">&lt;/field<span class="re2">&gt;</span></span></span>
        <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">name</span>=<span class="st0">&quot;prix&quot;</span><span class="re2">&gt;</span></span>23492<span class="sc3"><span class="re1">&lt;/field<span class="re2">&gt;</span></span></span>
        <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">name</span>=<span class="st0">&quot;saison&quot;</span><span class="re2">&gt;</span></span>Hiver<span class="sc3"><span class="re1">&lt;/field<span class="re2">&gt;</span></span></span>
        <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">name</span>=<span class="st0">&quot;created_at_dt&quot;</span><span class="re2">&gt;</span></span>2009-02-02T00:00:00.000Z<span class="sc3"><span class="re1">&lt;/field<span class="re2">&gt;</span></span></span>
    <span class="sc3"><span class="re1">&lt;/doc<span class="re2">&gt;</span></span></span>
    <span class="sc3"><span class="re1">&lt;doc<span class="re2">&gt;</span></span></span>
        <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">name</span>=<span class="st0">&quot;id&quot;</span><span class="re2">&gt;</span></span>4<span class="sc3"><span class="re1">&lt;/field<span class="re2">&gt;</span></span></span>
        <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">name</span>=<span class="st0">&quot;nom&quot;</span><span class="re2">&gt;</span></span>Soupe à la grimace<span class="sc3"><span class="re1">&lt;/field<span class="re2">&gt;</span></span></span>
        <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">name</span>=<span class="st0">&quot;repas&quot;</span><span class="re2">&gt;</span></span>Dîner<span class="sc3"><span class="re1">&lt;/field<span class="re2">&gt;</span></span></span>
        <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">name</span>=<span class="st0">&quot;plat&quot;</span><span class="re2">&gt;</span></span>Entrée<span class="sc3"><span class="re1">&lt;/field<span class="re2">&gt;</span></span></span>
        <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">name</span>=<span class="st0">&quot;difficulte&quot;</span><span class="re2">&gt;</span></span>Expérimenté<span class="sc3"><span class="re1">&lt;/field<span class="re2">&gt;</span></span></span>
        <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">name</span>=<span class="st0">&quot;prix&quot;</span><span class="re2">&gt;</span></span>3<span class="sc3"><span class="re1">&lt;/field<span class="re2">&gt;</span></span></span>
        <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">name</span>=<span class="st0">&quot;saison&quot;</span><span class="re2">&gt;</span></span>Hiver<span class="sc3"><span class="re1">&lt;/field<span class="re2">&gt;</span></span></span>
        <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">name</span>=<span class="st0">&quot;created_at_dt&quot;</span><span class="re2">&gt;</span></span>2009-06-02T00:00:00.000Z<span class="sc3"><span class="re1">&lt;/field<span class="re2">&gt;</span></span></span>
    <span class="sc3"><span class="re1">&lt;/doc<span class="re2">&gt;</span></span></span>
    <span class="sc3"><span class="re1">&lt;doc<span class="re2">&gt;</span></span></span>
        <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">name</span>=<span class="st0">&quot;id&quot;</span><span class="re2">&gt;</span></span>5<span class="sc3"><span class="re1">&lt;/field<span class="re2">&gt;</span></span></span>
        <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">name</span>=<span class="st0">&quot;nom&quot;</span><span class="re2">&gt;</span></span>Salades de bobards<span class="sc3"><span class="re1">&lt;/field<span class="re2">&gt;</span></span></span>
        <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">name</span>=<span class="st0">&quot;repas&quot;</span><span class="re2">&gt;</span></span>Déjeuner<span class="sc3"><span class="re1">&lt;/field<span class="re2">&gt;</span></span></span>
        <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">name</span>=<span class="st0">&quot;plat&quot;</span><span class="re2">&gt;</span></span>Entrée<span class="sc3"><span class="re1">&lt;/field<span class="re2">&gt;</span></span></span>
        <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">name</span>=<span class="st0">&quot;difficulte&quot;</span><span class="re2">&gt;</span></span>Débutant<span class="sc3"><span class="re1">&lt;/field<span class="re2">&gt;</span></span></span>
        <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">name</span>=<span class="st0">&quot;prix&quot;</span><span class="re2">&gt;</span></span>9<span class="sc3"><span class="re1">&lt;/field<span class="re2">&gt;</span></span></span>
        <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">name</span>=<span class="st0">&quot;saison&quot;</span><span class="re2">&gt;</span></span>Toutes<span class="sc3"><span class="re1">&lt;/field<span class="re2">&gt;</span></span></span>
        <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">name</span>=<span class="st0">&quot;created_at_dt&quot;</span><span class="re2">&gt;</span></span>2009-06-18T00:00:00.000Z<span class="sc3"><span class="re1">&lt;/field<span class="re2">&gt;</span></span></span>
    <span class="sc3"><span class="re1">&lt;/doc<span class="re2">&gt;</span></span></span>
    <span class="sc3"><span class="re1">&lt;doc<span class="re2">&gt;</span></span></span>
        <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">name</span>=<span class="st0">&quot;id&quot;</span><span class="re2">&gt;</span></span>6<span class="sc3"><span class="re1">&lt;/field<span class="re2">&gt;</span></span></span>
        <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">name</span>=<span class="st0">&quot;nom&quot;</span><span class="re2">&gt;</span></span>Gratin de couleuvres<span class="sc3"><span class="re1">&lt;/field<span class="re2">&gt;</span></span></span>
        <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">name</span>=<span class="st0">&quot;repas&quot;</span><span class="re2">&gt;</span></span>Dîner<span class="sc3"><span class="re1">&lt;/field<span class="re2">&gt;</span></span></span>
        <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">name</span>=<span class="st0">&quot;plat&quot;</span><span class="re2">&gt;</span></span>Plat principal<span class="sc3"><span class="re1">&lt;/field<span class="re2">&gt;</span></span></span>
        <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">name</span>=<span class="st0">&quot;difficulte&quot;</span><span class="re2">&gt;</span></span>Expérimenté<span class="sc3"><span class="re1">&lt;/field<span class="re2">&gt;</span></span></span>
        <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">name</span>=<span class="st0">&quot;prix&quot;</span><span class="re2">&gt;</span></span>2<span class="sc3"><span class="re1">&lt;/field<span class="re2">&gt;</span></span></span>
        <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">name</span>=<span class="st0">&quot;saison&quot;</span><span class="re2">&gt;</span></span>Toutes<span class="sc3"><span class="re1">&lt;/field<span class="re2">&gt;</span></span></span>
        <span class="sc3"><span class="re1">&lt;field</span> <span class="re0">name</span>=<span class="st0">&quot;created_at_dt&quot;</span><span class="re2">&gt;</span></span>2009-09-09T00:00:00.000Z<span class="sc3"><span class="re1">&lt;/field<span class="re2">&gt;</span></span></span>
    <span class="sc3"><span class="re1">&lt;/doc<span class="re2">&gt;</span></span></span>
<span class="sc3"><span class="re1">&lt;/add<span class="re2">&gt;</span></span></span></pre></div></div>

<p>Avant toute chose, je vous encourage &agrave; <a href="http://localhost:8983/solr/select?q=*:*">tester la bonne indexation des donn&eacute;es</a>. C&#8217;est bon<span class="fine">&nbsp;</span>? Alors passons &agrave; la recherche &agrave; facette.</p>
<h2>Place aux facettes</h2>
<p>Il existe trois types de facettes possibles. Pour vous en convaincre, essayez de rajouter le param&egrave;tre <em>facet=true</em>, qui active la recherche par facette.</p>
<p><a href="http://localhost:8983/solr/select?q=*:*&#038;facet=true">http://localhost:8983/solr/select?q=*:*&#038;facet=true</a></p>
<p>Notez l&#8217;apparition de nouvelles cl&eacute;s dans l&#8217;affichage des r&eacute;sultats.</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;">…
<span class="sc3"><span class="re1">&lt;lst</span> <span class="re0">name</span>=<span class="st0">&quot;facet_counts&quot;</span><span class="re2">&gt;</span></span>
<span class="sc3"><span class="re1">&lt;lst</span> <span class="re0">name</span>=<span class="st0">&quot;facet_queries&quot;</span><span class="re2">/&gt;</span></span>
<span class="sc3"><span class="re1">&lt;lst</span> <span class="re0">name</span>=<span class="st0">&quot;facet_fields&quot;</span><span class="re2">/&gt;</span></span>
<span class="sc3"><span class="re1">&lt;lst</span> <span class="re0">name</span>=<span class="st0">&quot;facet_dates&quot;</span><span class="re2">/&gt;</span></span>
<span class="sc3"><span class="re1">&lt;/lst<span class="re2">&gt;</span></span></span></pre></div></div>

<p>Nos trois types sont donc&nbsp;:</p>
<ul>
<li><strong>Les facettes par champ (field faceting)</strong>&nbsp;: Comptent les r&eacute;sultats en partitionnant selon un champ donn&eacute;&nbsp;<span class="fine">&nbsp;</span>;</li>
<li><strong>Les facettes par requ&ecirc;tes (query faceting)</strong>&nbsp;: Comptent les r&eacute;sultats qui correspondent &agrave; certaines requ&ecirc;tes&nbsp;<span class="fine">&nbsp;</span>;</li>
<li><strong>Les facettes par date (date faceting)</strong>&nbsp;: Comptent les r&eacute;sultats en partitionnant selon des intervalles de dates&nbsp;<span class="fine">&nbsp;</span>;</li>
</ul>
<p>Commen&ccedil;ons par le plus simple, et certainement le plus utilis&eacute;&nbsp;: les facettes par champ. Rien de plus simple, il vous suffit d&#8217;ajouter le nom du champ dans l&#8217;url, gr&acirc;ce au param&egrave;tre <em>facet.field</em>, et&hellip; et c&#8217;est tout. Il est bien entendu possible d&#8217;ajouter plusieurs param&egrave;tres &agrave; la fois, pour autant de facettes.</p>
<p><a href="http://localhost:8983/solr/select?q=*:*&#038;rows=0&#038;facet=true&#038;facet.field=repas&#038;facet.field=saison&#038;facet.field=difficulte">http://localhost:8983/solr/select?q=*:*&#038;rows=0&#038;facet=true&#038;facet.field=repas&#038;facet.field=saison&#038;facet.field=difficulte</a></p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;"><span class="sc3"><span class="re1">&lt;lst</span> <span class="re0">name</span>=<span class="st0">&quot;facet_counts&quot;</span><span class="re2">&gt;</span></span>
    <span class="sc3"><span class="re1">&lt;lst</span> <span class="re0">name</span>=<span class="st0">&quot;facet_queries&quot;</span><span class="re2">/&gt;</span></span> 
&nbsp;
    <span class="sc3"><span class="re1">&lt;lst</span> <span class="re0">name</span>=<span class="st0">&quot;facet_fields&quot;</span><span class="re2">&gt;</span></span>
&nbsp;
        <span class="sc3"><span class="re1">&lt;lst</span> <span class="re0">name</span>=<span class="st0">&quot;repas&quot;</span><span class="re2">&gt;</span></span>
            <span class="sc3"><span class="re1">&lt;int</span> <span class="re0">name</span>=<span class="st0">&quot;Dîner&quot;</span><span class="re2">&gt;</span></span>3<span class="sc3"><span class="re1">&lt;/int<span class="re2">&gt;</span></span></span>
            <span class="sc3"><span class="re1">&lt;int</span> <span class="re0">name</span>=<span class="st0">&quot;Déjeuner&quot;</span><span class="re2">&gt;</span></span>2<span class="sc3"><span class="re1">&lt;/int<span class="re2">&gt;</span></span></span>
            <span class="sc3"><span class="re1">&lt;int</span> <span class="re0">name</span>=<span class="st0">&quot;Petit-déjeuner&quot;</span><span class="re2">&gt;</span></span>1<span class="sc3"><span class="re1">&lt;/int<span class="re2">&gt;</span></span></span>
        <span class="sc3"><span class="re1">&lt;/lst<span class="re2">&gt;</span></span></span>
&nbsp;
        <span class="sc3"><span class="re1">&lt;lst</span> <span class="re0">name</span>=<span class="st0">&quot;saison&quot;</span><span class="re2">&gt;</span></span>
            <span class="sc3"><span class="re1">&lt;int</span> <span class="re0">name</span>=<span class="st0">&quot;Hiver&quot;</span><span class="re2">&gt;</span></span>2<span class="sc3"><span class="re1">&lt;/int<span class="re2">&gt;</span></span></span>
            <span class="sc3"><span class="re1">&lt;int</span> <span class="re0">name</span>=<span class="st0">&quot;Toutes&quot;</span><span class="re2">&gt;</span></span>2<span class="sc3"><span class="re1">&lt;/int<span class="re2">&gt;</span></span></span>
            <span class="sc3"><span class="re1">&lt;int</span> <span class="re0">name</span>=<span class="st0">&quot;Automne&quot;</span><span class="re2">&gt;</span></span>1<span class="sc3"><span class="re1">&lt;/int<span class="re2">&gt;</span></span></span>
            <span class="sc3"><span class="re1">&lt;int</span> <span class="re0">name</span>=<span class="st0">&quot;Été&quot;</span><span class="re2">&gt;</span></span>1<span class="sc3"><span class="re1">&lt;/int<span class="re2">&gt;</span></span></span>
        <span class="sc3"><span class="re1">&lt;/lst<span class="re2">&gt;</span></span></span>
&nbsp;
        <span class="sc3"><span class="re1">&lt;lst</span> <span class="re0">name</span>=<span class="st0">&quot;difficulte&quot;</span><span class="re2">&gt;</span></span>
            <span class="sc3"><span class="re1">&lt;int</span> <span class="re0">name</span>=<span class="st0">&quot;Expérimenté&quot;</span><span class="re2">&gt;</span></span>3<span class="sc3"><span class="re1">&lt;/int<span class="re2">&gt;</span></span></span>
            <span class="sc3"><span class="re1">&lt;int</span> <span class="re0">name</span>=<span class="st0">&quot;Débutant&quot;</span><span class="re2">&gt;</span></span>2<span class="sc3"><span class="re1">&lt;/int<span class="re2">&gt;</span></span></span>
            <span class="sc3"><span class="re1">&lt;int</span> <span class="re0">name</span>=<span class="st0">&quot;Astronomique&quot;</span><span class="re2">&gt;</span></span>1<span class="sc3"><span class="re1">&lt;/int<span class="re2">&gt;</span></span></span>
        <span class="sc3"><span class="re1">&lt;/lst<span class="re2">&gt;</span></span></span>
    <span class="sc3"><span class="re1">&lt;/lst<span class="re2">&gt;</span></span></span>
    <span class="sc3"><span class="re1">&lt;lst</span> <span class="re0">name</span>=<span class="st0">&quot;facet_dates&quot;</span><span class="re2">/&gt;</span></span>
<span class="sc3"><span class="re1">&lt;/lst<span class="re2">&gt;</span></span></span></pre></div></div>

<p>Le r&eacute;sultat affiche maintenant la liste des facettes, avec le nombre de r&eacute;ponses pour chaque param&egrave;tre. Vous pensiez que &ccedil;a allait &ecirc;tre compliqu&eacute;<span class="fine">&nbsp;</span>? Au passage, vous pouvez consulter la <a href="http://wiki.apache.org/solr/SimpleFacetParameters">liste des param&egrave;tres disponibles</a>.</p>
<p>Note&nbsp;: le calcul des facettes s&#8217;effectue toujours dans le contexte de la recherche actuelle. Si ma recherche initiale (q=) ne retourne que 3 r&eacute;sultats, seuls ces trois l&agrave; seront pris en compte.</p>
<h2>Les facettes par requ&ecirc;tes</h2>
<p>Les facettes par requ&ecirc;tes permettent de sp&eacute;cifier des requ&ecirc;tes (au format classique) plut&ocirc;t que d&#8217;utiliser directement les valeurs des champs. C&#8217;est particuli&egrave;rement utile pour les intervalles (ex&nbsp;: les prix).</p>
<p>Les requ&ecirc;tes sont sp&eacute;cifi&eacute;es via le champ <em>facet.query</em>. Ajoutez plusieurs requ&ecirc;tes pour plusieurs facettes.</p>
<p><a href="http://localhost:8983/solr/select?q=*:*&#038;rows=0&#038;facet=true&#038;facet.query=prix:[*+TO+5]&#038;facet.query=prix:[5+TO+10]&#038;facet.query=prix:[10+TO+*]">http://localhost:8983/solr/select?q=*:*&#038;rows=0&#038;facet=true&#038;facet.query=prix:[*+TO+5]&#038;facet.query=prix:[5+TO+10]&#038;facet.query=prix:[10+TO+*]</a></p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;"><span class="sc3"><span class="re1">&lt;lst</span> <span class="re0">name</span>=<span class="st0">&quot;facet_counts&quot;</span><span class="re2">&gt;</span></span>
    <span class="sc3"><span class="re1">&lt;lst</span> <span class="re0">name</span>=<span class="st0">&quot;facet_queries&quot;</span><span class="re2">&gt;</span></span>
        <span class="sc3"><span class="re1">&lt;int</span> <span class="re0">name</span>=<span class="st0">&quot;prix:[* TO 5]&quot;</span><span class="re2">&gt;</span></span>3<span class="sc3"><span class="re1">&lt;/int<span class="re2">&gt;</span></span></span>
        <span class="sc3"><span class="re1">&lt;int</span> <span class="re0">name</span>=<span class="st0">&quot;prix:[5 TO 10]&quot;</span><span class="re2">&gt;</span></span>3<span class="sc3"><span class="re1">&lt;/int<span class="re2">&gt;</span></span></span>
        <span class="sc3"><span class="re1">&lt;int</span> <span class="re0">name</span>=<span class="st0">&quot;prix:[10 TO *]&quot;</span><span class="re2">&gt;</span></span>1<span class="sc3"><span class="re1">&lt;/int<span class="re2">&gt;</span></span></span>
    <span class="sc3"><span class="re1">&lt;/lst<span class="re2">&gt;</span></span></span>
    <span class="sc3"><span class="re1">&lt;lst</span> <span class="re0">name</span>=<span class="st0">&quot;facet_fields&quot;</span><span class="re2">/&gt;</span></span>
    <span class="sc3"><span class="re1">&lt;lst</span> <span class="re0">name</span>=<span class="st0">&quot;facet_dates&quot;</span><span class="re2">/&gt;</span></span>
<span class="sc3"><span class="re1">&lt;/lst<span class="re2">&gt;</span></span></span></pre></div></div>

<h2>Les facettes par dates</h2>
<p>Il serait bien entendu possible d&#8217;obtenir des facettes sur des champs dates en utilisant des requ&ecirc;tes, mais pourquoi se compliquer la vie&nbsp;<span class="fine">&nbsp;</span>? Gr&acirc;ce aux facettes par date, il suffit d&#8217;indiquer une date de d&eacute;but, une date de fin, et un intervalle.</p>
<p>Utile si je veux conna&icirc;tre le nombre de commentaires post&eacute;s pour chaque heure de la journ&eacute;e, ou le nombre de recettes post&eacute;es par mois de l&#8217;ann&eacute;e.</p>
<p>Les param&egrave;tres utiles sont&nbsp;:</p>
<ul>
<li><strong>facet.date</strong>&nbsp;: indique quel sera le champ pris en compte&nbsp;<span class="fine">&nbsp;</span>;</li>
<li><strong>facet.date.start</strong>&nbsp;: quelle est la date de d&eacute;but de la p&eacute;riode prise en compte&nbsp;<span class="fine">&nbsp;</span>;</li>
<li><strong>facet.date.end</strong>&nbsp;: je vous laisse deviner&nbsp;<span class="fine">&nbsp;</span>;</li>
<li><strong>facet.date.gap</strong>&nbsp;: l&#8217;invervalle de partitionnememt&nbsp;<span class="fine">&nbsp;</span>;</li>
</ul>
<p><a href="http://localhost:8983/solr/select?q=*:*&#038;facet=true&#038;facet.date=created_at_dt&#038;facet.date.start=NOW/YEAR&#038;facet.date.end=NOW&#038;facet.date.gap=%2B1MONTH">http://localhost:8983/solr/select?q=*:*&#038;facet=true&#038;facet.date=created_at_dt&#038;facet.date.start=NOW/YEAR&#038;facet.date.end=NOW&#038;facet.date.gap=+1MONTH</a></p>
<p>NOW/YEAR signifie que je d&eacute;marre mon calcul du d&eacute;but de l&#8217;ann&eacute;e. <a href="http://lucene.apache.org/solr/api/org/apache/solr/util/DateMathParser.html">La syntaxe est relativement simple</a>, je vous laisse consulter la doc.</p>
<h2>S&eacute;lectionner un crit&egrave;re</h2>
<div class="postimg alignright"><a href="http://www.flickr.com/photos/45942274@N00/3861490480/" title="Coffee" target="_blank"><img src="http://farm3.static.flickr.com/2566/3861490480_b0ff10bdfd_m.jpg" alt="Coffee" border="0" /></a><br /><small><a href="http://creativecommons.org/licenses/by-nc-nd/2.0/" title="Attribution-NonCommercial-NoDerivs License" target="_blank"><img src="http://www.miximum.fr/wp-content/plugins/photo-dropper/images/cc.png" alt="Creative Commons License" border="0" width="16" height="16" align="absmiddle" /></a> <a href="http://www.photodropper.com/photos/" target="_blank">photo</a> credit&nbsp;: <a href="http://www.flickr.com/photos/45942274@N00/3861490480/" title="Ryan Orr" target="_blank">Ryan Orr</a></small></div>
<p>Avec tout &ccedil;a, vous &ecirc;tes d&eacute;sormais capables d&#8217;effectuer des recherches par facettes sur des requ&ecirc;tes de bases. Il nous reste &agrave; voir comment restreindre notre recherche en s&eacute;lectionnant un crit&egrave;re particulier. Pour ce faire, nous allons utiliser le param&egrave;tre <a href="http://wiki.apache.org/solr/CommonQueryParameters#fq"><strong>fq</strong> (pour filter query)</a>, qui nous permettra d&#8217;appliquer un filtre sur les r&eacute;sultats renvoy&eacute;s par la requ&ecirc;te initiale.</p>
<p>Pour l&#8217;exemple, reprenons notre requ&ecirc;te initiale, avec facettes sur divers champs de la recette.</p>
<p><a href="http://localhost:8983/solr/select?q=*:*&#038;rows=0&#038;facet=true&#038;facet.field=repas&#038;facet.field=saison&#038;facet.field=difficulte">http://localhost:8983/solr/select?q=*:*&#038;rows=0&#038;facet=true&#038;facet.field=repas&#038;facet.field=saison&#038;facet.field=difficulte</a></p>
<p>Admettons que je cherche une id&eacute;e de recette pour le repas de no&euml;l, je vais restreindre ma recherche en n&#8217;affichant que les plats r&eacute;alisables en hiver.</p>
<p><a href="http://localhost:8983/solr/select?q=*:*&#038;facet=true&#038;facet.field=repas&#038;facet.field=difficulte&#038;fq=saison:Hiver">http://localhost:8983/solr/select?q=*:*&#038;facet=true&#038;facet.field=repas&#038;facet.field=difficulte&#038;fq=saison:Hiver</a></p>
<p>J&#8217;applique donc mon filtre (<strong>fq:Hiver</strong>), et j&#8217;en profite pour supprimer la facette sur le champ &laquo;&nbsp;saison&nbsp;&raquo; qui ne sert plus &agrave; rien. Rien ne m&#8217;emp&ecirc;che de raffiner ma requ&ecirc;te selon plusieurs crit&egrave;res en utilisant plusieurs fois le param&egrave;tre fq.</p>
<p>Vous savez tout. Il ne reste plus qu&#8217;&agrave; g&eacute;rer tous ces param&egrave;tres c&ocirc;t&eacute; frontend, en affichant le fil d&#8217;ariane, les crit&egrave;res et les effets kikoolol qui vont bien.</p>
<h4>Notes&nbsp;:</h4><ol class="footnotes"><li id="footnote-1-347">Admirez au passage le savant emploi de mots techniques qui n&#8217;a d&#8217;autres utilit&eacute; que de me donner l&#8217;air d&#8217;&ecirc;tre un expert  [<a href="#footnote-link-1-347">retour</a>]</li></ol>]]></content:encoded>
			<wfw:commentRss>http://www.miximum.fr/tutos/347-recherche-a-facette-sous-solr/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Besoin d&#8217;un freelance ?</title>
		<link>http://www.miximum.fr/inclassable/378-besoin-dun-freelance</link>
		<comments>http://www.miximum.fr/inclassable/378-besoin-dun-freelance#comments</comments>
		<pubDate>Wed, 18 Nov 2009 12:03:04 +0000</pubDate>
		<dc:creator>thibault</dc:creator>
				<category><![CDATA[Inclassable]]></category>
		<category><![CDATA[eZ Publish]]></category>
		<category><![CDATA[freelance]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[solr]]></category>
		<category><![CDATA[symfony]]></category>

		<guid isPermaLink="false">http://www.miximum.fr/?p=378</guid>
		<description><![CDATA[photo credit&#160;: h.koppdelaney C&#8217;est un petit pas pour l&#8217;humanit&#233;, mais un grand saut pour moi. &#192; partir de d&#233;cembre, je serai in&#233;luctablement freelance &#224; plein temps. Fini les embouteillages tous les matins (m&#234;me si je prends le v&#233;lo, &#231;a n&#8217;emp&#234;che pas l&#8217;air de puer le gaz). Envol&#233;s, les 2.5 jours de cong&#233;s par mois. Me [...]]]></description>
			<content:encoded><![CDATA[<div class="postimg alignright"><a href="http://www.flickr.com/photos/16230215@N08/3066799064/" title="Knight Horse and Sword" target="_blank"><img src="http://farm4.static.flickr.com/3171/3066799064_ed792a1b3f_m.jpg" alt="Knight Horse and Sword" border="0" /></a><br /><small><a href="http://creativecommons.org/licenses/by-nd/2.0/" title="Attribution-NoDerivs License" target="_blank"><img src="http://www.miximum.fr/wp-content/plugins/photo-dropper/images/cc.png" alt="Creative Commons License" border="0" width="16" height="16" align="absmiddle" /></a> <a href="http://www.photodropper.com/photos/" target="_blank">photo</a> credit&nbsp;: <a href="http://www.flickr.com/photos/16230215@N08/3066799064/" title="h.koppdelaney" target="_blank">h.koppdelaney</a></small></div>
<p>C&#8217;est un petit pas pour l&#8217;humanit&eacute;, mais un grand saut pour moi. &Agrave; partir de d&eacute;cembre, je serai in&eacute;luctablement <strong>freelance &agrave; plein temps</strong>.</p>
<p>Fini les embouteillages tous les matins (m&ecirc;me si je prends le v&eacute;lo, &ccedil;a n&#8217;emp&ecirc;che pas l&#8217;air de puer le gaz). Envol&eacute;s, les 2.5 jours de cong&eacute;s par mois. Me voil&agrave; pleinement ma&icirc;tre de mon destin, et &ccedil;a fait du bien (Ah<span class="fine">&nbsp;</span>?! On me signale que les freelances n&#8217;ont pas la vie rose tous les jours<span class="fine">&nbsp;</span>? Bon, tant pis&hellip;)</p>
<p>J&#8217;aurais pu me qualifier d&#8217;&laquo;&nbsp;entrepreneur&nbsp;&raquo;, de &laquo;&nbsp;chef d&#8217;entreprise&nbsp;&raquo;, d&#8217;&laquo;&nbsp;ind&eacute;pendant&nbsp;&raquo;, voire d&#8217;&laquo;&nbsp;indep&#8217;&nbsp;&raquo;, mais j&#8217;aime cette image du chevalier, libre comme l&#8217;air et cheveux au vent, n&#8217;ayant pour biens que sa monture et son &eacute;p&eacute;e (une lance, en l&#8217;occurence), chevauchant par monts et par vaux en combattant pour ses id&eacute;aux, et aussi un peu pour remplir sa gamelle.</p>
<p>Alors voil&agrave;, puisque vous me le demandez (sisi, vous me le demandez), j&#8217;ai choisi, dans un premier temps, de focaliser mon activit&eacute; sur les d&eacute;veloppements web sp&eacute;cifiques, bas&eacute;s sur l&#8217;int&eacute;gration des technologies libres suivantes&nbsp;:</p>
<ul>
<li><strong>Symfony</strong>&nbsp;: Le top des frameworks PHP, pour des d&eacute;veloppements sp&eacute;cifiques&nbsp;fonctionnels et standardis&eacute;s&nbsp;<span class="fine">&nbsp;</span>;</li>
<li><strong>eZ&nbsp;Publish</strong>&nbsp;: La Rolls Royce des CMS, pour des sites &eacute;ditoriaux&nbsp;haut de gamme&nbsp;<span class="fine">&nbsp;</span>;</li>
<li><strong>Solr</strong>&nbsp;: Le meilleur moteur de recherche libre au monde, pour fournir &agrave; vos utilisateurs une exp&eacute;rience de recherche incomparable&nbsp;<span class="fine">&nbsp;</span>;</li>
</ul>
<p>Et puis, tant qu&#8217;&agrave; faire, j&#8217;entends bien batir des prestations de qualit&eacute;, en industrialisant mes d&eacute;veloppements au maximum (TDD, int&eacute;gration continue, m&eacute;thodo agile, etc.).</p>
<p>Je serai bien entendu enchant&eacute; de r&eacute;pondre &agrave; votre coup de fil si vous souhaitez discuter de votre projet. Si vous voulez en savoir plus, vous pouvez <a href="http://thibault.jouannic.fr" title="ingenieur web freelance">consulter ma page professionnelle</a>. Vous y trouverez les informations n&eacute;cessaires pour me contacter.</p>
<p>Comme je suis d&#8217;un naturel optimiste, je suis intimement convaincu que tout ce passera bien et que j&#8217;adorerai ma nouvelle vie. Cela dit, un petit commentaire d&#8217;encouragement est toujours bon &agrave; prendre <img src='http://www.miximum.fr/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.miximum.fr/inclassable/378-besoin-dun-freelance/feed</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
	</channel>
</rss>

