This post was originally published on Coding Glamour.

Alle huizen op funda staan netjes opgeslagen in een SQL Server database. Normaal gesproken best praktisch, maar niet flexibel genoeg om al onze wensen eenvoudig te vervullen. Vandaar de overstap naar een zoekplatform dat hier wél voor geoptimaliseerd is. Vandaag deel 1 in een technische serie over de overgang naar Solr.

Bij onze zoektocht naar nieuwe software is het van belang dat deze snel is, want we serveren tijdens een beetje drukte makkelijk meer dan 300 pageviews per seconde. Daar ligt ook meteen het goede nieuws: Solr is blazingly fast! Op één instance haalden we al een performance van 1.000 req/s. En dat is niet alleen zoeken, maar inclusief het converteren van en naar .NET code. En het mooie is; het integreren binnen een bestaande .NET omgeving is helemaal niet zo lastig! Faceted search
Faceted search is het clusteren van zoekresultaten in relevante categoriën; om snel en intuitief door grote sets data heen te filteren:
http://weblogs.asp.net/blogs/drnetjes/CNET_faceted_search.jpg
Het hele doel van dit implementatietraject is om dit eenvoudiger te laten verlopen, zoals in een eerder artikel al eens uitgezet is.

Onze pre-Solr oplossing
Voordat we met Solr aan de slag gingen gebruikten we veel redundante kolommen op funda, waarbij we voor elk hiervan een COUNT(...) deden:
http://weblogs.asp.net/blogs/drnetjes/wide_table2.png
Wanneer een gebruiker dus zocht naar 'Amsterdam', dan zag een gemiddelde query er uit als:

SELECT COUNT(hasGarden), COUNT(yearBuilt1930_1940), COUNT(yearBuilt1941_1950), COUNT(etc...) 
FROM KoopObjecten
WHERE city = 'Amsterdam'

Nadelen van deze oplossing zijn:
  • Toevoegen van nieuwe facetten is arbeidsintensief
  • Performance is niet acceptabel bij grote datasets
En wanneer je dan flink wat meer huizen wil tonen op je site, gaan deze argumenten vrij zwaar wegen.

Welkom bij Solr
Wikipedia:
"Solr is an open source enterprise search server based on the Lucene Java search library, with XML/HTTP and JSON APIs, hit highlighting, faceted search, caching, replication, and a web administration interface."
Je moet Solr dus ook niet als database zien, maar meer als een grote index. Wanneer je data upload naar de server wordt de data geanalyseerd, en wordt er een inverted index van gebakken. Op deze manier kan er razendsnel worden gezocht. Voor meer info over de werking van de indexer kan je op de Solr wiki terecht.

Na installatie is het opvragen van zoekresultaten eenvoudig. Het is namelijk niets anders dan het opvragen van een URL in de browser:

http://localhost:8983/solr/select?q=city:Amsterdam

Er wordt nu standaard XML teruggegeven:

   <response>
     <result name="response" numFound="3" start="0">
         <doc>
            <long name="id">3203</long>
            <str name="city">Amsterdam</str>
            <str name="steet">Keizersgracht</str>
            <bool name="hasGarden">false</bool>
            <int name="yearBuilt">1932</int>
        </doc>
        <doc>
            <long name="id">3205</long>
            <str name="city">Amsterdam</str>
            <str name="steet">Vondelstraat</str>
            <bool name="hasGarden">true</bool>
            <int name="yearBuilt">1938</int>
         </doc>
         <doc>
            <long name="id">4293</long>
            <str name="city">Amsterdam</str>
            <str name="steet">Trompstraat</str>
            <bool name="hasGarden">true</bool>
            <int name="yearBuilt">1949</int>
         </doc>
      </result>
   </response>

Het wordt echter pas interessant, als we aangeven dat we ook de faceted search willen hebben. Dit kan door extra parameters mee te geven:

...&facet.field=hasGarden&facet.query=yearBuilt:[1930 TO 1940]&facet.query=yearBuilt:[1941 TO 1950]

Naast de standaard resultaten voegt Solr nu een extra sectie toe aan het xml document, met daarin de facetten voor alle objecten binnen je zoekopdracht vallen (ook degene die je niet ziet door bijv. paging)!

   <response>
      <result name="response" numFound="3" start="0">
         ...
      </result>
      <lst name="facet_counts">
         <lst name="facet_queries">
            <int name="yearBuilt:[1930 TO 1940]">2</int>
            <int name="yearBuilt:[1941 TO 1950]">1</int>
         </lst>
         <lst name="facet_fields">
            <lst name="hasGarden">
               <int name="true">2</int>
               <int name="false">1</int>
            </lst>
         </lst>
      </lst>
   </response>


Zelf spelen?
No problemo. Zorg dat Java is geïnstalleerd op je machine, en open deze tutorial. Binnen een uur heb je Solr geïnstalleerd, geconfigureerd, data geüpload en je eerste queries gedaan. Solr werkt ook onder Windows zonder verdere problemen.

Tips en best practices voor Solr met .NET
  • In tegenstelling tot wat in de tutorial staat, was het voor ons makkelijker zijn om Solr te hosten binnen Tomcat. Tomcat draait gewoon als Windows service; met alle voordelen van dien. Voor installatie: zie SolrTomcat.
  • Gebruik de 64-bits versie van Tomcat. Bij ons verdubbelde het aantal req/s.
  • Gebruik .NET's XmlReader om de XML van Solr te converteren naar .NET objecten. XPath is te traag.
  • Gebruik filter queries ("fq" ipv "q") als het mogelijk is. Deze worden namelijk gecached, en dat scheelt aanzienlijk in snelheid.
Next up?
In de nabije toekomst wordt deze serie vervolgd met een artikel over het synchroon houden van de data in SQL Server en in de Solr index!

Dit was een gastbijdrage van Dion Olsthoorn, mede-developer bij funda.