Aplikacja „sprzedaż samochodów” – Result Grouping, czyli grupowanie wyników wyszukiwania (cz. 6)

W dzisiejszym poście postaramy się dodać do naszej aplikacji sprzedaży samochodów kolejną funkcjonalność, która będzie polegała na grupowaniu wyników wyszukiwania. Wyobraźmy sobie sytuację, że użytkownik chciałby na zapytanie „Audi A4” otrzymać wyniki pogrupowane np. po roku produkcji, tak aby widział po 2-3 wyniki wyszukiwania dla każdego roku. A może grupowanie po zakresach przebiegu auta ? Zajmijmy się tym tematem.

Opis parametrów requestu nowej funkcjonalności

Funkcjonalność grupowania wyników wyszukiwania jest dostępna od wersji solr 3.3. Przyjrzyjmy się podstawowym parametrom requestu, jakich będziemy potrzebowali:

  • group – włącza/wyłącza grupowanie wyników
  • group.field – nazwa pola, po którym chcemy pogrupować wyniki. Musimy zadbać o to aby pole, po którym chcemy grupować (rok produkcji), było w postaci tekstowej i nie było polem wielokrotnym
  • group.query – zapytanie, które użyjemy w celu pogrupowania wyników po zakresie przebiegu auta
  • group.limit – limit wyników wyszukiwania w każdej z grup

Te cztery podstawowe parametry pozwolą nam na zrealizowanie założeń.

Zmiany w schema.xml

Ewentualne zmiany w pliku schema.xml będą polegały na zadbaniu, aby pola, po których chcemy grupować wyniki wyszukiwania, było w postaci „string” lub „text”. Nasze wyniki chcielibyśmy grupować po polu „rok produkcji”. Dla przypomnienia, reprezentacja tego pola w tym momencie wygląda tak:

<field name="year" type="tint" indexed="true" stored="true" required="true" />

czyli jest to pole typu całkowitoliczbowego. W celu umożliwienia grupowania po tym polu tworzymy kolejne pole, które będzie odpowiednikiem pola „year”, ale w postaci tekstowej:

<field name="year_group" type="string" indexed="true" stored="false" />

i kopiujemy zawartość pola „year” do pola „year_group”:

<copyField source="year" dest="year_group"/>

To praktycznie wszystkie zmiany jakie musimy dokonać w pliku konfiguracyjnym schema.xml.

Przykładowe dane

Stwórzmy teraz przykładowe dane w celu przetestowania nowej funkcjonalności. Załóżmy że mamy próbkę danych aut o marce Audi i modelu A4. Dwa z nich są z rocznika 2002, kolejne dwa z rocznika 2003 oraz jeden z rocznika 2006. Dodatkowo, jedno z aut ma przebieg poniżej 100 000 km, trzy mają przebieg od 100 000 do 199 999 km i jedno auto które ma przebieg co najmniej 200 000 km:

<add>
   <doc>
      <field name="id">1</field>
      <field name="make">Audi</field>
      <field name="model">A4</field>
      <field name="year">2002</field>
      <field name="price">22700</field>
      <field name="engine_size">1900</field>
      <field name="mileage">197000</field>
      <field name="colour">green</field>
      <field name="damaged">false</field>
      <field name="city">Koszalin</field>
      <field name="loc">54.12,16.11</field>
   </doc>
   <doc>
      <field name="id">2</field>
      <field name="make">Audi</field>
      <field name="model">A4</field>
      <field name="year">2003</field>
      <field name="price">27800</field>
      <field name="engine_size">1900</field>
      <field name="mileage">220000</field>
      <field name="colour">black</field>
      <field name="damaged">false</field>
      <field name="city">Bialystok</field>
      <field name="loc">53.08,23.09</field>
   </doc>
   <doc>
      <field name="id">3</field>
      <field name="make">Audi</field>
      <field name="model">A4</field>
      <field name="year">2002</field>
      <field name="price">21300</field>
      <field name="engine_size">1900</field>
      <field name="mileage">125000</field>
      <field name="colour">black</field>
      <field name="damaged">false</field>
      <field name="city">Szczecin</field>
      <field name="loc">53.25,14.35</field>
   </doc>
   <doc>
      <field name="id">4</field>
      <field name="make">Audi</field>
      <field name="model">A4</field>
      <field name="year">2003</field>
      <field name="price">30300</field>
      <field name="engine_size">1900</field>
      <field name="mileage">150000</field>
      <field name="colour">red</field>
      <field name="damaged">false</field>
      <field name="city">Gdansk</field>
      <field name="loc">54.21,18.40</field>
   </doc>
  <doc>
      <field name="id">5</field>
      <field name="make">Audi</field>
      <field name="model">A4</field>
      <field name="year">2006</field>
      <field name="price">32100</field>
      <field name="engine_size">1900</field>
      <field name="mileage">9900</field>
      <field name="colour">red</field>
      <field name="damaged">false</field>
      <field name="city">Swidnik</field>
      <field name="loc">52.15,21.00</field>
   </doc>
</add>

Tworzymy zapytania

Wykorzystując parametry opisane na początku artykułu, tworzymy zapytanie, które zwróci nam wyniki wyszukiwania dla zapytania „Audi A4” pogrupowane po roku produkcji auta:

?q=audi+a4&group=true&group.field=year_group&group.limit=2&fl=id,mileage,make,model,year

Jak widać, ograniczyliśmy nasze wyniki wyszukiwania do maksymalnie dwóch w każdej z grup. Wypiszemy sobie w response jedynie te pola, które dadzą nam czytelny obraz identyfikacji dokumentów, czyli identyfikator, przebieg, marka, model oraz rok produkcji. W rezultacie otrzymujemy w response:

<lst name="grouped">
  <lst name="year_group">
    <int name="matches">5</int>
    <arr name="groups">
      <lst>
        <str name="groupValue">2002</str>
        <result name="doclist" numFound="2" start="0">
          <doc>
            <str name="id">1</str>
            <str name="make">Audi</str>
            <int name="mileage">197000</int>
            <str name="model">A4</str>
            <int name="year">2002</int>
          </doc>
          <doc>
            <str name="id">3</str>
            <str name="make">Audi</str>
            <int name="mileage">125000</int>
            <str name="model">A4</str>
            <int name="year">2002</int>
          </doc>
        </result>
      </lst>
      <lst>
        <str name="groupValue">2003</str>
        <result name="doclist" numFound="2" start="0">
          <doc>
            <str name="id">2</str>
            <str name="make">Audi</str>
            <int name="mileage">220000</int>
            <str name="model">A4</str>
            <int name="year">2003</int>
          </doc>
          <doc>
            <str name="id">4</str>
            <str name="make">Audi</str>
            <int name="mileage">150000</int>
            <str name="model">A4</str>
            <int name="year">2003</int>
          </doc>
        </result>
      </lst>
      <lst>
        <str name="groupValue">2006</str>
        <result name="doclist" numFound="1" start="0">
          <doc>
            <str name="id">5</str>
            <str name="make">Audi</str>
            <int name="mileage">9900</int>
            <str name="model">A4</str>
            <int name="year">2006</int>
          </doc>
        </result>
      </lst>
    </arr>
  </lst>
</lst>

Przeanalizujmy sobie odpowiedź. Na dane zapytanie otrzymaliśmy 5 trafień:

<int name="matches">5</int>

Odpowiedź została podzielona na 3 niezależne grupy:

  1. <str name="groupValue">2002</str>

    w której znalazły się dwa dokumenty (numFound=”2″), czyli auta z rocznika 2002

  2. <str name="groupValue">2003</str>

    w której znalazły się dwa dokumenty (numFound=”2″), czyli auta z rocznika 2003

  3. <str name="groupValue">2006</str>

    w której znalazł się jeden dokument (numFound=”1″), czyli auto z rocznika 2006

Zgadza się!

Skonstruujmy teraz zapytanie, które pogrupuje nam wyniki wyszukiwania po zakresie przebiegu samochodu. Zakładamy 3 zakresy:

  1. <0km ; 99999km>
  2. <100000km ; 199999km>
  3. <200000km ; * >

Zapytanie:

?q=audi+a4&group=true&group.query=mileage:[0+TO+99999]&group.query=mileage:[100000+TO+199999]&group.query=mileage:[200000+TO+*]&group.limit=3&fl=id,mileage,make,model,year

Dostajemy odpowiedź:

<lst name="grouped">
  <lst name="mileage:[0 TO 99999]">
    <int name="matches">5</int>
    <result name="doclist" numFound="1" start="0">
      <doc>
        <str name="id">5</str>
        <str name="make">Audi</str>
        <int name="mileage">9900</int>
        <str name="model">A4</str>
        <int name="year">2006</int>
      </doc>
    </result>
  </lst>
  <lst name="mileage:[100000 TO 199999]">
    <int name="matches">5</int>
    <result name="doclist" numFound="3" start="0">
      <doc>
        <str name="id">1</str>
        <str name="make">Audi</str>
        <int name="mileage">197000</int>
        <str name="model">A4</str>
        <int name="year">2002</int>
      </doc>
      <doc>
        <str name="id">3</str>
        <str name="make">Audi</str>
        <int name="mileage">125000</int>
        <str name="model">A4</str>
        <int name="year">2002</int>
      </doc>
      <doc>
        <str name="id">4</str>
        <str name="make">Audi</str>
        <int name="mileage">150000</int>
        <str name="model">A4</str>
        <int name="year">2003</int>
      </doc>
    </result>
  </lst>
  <lst name="mileage:[200000 TO *]">
    <int name="matches">5</int>
    <result name="doclist" numFound="1" start="0">
      <doc>
        <str name="id">2</str>
        <str name="make">Audi</str>
        <int name="mileage">220000</int>
        <str name="model">A4</str>
        <int name="year">2003</int>
      </doc>
    </result>
  </lst>
</lst>

Ponownie otrzymaliśmy 5 wyników. W pierwszej grupie znalazło się auto o przebiegu 9900 km, w drugiej grupie auta o przebiegach 197000 km, 125000 km oraz 150000 km, a w trzeciej auto o największym przebiegu, czyli 220000 km.
Otrzymaliśmy to co chcieliśmy osiągnąć. Zadanie wykonane.

Podsumowanie

Kolejna funkcjonalność, tym razem związana z grupowaniem wyników wyszukiwania, została dodana do naszej aplikacji sprzedaży samochodów. Zobaczymy jak zareagują na nią klienci 🙂

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *