Auf der Suche nach dem heiligen Gral

Let’s code

Wie eben erwähnt, besitzt Solr ein Java API namens SolrJ. Wir können mit diesem API eine Instanz eines Solr-Servers erstellen, die wir dann programmatisch verwenden, um Dokumente mithilfe der getNamedSolrServer()-Methode wie in Listing 1 zu erstellen, zu aktualisieren und zu löschen. Aus Platzgründen sind innerhalb des Artikels nur gekürzte Listings wiedergegeben, die kompletten Versionen befinden sich unter [9]. Das komplette Listing 1 enthält Methoden zum Auf- und Abbau der Solr-Verbindung, zum Hinzufügen, Ersetzen und Löschen von Solr-Dokumenten in unserem Index und Hilfsmethoden zum Bauen von Anfragen gegen den Index. Das SolrJ API ist intuitiv zu nutzen, aber gelegentlich etwas gesprächig, deshalb haben wir in der in Listing 1 dargestellten Hilfsklasse SolrUtil einige häufig aufgerufene Aktionen abstrahiert:

Listing 1
public class SolrUtil {
  public static final Logger LOG = LoggerFactory.getLogger(SolrUtil.class); 
  private static final String DEFAULT_AND_OPERATOR_STRING = " "; 
  private static final String DEFAULT_OR_OPERATOR_STRING = "OR"; 

  public enum FolderSchemaField {
    ID, FOLDER_ID, PARENT_ID, NAME, USER, TOTAL, UNREAD; 

public String getSName() { 
  return toString().toLowerCase(); 
} 
  } 

  public static SolrServer getNamedSolrServer(Properties props,
    String propertyName) { 
    String server = props.getProperty(propertyName); 
    try { 
      return new CommonsHttpSolrServer(server); 
    } catch (MalformedURLException e) { 
      LOG.error("Solr server could not be created!", e); 
    } 
return null; 
  } 

  public static void addOrReplaceFolder(SolrServer solr, String folderId, 
    String parentId, String folderName, String userName, int total, int unread) {                   
    SolrInputDocument folderDocument = new SolrInputDocument(); 
    folderDocument.addField(FolderSchemaField.ID.getSName(), folderId);
    folderDocument.addField(FolderSchemaField.FOLDER_ID.getSName(), folderId);
    folderDocument.addField(FolderSchemaField.PARENT_ID.getSName(), parentId);
    folderDocument.addField(FolderSchemaField.NAME.getSName(), folderName);
    folderDocument.addField(FolderSchemaField.USER.getSName(), userName);
    folderDocument.addField(FolderSchemaField.TOTAL.getSName(), total);
    folderDocument.addField(FolderSchemaField.UNREAD.getSName(), unread);
    addOrReplaceDocument(solr, folderDocument, true); 
  } 

  public static void addOrReplaceDocument(SolrServer solr, SolrInputDocument sdoc,
    boolean commit) { 
    Collection docs = new ArrayList(); 
    docs.add(sdoc); 
    try { 
      if (commit) { 
        UpdateRequest req = new UpdateRequest(); 
        req.setAction(AbstractUpdateRequest.ACTION.COMMIT, true, true); 
        req.add(docs); 
        UpdateResponse rsp = req.process(solr); 
        if (rsp.getStatus() != 0) { 
          LOG.warn("UpdateRequest returned the status " + rsp.getStatus()); 
        } 
      } else { 
        solr.add(docs); 
      } 
    } catch (Exception e) {
      // removed for brevity , don't do this at home
    } 
  }

  public static List getUserFolders(SolrServer solr, String folderId, 
    String username) { 
    List folderIds = new ArrayList(); 
    StringBuilder sb = new StringBuilder(); 

    SolrUtil.appendANDedTerms(sb, 
      SolrUtil.getQuotedQueryTerm(FolderSchemaField.USER, username),
      SolrUtil.getQuotedQueryTerm(FolderSchemaField.FOLDER_ID, folderId));

    QueryResponse queryResponse = getFolderQueryReponse(solr, sb.toString(), 1); 

    if (queryResponse != null) { 
      SolrDocumentList r = 
        (SolrDocumentList) queryResponse.getResponse().get(RESPONSE); 

      if (r.getNumFound() > 1) { 
        queryResponse = getFolderQueryReponse(solr, sb.toString(),
          (int) r.getNumFound()); 
        r = (SolrDocumentList) queryResponse.getResponse().get(RESPONSE); 
      } 

      for (SolrDocument solrDocument : r) { 
        String folder_id = 
          (String) solrDocument.getFieldValue(FolderSchemaField.FOLDER_ID 
                                                .getSName()); 
        folderIds.add(folder_id); 
      } 
    } 
    return folderIds; 
  } 

  public static void appendANDedTerms(StringBuilder sb, String... queryTerms) { 
    appendTerms(sb, DEFAULT_AND_OPERATOR_STRING, queryTerms); 
  } 

  public static void appendORedTerms(StringBuilder sb, String... queryTerms) { 
    appendTerms(sb, DEFAULT_OR_OPERATOR_STRING, queryTerms); 
  }

  private static void appendTerms(StringBuilder sBuilder, String operator, 
    String... queryTerms) { 
    StringBuilder sb = sBuilder; 
    if (sb == null) { 
      sb = new StringBuilder("("); 
    } else { 
      sb.append(sb.length() == 0 ? "(" : " ("); 
    } 
    String operatorStr = " " + operator.trim() + " "; 
    boolean first = true; 

    for (String queryTerm : queryTerms) { 
      if (null != queryTerm && queryTerm.length() > 0) { 
        /* 
         * ignore empty terms 
         */ 
        if (!first) { 
          sb.append(operatorStr); 
        } 
        first = false; 
        sb.append(queryTerm); 
      } 
    } 
    sb.append(")"); 
  }
}
  • Unsere Testdokumente repräsentieren Informationen über E-Mail-Ordner, daher haben wir ein Enum FolderSchemaField definiert, das den Zugriff auf die Felder etwas robuster gestaltet (siehe auch den Ausschnitt der Schemadefinition in Listing 2).
  • Es wurden Hilfsmethoden für die Erstellung von Abfragen (QueryBuilder) hinzugefügt (appendANDedTerms, appendORedTerms, getQuotedQueryTerm).
  • Zusätzlich haben wir eine Methode getUserFolders ergänzt, die die eigentliche Indexabfrage kapselt und nur mit den Parametern folderId und username operiert.
Listing 2

Der Beispieltest testSolrInsertFetchDelete in Listing 3 demonstriert, wie einfach es nun ist, auf den Index mit der Kombination aus SolrJ und unserer Hilfsklasse zuzugreifen. Der Testfall führt quasi einen kompletten CRUD-Zyklus für einen E-Mail-Ordner durch.

Listing 3
  @Test 
  public void testSolrInsertFetchDelete() { 
    SolrServer solr = SolrUtil.getNamedSolrServer(searchConfig, SOLR_SERVER); 
    SolrUtil.deleteByUser(solr, "me", true); 

    SolrUtil.addOrReplaceFolder(solr, "12345", "1234", "test", "me", 12, 12); 
    String queryStr = SolrUtil.getQuotedQueryTerm(SolrUtil.FolderSchemaField.USER, "me"); 
    QueryResponse q = SolrUtil.getFolderQueryReponse(solr, queryStr, 10); 

    System.out.println("Query time was " + q.getQTime()); 
    System.out.println("Elapsed time was " + q.getElapsedTime()); 

    SolrDocumentList mr = (SolrDocumentList) q.getResponse().get(SolrUtil.RESPONSE); 
    assertEquals(mr.getNumFound(), 1); 

    SolrUtil.deleteByQuery(solr, queryStr, false); 
    SolrUtil.closeConnections(solr); 
  }
Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.