Volltextsuche mit Solr

1. Übersicht

In diesem Artikel untersuchen wir ein grundlegendes Konzept in der Apache Solr-Suchmaschine - die Volltextsuche.

Das Apache Solr ist ein Open Source-Framework, das für den Umgang mit Millionen von Dokumenten entwickelt wurde. Wir werden die Kernfunktionen anhand von Beispielen mit der Java-Bibliothek SolrJ durchgehen.

2. Maven-Konfiguration

Angesichts der Tatsache, dass Solr Open Source ist, können wir einfach die Binärdatei herunterladen und den Server separat von unserer Anwendung starten.

Um mit dem Server zu kommunizieren, definieren wir die Maven-Abhängigkeit für den SolrJ-Client:

 org.apache.solr solr-solrj 6.4.2 

Die neueste Abhängigkeit finden Sie hier.

3. Indizieren von Daten

Um Daten zu indizieren und zu suchen, müssen wir einen Kern erstellen . Wir erstellen ein benanntes Element, um unsere Daten zu indizieren.

Zuvor müssen Daten auf dem Server indiziert werden, damit sie durchsucht werden können.

Es gibt viele verschiedene Möglichkeiten, Daten zu indizieren. Wir können Datenimport-Handler verwenden, um Daten direkt aus relationalen Datenbanken zu importieren, Daten mit Solr Cell mithilfe von Apache Tika hochzuladen oder XML / XSLT-, JSON- und CSV-Daten mithilfe von Index-Handlern hochzuladen.

3.1. Indizieren von Solr-Dokumenten

Wir können Daten in einem Kern indizieren, indem wir SolrInputDocument erstellen . Zuerst müssen wir das Dokument mit unseren Daten füllen und dann nur die SolrJ-API aufrufen, um das Dokument zu indizieren:

SolrInputDocument doc = new SolrInputDocument(); doc.addField("id", id); doc.addField("description", description); doc.addField("category", category); doc.addField("price", price); solrClient.add(doc); solrClient.commit();

Beachten Sie, dass die ID natürlich für verschiedene Elemente eindeutig sein sollte . Wenn Sie eine ID eines bereits indizierten Dokuments haben, wird dieses Dokument aktualisiert.

3.2. Bohnen indizieren

SolrJ bietet APIs zum Indizieren von Java-Beans. Um eine Bean zu indizieren, müssen wir sie mit den @ Field- Annotationen versehen:

public class Item { @Field private String id; @Field private String description; @Field private String category; @Field private float price; }

Sobald wir die Bohne haben, ist die Indizierung einfach:

solrClient.addBean(item); solrClient.commit();

4. Solr-Abfragen

Suchen ist die mächtigste Fähigkeit von Solr. Sobald wir die Dokumente in unserem Repository indiziert haben, können wir nach Schlüsselwörtern, Phrasen, Datumsbereichen usw. suchen. Die Ergebnisse werden nach Relevanz (Punktzahl) sortiert.

4.1. Grundlegende Abfragen

Der Server stellt eine API für Suchvorgänge bereit. Wir können Anforderungshandler entweder aufrufen / auswählen oder / abfragen .

Lassen Sie uns eine einfache Suche durchführen:

SolrQuery query = new SolrQuery(); query.setQuery("brand1"); query.setStart(0); query.setRows(10); QueryResponse response = solrClient.query(query); List items = response.getBeans(Item.class);

SolrJ verwendet intern den Hauptabfrageparameter q in seiner Anforderung an den Server. Die Anzahl der zurückgegebenen Datensätze beträgt 10 und wird von Null indiziert, wenn Start und Zeilen nicht angegeben sind.

Die obige Suchabfrage sucht nach Dokumenten, die das vollständige Wort "brand1" in einem der indizierten Felder enthalten. Beachten Sie, dass bei einfachen Suchvorgängen nicht zwischen Groß- und Kleinschreibung unterschieden wird.

Schauen wir uns ein anderes Beispiel an. Wir wollen jedes Wort suchen, das "rand" enthält , das mit einer beliebigen Anzahl von Zeichen beginnt und mit nur einem Zeichen endet. Wir können Platzhalterzeichen * und ? Verwenden . in unserer Anfrage:

query.setQuery("*rand?");

Solr-Abfragen unterstützen auch boolesche Operatoren wie in SQL:

query.setQuery("brand1 AND (Washing OR Refrigerator)");

Alle booleschen Operatoren müssen in Großbuchstaben angegeben werden. Diejenigen, die vom Abfrageparser unterstützt werden, sind AND , OR, NOT , + und -.

Wenn wir anstelle aller indizierten Felder nach bestimmten Feldern suchen möchten, können wir diese in der Abfrage angeben:

query.setQuery("description:Brand* AND category:*Washing*");

4.2. Phrasenabfragen

Bis zu diesem Punkt suchte unser Code in den indizierten Feldern nach Schlüsselwörtern. Wir können auch nach Phrasen in den indizierten Feldern suchen:

query.setQuery("Washing Machine");

Wenn wir einen Satz wie „ Waschmaschine “ haben, analysiert der Standard-Abfrageparser von Solr ihn in „ Waschen ODER Maschine “. Um nach einer ganzen Phrase zu suchen, können wir den Ausdruck nur in doppelte Anführungszeichen setzen:

query.setQuery("\"Washing Machine\"");

Wir können die Näherungssuche verwenden, um Wörter in bestimmten Entfernungen zu finden . Wenn wir die Wörter finden möchten, die mindestens zwei Wörter voneinander entfernt sind, können wir die folgende Abfrage verwenden:

query.setQuery("\"Washing equipment\"~2");

4.3. Bereichsabfragen

Bereichsabfragen ermöglichen das Abrufen von Dokumenten, deren Felder zwischen bestimmten Bereichen liegen.

Angenommen, wir möchten Artikel finden, deren Preis zwischen 100 und 300 liegt:

query.setQuery("price:[100 TO 300]");

Die obige Abfrage findet alle Elemente, deren Preis zwischen 100 und einschließlich 300 liegt. Wir können " } " und " { " verwenden, um Endpunkte auszuschließen:

query.setQuery("price:{100 TO 300]");

4.4. Abfragen filtern

Filterabfragen können verwendet werden, um die Obermenge der Ergebnisse einzuschränken, die zurückgegeben werden können. Die Filterabfrage hat keinen Einfluss auf die Punktzahl:

SolrQuery query = new SolrQuery(); query.setQuery("price:[100 TO 300]"); query.addFilterQuery("description:Brand1","category:Home Appliances");

Im Allgemeinen enthält die Filterabfrage häufig verwendete Abfragen. Da sie häufig wiederverwendbar sind, werden sie zwischengespeichert, um die Suche effizienter zu gestalten.

5. Facettierte Suche

Faceting helps to arrange search results into group counts. We can facet fields, query or ranges.

5.1. Field Faceting

For example, we want to get the aggregated counts of categories in the search result. We can add category field in our query:

query.addFacetField("category"); QueryResponse response = solrClient.query(query); List facetResults = response.getFacetField("category").getValues();

The facetResults will contain counts of each category in the results.

5.2. Query Faceting

Query faceting is very useful when we want to bring back counts of subqueries:

query.addFacetQuery("Washing OR Refrigerator"); query.addFacetQuery("Brand2"); QueryResponse response = solrClient.query(query); Map facetQueryMap = response.getFacetQuery();

As a result, the facetQueryMap will have counts of facet queries.

5.3. Range Faceting

Range faceting is used to get the range counts in the search results. The following query will return the counts of price ranges between 100 and 251, gapped by 25:

query.addNumericRangeFacet("price", 100, 275, 25); QueryResponse response = solrClient.query(query); List rangeFacets = response.getFacetRanges().get(0).getCounts();

Apart from numeric ranges, Solr also supports date ranges, interval faceting, and pivot faceting.

6. Hit Highlighting

We may want the keywords in our search query to be highlighted in the results. This will be very helpful to get a better picture of the results. Let's index some documents and define keywords to be highlighted:

itemSearchService.index("hm0001", "Brand1 Washing Machine", "Home Appliances", 100f); itemSearchService.index("hm0002", "Brand1 Refrigerator", "Home Appliances", 300f); itemSearchService.index("hm0003", "Brand2 Ceiling Fan", "Home Appliances", 200f); itemSearchService.index("hm0004", "Brand2 Dishwasher", "Washing equipments", 250f); SolrQuery query = new SolrQuery(); query.setQuery("Appliances"); query.setHighlight(true); query.addHighlightField("category"); QueryResponse response = solrClient.query(query); Map
    
     > hitHighlightedMap = response.getHighlighting(); Map
     
       highlightedFieldMap = hitHighlightedMap.get("hm0001"); List highlightedList = highlightedFieldMap.get("category"); String highLightedText = highlightedList.get(0);
     
    

We'll get the highLightedText as “Home Appliances. Please notice that the search keyword Appliances is tagged with . Default highlighting tag used by Solr is , but we can change this by setting the pre and post tags:

query.setHighlightSimplePre(""); query.setHighlightSimplePost("");

7. Search Suggestions

One of the important features that Solr supports are suggestions. If the keywords in the query contain spelling mistakes or if we want to suggest to autocomplete a search keyword, we can use the suggestion feature.

7.1. Spell Checking

The standard search handler does not include spell checking component; it has to be configured manually. There are three ways to do it. You can find the configuration details in the official wiki page. In our example, we'll use IndexBasedSpellChecker, which uses indexed data for keyword spell checking.

Let's search for a keyword with spelling mistake:

query.setQuery("hme"); query.set("spellcheck", "on"); QueryResponse response = solrClient.query(query); SpellCheckResponse spellCheckResponse = response.getSpellCheckResponse(); Suggestion suggestion = spellCheckResponse.getSuggestions().get(0); List alternatives = suggestion.getAlternatives(); String alternative = alternatives.get(0);

Expected alternative for our keyword “hme” should be “home” as our index contains the term “home”. Note that spellcheck has to be activated before executing the search.

7.2. Auto Suggesting Terms

We may want to get the suggestions of incomplete keywords to assist with the search. Solr's suggest component has to be configured manually. You can find the configuration details in its official wiki page.

We have configured a request handler named /suggest to handle suggestions. Let's get suggestions for keyword “Hom”:

SolrQuery query = new SolrQuery(); query.setRequestHandler("/suggest"); query.set("suggest", "true"); query.set("suggest.build", "true"); query.set("suggest.dictionary", "mySuggester"); query.set("suggest.q", "Hom"); QueryResponse response = solrClient.query(query); SuggesterResponse suggesterResponse = response.getSuggesterResponse(); Map
      
        suggestedTerms = suggesterResponse.getSuggestedTerms(); List suggestions = suggestedTerms.get("mySuggester");
      

The list suggestions should contain all words and phrases. Note that we have configured a suggester named mySuggester in our configuration.

8. Conclusion

This article is a quick intro to the search engine's capabilities and features of Solr.

We touched on many features, but these are of course just scratching the surface of what we can do with an advanced and mature search server such as Solr.

The examples used here are available as always, over on GitHub.