Inhaltsconnector erstellen

Ein Inhaltsconnector ist ein Programm, mit dem die Daten im Repository eines Unternehmens durchsucht werden, um eine Datenquelle darzustellen. Google bietet Ihnen folgende Möglichkeiten, Inhaltsconnectors zu entwickeln:

  • Content Connector SDK Diese Option eignet sich gut, wenn Sie in Java programmieren. Dieses SDK ist ein Wrapper für die REST API, mit dem Sie schnell Connectors erstellen können. Weitere Informationen zum Erstellen eines Inhaltsconnectors mit dem SDK finden Sie im Abschnitt Mithilfe des Content Connector SDK Inhaltsconnectors erstellen.

  • Eine Low-Level-REST API oder API-Bibliotheken: Verwenden Sie diese Optionen, wenn Sie nicht in Java programmieren oder wenn Ihre Codebasis besser für eine REST API oder eine Bibliothek geeignet ist. Weitere Informationen zum Erstellen eines Inhaltsconnectors mit der REST API finden Sie im Abschnitt Mithilfe der REST API Inhaltsconnectors erstellen.

Mit einem typischen Inhaltsconnector werden die folgenden Aufgaben ausgeführt:

  1. Liest und verarbeitet Konfigurationsparameter.
  2. Diskrete Teile indexierbarer Daten, sogenannte Elemente, aus dem Inhalts-Repository eines Drittanbieters abrufen
  3. Aus ACLs, Metadaten und Inhaltsdaten indexierbare Elemente erstellen
  4. Elemente indexieren und in die Cloud Search-Datenquelle aufnehmen
  5. Optional: Benachrichtigungen über Änderungen aus dem Inhalts-Repository des Drittanbieters erkennen. Änderungsbenachrichtigungen werden in Indexierungsanfragen umgewandelt, um die Cloud Search-Datenquelle und das Repository des Drittanbieters synchron zu halten. Diese Aufgabe wird nur ausgeführt, wenn das Repository die Änderungserkennung unterstützt.

Mit dem Content Connector SDK Inhaltsconnectors erstellen

In den folgenden Abschnitten wird erläutert, wie Sie mit dem Content Connector SDK einen Inhaltsconnector erstellen.

Abhängigkeiten einrichten

Sie müssen bestimmte Abhängigkeiten in Ihre Build-Datei aufnehmen, um das SDK verwenden zu können. Klicken Sie unten auf einen Tab, um sich die Abhängigkeiten für Ihre Build-Umgebung anzusehen:

Maven

<dependency>
<groupId>com.google.enterprise.cloudsearch</groupId>
<artifactId>google-cloudsearch-indexing-connector-sdk</artifactId>
<version>v1-0.0.3</version>
</dependency>

Gradle

compile group: 'com.google.enterprise.cloudsearch',
        name: 'google-cloudsearch-indexing-connector-sdk',
        version: 'v1-0.0.3'

Connectorkonfiguration erstellen

Jeder Connector hat eine Konfigurationsdatei mit Parametern, die von ihm verwendet werden, u. a. die ID für Ihr Repository. Parameter werden als Schlüssel/Wert-Paare definiert, z. B. api.sourceId=1234567890abcdef.

Das Google Cloud Search SDK enthält mehrere von Google bereitgestellte Konfigurationsparameter, die von allen Connectors verwendet werden. Davon müssen Sie folgende in Ihrer Konfigurationsdatei deklarieren:

  • Für einen Inhaltsconnector benötigen Sie die Parameter api.sourceId und api.serviceAccountPrivateKeyFile, da diese den Speicherort Ihres Repositorys und des für den Zugriff nötigen privaten Schlüssels angeben.
  • Für einen Identitätsconnector benötigen Sie den Parameter api.identitySourceId, da dieser den Speicherort Ihrer externen Identitätsquelle angibt. Wenn Sie Nutzer synchronisieren, müssen Sie api.customerId auch als eindeutige ID für das Google Workspace-Konto Ihres Unternehmens deklarieren.

Wenn Sie die Standardwerte anderer von Google bereitgestellter Parameter nicht überschreiben möchten, müssen Sie sie auch nicht in Ihrer Konfigurationsdatei angeben. Weitere Informationen zu den von Google bereitgestellten Konfigurationsparametern, z. B. wie Sie bestimmte IDs und Schlüssel generieren, finden Sie in diesem Artikel.

Sie können auch eigene Repository-spezifische Parameter für Ihre Konfigurationsdatei definieren.

Konfigurationsdatei an den Connector übergeben

Legen Sie das Systemattribut config fest, um die Konfigurationsdatei an Ihren Connector zu übergeben. Dazu verwenden Sie beim Starten des Connectors das Argument -D. Im folgenden Beispiel wird der Connector gestartet und die Konfigurationsdatei MyConfig.properties verwendet:

java -classpath myconnector.jar;... -Dconfig=MyConfig.properties MyConnector

Wenn dieses Argument fehlt, versucht das SDK, auf eine Standardkonfigurationsdatei mit dem Namen connector-config.properties zuzugreifen.

Durchlaufstrategie festlegen

Die Hauptfunktion eines Inhaltsconnectors besteht darin, ein Repository zu durchsuchen und seine Daten zu indexieren. Die Durchlaufstrategie dafür muss auf die Größe und das Layout der Daten in Ihrem Repository abgestimmt sein. Sie können Ihre eigene entwerfen oder aus den folgenden im SDK implementierten wählen:

Durchlauf mit vollständiger Indexierung (Full Traversal)

Bei dieser Strategie wird das gesamte Repository gescannt und blind indexiert. Sie wird häufig verwendet, wenn das Repository klein ist und ein kompletter Durchlauf bei jeder Indexierung kein Problem darstellt.

Diese Durchlaufstrategie eignet sich für kleine Repositories, die mehr statische als nicht hierarchische Daten enthalten. Sie können sie auch verwenden, wenn die Änderungserkennung schwierig ist oder vom Repository nicht unterstützt wird.

Durchlauf mit Teilindexierung (List Traversal)

Bei dieser Strategie wird das gesamte Repository einschließlich aller untergeordneten Knoten gescannt, um den Status der einzelnen Elemente zu bestimmen. Anschließend führt der Connector einen zweiten Durchlauf aus und indexiert nur Elemente, die neu sind oder seit der letzten Indexierung aktualisiert wurden. Diese Strategie wird im Allgemeinen verwendet, um inkrementelle Updates an einem vorhandenen Index durchzuführen. So muss nicht bei jedem Update des Index ein vollständiger Durchlauf erfolgen.

Diese Durchlaufstrategie eignet sich, wenn die Änderungserkennung schwierig ist oder vom Repository nicht unterstützt wird. wenn Sie nicht hierarchische Daten haben oder wenn Sie mit sehr großen Datenmengen arbeiten.

Knotenbasierter Durchlauf mit Teilindexierung (Graph Traversal)

Bei dieser Strategie wird der gesamte übergeordnete Knoten gescannt, um den Status der einzelnen Elemente zu bestimmen. Anschließend führt der Connector einen zweiten Durchlauf aus und indexiert nur Elemente im Wurzelknoten, die neu sind oder seit der letzten Indexierung aktualisiert wurden. Dann übergibt der Connector alle untergeordneten IDs und indexiert die Elemente in den untergeordneten Knoten, die neu sind oder aktualisiert wurden. Der Connector geht rekursiv alle untergeordneten Knoten durch, bis alle Elemente abgearbeitet sind. Ein derartiger Durchlauf wird normalerweise für hierarchische Repositories verwendet, bei denen das Auflisten aller IDs nicht praktikabel ist.

Diese Strategie eignet sich, wenn Sie hierarchische Daten haben, die gecrawlt werden müssen, z. B. Serienverzeichnisse oder Webseiten.

Jede dieser Durchlaufstrategien wird im SDK durch eine Vorlagenklasse für Connectors implementiert. Sie können zwar auch eine eigene Durchlaufstrategie implementieren, mit diesen Vorlagen wird die Entwicklung Ihres Connectors jedoch erheblich beschleunigt. Wenn Sie mithilfe einer Vorlage einen Connector erstellen möchten, lesen Sie den zu Ihrer Durchlaufstrategie passenden Abschnitt:

Full Traversal-Connector mithilfe einer Vorlagenklasse erstellen

Dieser Abschnitt bezieht sich auf Code-Snippets aus dem Beispiel FullTraversalSample.

Einstiegspunkt des Connectors implementieren

Der Einstiegspunkt für einen Connector ist die Methode main(). Sie dient hauptsächlich dazu, eine Instanz der Klasse Application zu erstellen und die Methode start() aufzurufen, um den Connector auszuführen.

Verwenden Sie die Klasse IndexingApplication.Builder, um die Vorlage FullTraversalConnector zu instanziieren, bevor Sie application.start() aufrufen. Für FullTraversalConnector wird ein Repository-Objekt akzeptiert, dessen Methoden Sie implementieren. Das folgende Code-Snippet zeigt das für die Methode main():

FullTraversalSample.java
/**
 * This sample connector uses the Cloud Search SDK template class for a full
 * traversal connector.
 *
 * @param args program command line arguments
 * @throws InterruptedException thrown if an abort is issued during initialization
 */
public static void main(String[] args) throws InterruptedException {
  Repository repository = new SampleRepository();
  IndexingConnector connector = new FullTraversalConnector(repository);
  IndexingApplication application = new IndexingApplication.Builder(connector, args).build();
  application.start();
}

Nachdem Application.build von der Methode main() des Connectors aufgerufen wurde, wird die Methode initConfig() vom SDK im Hintergrund aufgerufen. Über die Methode initConfig() werden die folgenden Aufgaben ausgeführt:

  1. Die Methode Configuation.isInitialized() wird aufgerufen, um zu prüfen, ob Configuration noch nicht initialisiert wurde.
  2. Ein Configuration-Objekt wird mithilfe der von Google bereitgestellten Schlüssel/Wert-Paare initialisiert. Jedes dieser Paare wird in einem ConfigValue-Objekt innerhalb des Configuration-Objekts gespeichert.

Repository-Schnittstelle implementieren

Die einzige Aufgabe des Repository-Objekts besteht darin, Repository-Elemente zu durchsuchen und zu indexieren. Wenn Sie eine Vorlage verwenden, müssen Sie nur bestimmte Methoden in der Schnittstelle Repository überschreiben, um einen Inhaltsconnector zu erstellen. Welche das sind, hängt von der verwendeten Vorlage und der Durchlaufstrategie ab. Überschreiben Sie für FullTraversalConnector die folgenden Methoden:

  • Die Methode init(). Wenn Sie ein Daten-Repository einrichten und initialisieren möchten, überschreiben Sie die Methode init().

  • Die Methode getAllDocs(). Wenn alle Elemente in einem Datenrepository durchlaufen und indexiert werden sollen, überschreiben Sie die Methode getAllDocs(). Diese Methode wird bei jedem geplanten Durchlauf einmal aufgerufen, wie in Ihrer Konfiguration definiert.

  • Optional: Die Methode getChanges(). Wenn Ihr Repository die Änderungserkennung unterstützt, überschreiben Sie die Methode getChanges(). Sie wird für jeden geplanten inkrementellen Durchlauf (wie in Ihrer Konfiguration definiert) einmal aufgerufen, um die geänderten Elemente abzurufen und zu indexieren.

  • Optional: Die Methode close(). Wenn Sie eine Repository-Bereinigung ausführen müssen, überschreiben Sie die Methode close(). Sie wird einmal beim Herunterfahren des Connectors aufgerufen.

Für jede der Methoden des Repository-Objekts wird ein Objekt des Typs ApiOperation zurückgegeben. Ein ApiOperation-Objekt führt eine Aktion in Form eines einzelnen oder möglicherweise mehrerer Aufrufe der Methode IndexingService.indexItem() aus, um die tatsächliche Indexierung Ihres Repositorys zu veranlassen.

Benutzerdefinierte Konfigurationsparameter abrufen

Im Rahmen der Konfiguration der Konnektivität des Connectors müssen Sie alle benutzerdefinierten Parameter aus dem Configuration-Objekt abrufen. Diese Aufgabe wird normalerweise in der Methode init() der Klasse Repository ausgeführt.

Die Klasse Configuration bietet Ihnen mehrere Methoden, unterschiedliche Datentypen aus einer Konfiguration abzurufen. Bei jeder Methode wird ein ConfigValue-Objekt zurückgegeben. Anschließend verwenden Sie die Methode get() des ConfigValue-Objekts, um den tatsächlichen Wert abzurufen. Der folgende Ausschnitt aus FullTraversalSample zeigt, wie eine einzelne benutzerdefinierte Ganzzahl aus einem Configuration-Objekt abgerufen wird:

FullTraversalSample.java
@Override
public void init(RepositoryContext context) {
  log.info("Initializing repository");
  numberOfDocuments = Configuration.getInteger("sample.documentCount", 10).get();
}

Wenn Sie einen Parameter abrufen und parsen möchten, der mehrere Werte enthält, verwenden Sie einen Typ-Parser der Klasse Configuration, um die Daten in einzelne Blöcke zu parsen. Das folgende Snippet aus dem Connectorbeispiel des Tutorials zeigt, wie Sie mithilfe der Methode getMultiValue eine Liste mit Namen von GitHub-Repositories erhalten:

GithubRepository.java
ConfigValue<List<String>> repos = Configuration.getMultiValue(
    "github.repos",
    Collections.emptyList(),
    Configuration.STRING_PARSER);

Vollständigen Durchlauf durchführen

Überschreiben Sie getAllDocs(), um einen vollständigen Durchlauf (Full Traversal) durchzuführen und das gesamte Repository zu indexieren. An die Methode getAllDocs() kann ein Prüfpunkt übergeben werden. Dieser ermöglicht es, die Indexierung bei einem bestimmten Element fortzusetzen, sollte der Prozess unterbrochen werden. Führen Sie für jedes Element in Ihrem Repository die folgenden Schritte in der Methode getAllDocs() aus:

  1. Legen Sie die Berechtigungen fest.
  2. Legen Sie die Metadaten für das zu indexierende Element fest.
  3. Kombinieren Sie die Metadaten und das Element in einer indexierbaren RepositoryDoc-Klasse.
  4. Packen Sie jedes indexierbare Element in einen Iterator, der von der Methode getAllDocs() zurückgegeben wird. Beachten Sie, dass getAllDocs() genau genommen CheckpointCloseableIterable zurückgibt, eine Iteration des Objekts ApiOperation. Jedes Objekt steht für eine API-Anfrage gegenüber RepositoryDoc, z. B. für die Indexierung.

Wenn zu viele Elemente für einen einzigen Aufruf vorhanden sind, verwenden Sie einen Checkpoint und legen Sie hasMore(true) fest, um anzugeben, dass noch mehr Elemente für die Indexierung verfügbar sind.

Berechtigungen für ein Element festlegen

In Ihrem Repository wird eine Zugriffssteuerungsliste (Access Control List, ACL) verwendet, um die Nutzer oder Gruppen zu identifizieren, die Zugriff auf ein Element haben. Eine ACL besteht aus einer Liste mit den IDs der Gruppen oder Nutzer, die Zugriff auf das Element haben.

Sie müssen die von Ihrem Repository verwendete ACL duplizieren. So sorgen Sie dafür, dass nur Nutzer, die Zugriff auf ein Element haben, es auch in den Suchergebnissen sehen können. Die ACL für ein Element muss beim Indexieren angegeben werden, damit Google Cloud Search über die erforderlichen Informationen verfügt, um die korrekten Zugriffsberechtigungen für das Element bereitzustellen.

Das Content Connector SDK bietet eine Vielzahl von ACL-Klassen und ‑Methoden, mit denen sich die ACLs der meisten Repositories modellieren lassen. Sie müssen die ACL jedes Elements in Ihrem Repository analysieren und eine entsprechende ACL für Google Cloud Search erstellen, wenn Sie ein Element indexieren. Wenn für die ACL Ihres Repositorys Konzepte wie die ACL-Vererbung verwendet werden, kann es schwierig sein, sie zu modellieren. Weitere Informationen zu ACLs von Google Cloud Search finden Sie im Leitfaden ACLs zuordnen.

Hinweis:Die Cloud Search Indexing API unterstützt nur ACLs für einzelne Domains. Domainübergreifende ACLs werden nicht unterstützt. Verwenden Sie die Klasse Acl.Builder, um den Zugriff auf jedes einzelne Element mithilfe einer ACL zu regeln. Mit dem folgenden Code-Snippet aus dem Beispiel zum Durchlauf mit vollständiger Indexierung erhalten alle Nutzer, auch bekannt als Hauptkonten oder „principals“ (getCustomerPrincipal()), bei einer Suche die Erlaubnis, alle Elemente zu lesen, also „reader“ zu sein (.setReaders()).

FullTraversalSample.java
// Make the document publicly readable within the domain
Acl acl = new Acl.Builder()
    .setReaders(Collections.singletonList(Acl.getCustomerPrincipal()))
    .build();

Sie müssen genau wissen, wie ACLs funktionieren, um sie für das Repository richtig zu modellieren. Es ist möglich, dass Sie Dateien in einem Dateisystem indexieren, das eine Art Vererbungsmodell verwendet, bei dem Unterordner Berechtigungen von übergeordneten Ordnern erben. Für die Modellierung der ACL-Vererbung sind zusätzliche Angaben erforderlich. Weitere Informationen hierzu finden Sie im Leitfaden ACLs zuordnen.

Metadaten für ein Element festlegen

Metadaten werden in einem Item-Objekt gespeichert. Um ein Item-Objekt zu erstellen, benötigen Sie mindestens die folgenden Angaben: die eindeutige String-ID, den Elementtyp, die ACL, die URL und die Elementversion. Das folgende Code-Snippet zeigt, wie ein Item-Objekt mithilfe der Helper-Klasse IndexingItemBuilder erstellt wird.

FullTraversalSample.java
// Url is required. Use google.com as a placeholder for this sample.
String viewUrl = "https://www.google.com";

// Version is required, set to current timestamp.
byte[] version = Longs.toByteArray(System.currentTimeMillis());

// Using the SDK item builder class to create the document with appropriate attributes
// (this can be expanded to include metadata fields etc.)
Item item = IndexingItemBuilder.fromConfiguration(Integer.toString(id))
    .setItemType(IndexingItemBuilder.ItemType.CONTENT_ITEM)
    .setAcl(acl)
    .setSourceRepositoryUrl(IndexingItemBuilder.FieldOrValue.withValue(viewUrl))
    .setVersion(version)
    .build();

Indexierbares Element erstellen

Nachdem Sie die Metadaten für das Element festgelegt haben, können Sie mithilfe der Klasse RepositoryDoc.Builder das tatsächliche indexierbare Element erstellen. Im folgenden Beispiel wird die Vorgehensweise für ein einzelnes indexierbares Element gezeigt:

FullTraversalSample.java
// For this sample, content is just plain text
String content = String.format("Hello world from sample doc %d", id);
ByteArrayContent byteContent = ByteArrayContent.fromString("text/plain", content);

// Create the fully formed document
RepositoryDoc doc = new RepositoryDoc.Builder()
    .setItem(item)
    .setContent(byteContent, IndexingService.ContentFormat.TEXT)
    .build();

RepositoryDoc ist eine ApiOperation, die die eigentliche IndexingService.indexItem()-Anfrage ausführt.

Sie können auch die Methode setRequestMode() der Klasse RepositoryDoc.Builder verwenden, um die Indexierungsanfrage als ASYNCHRONOUS oder SYNCHRONOUS zu identifizieren:

ASYNCHRONOUS
Im asynchronen Modus ist die Latenz zwischen Indexierung und Ausgabe höher, dafür kann er größere Mengen an Indexierungsanfragen verarbeiten. Der asynchrone Modus empfiehlt sich für die anfängliche Indexierung (Backfill) des gesamten Repositorys.
SYNCHRONOUS
Im synchronen Modus ist die Latenz zwischen Indexierung und Ausgabe geringer, er eignet sich aber nur für begrenzte Durchsätze. Der synchrone Modus wird für die Indexierung von Updates und Änderungen am Repository empfohlen. Falls nichts festgelegt ist, wird standardmäßig der Modus SYNCHRONOUS verwendet.

Jedes indexierbare Element in einen Iterator verpacken

Die Methode getAllDocs() gibt Iterator zurück, genau genommen ein CheckpointCloseableIterable von RepositoryDoc-Objekten. Zum Erstellen und Zurückgeben eines Iterators können Sie die Klasse CheckpointClosableIterableImpl.Builder verwenden. Das folgende Code-Snippet verdeutlicht das.

FullTraversalSample.java
CheckpointCloseableIterable<ApiOperation> iterator =
  new CheckpointCloseableIterableImpl.Builder<>(allDocs).build();

Das SDK führt jeden Indexierungsaufruf aus, der im Iterator enthalten ist.

Nächste Schritte

Als Nächstes könnten Sie Folgendes tun:

List Traversal-Connector mithilfe einer Vorlagenklasse erstellen

Diese Warteschlange enthält IDs und optionale Hashwerte für jedes Element im Repository. Mit dem List Traversal-Connector werden Element-IDs einer Indexierungswarteschlange in Cloud Search hinzugefügt und nacheinander für die Indexierung abgerufen. In Google Cloud Search werden Warteschlangen verwaltet und Inhalte verglichen, um den Status der Elemente zu ermitteln, beispielsweise, ob eines aus dem Repository gelöscht wurde. Hier finden Sie weitere Informationen zur Indexierungswarteschlange in Cloud Search.

Dieser Abschnitt bezieht sich auf Code-Snippets aus dem Beispiel ListTraversalSample.

Einstiegspunkt des Connectors implementieren

Der Einstiegspunkt für einen Connector ist die Methode main(). Sie dient hauptsächlich dazu, eine Instanz der Klasse Application zu erstellen und die Methode start() aufzurufen, um den Connector auszuführen.

Verwenden Sie die Klasse IndexingApplication.Builder, um die Vorlage ListingConnector zu instanziieren, bevor Sie application.start() aufrufen. Für ListingConnector wird ein Repository-Objekt akzeptiert, dessen Methoden Sie implementieren. Das folgende Snippet zeigt, wie die Klasse ListingConnector und das dazugehörige Repository instanziiert werden:

ListTraversalSample.java
/**
 * This sample connector uses the Cloud Search SDK template class for a
 * list traversal connector.
 *
 * @param args program command line arguments
 * @throws InterruptedException thrown if an abort is issued during initialization
 */
public static void main(String[] args) throws InterruptedException {
  Repository repository = new SampleRepository();
  IndexingConnector connector = new ListingConnector(repository);
  IndexingApplication application = new IndexingApplication.Builder(connector, args).build();
  application.start();
}

Nachdem Application.build von der Methode main() des Connectors aufgerufen wurde, wird die Methode initConfig() vom SDK im Hintergrund aufgerufen. Die Methode initConfig():

  1. Die Methode Configuation.isInitialized() wird aufgerufen, um zu prüfen, ob Configuration noch nicht initialisiert wurde.
  2. Ein Configuration-Objekt wird mithilfe der von Google bereitgestellten Schlüssel/Wert-Paare initialisiert. Jedes dieser Paare wird in einem ConfigValue-Objekt innerhalb des Configuration-Objekts gespeichert.

Repository-Schnittstelle implementieren

Die einzige Aufgabe des Repository-Objekts besteht darin, Repository-Elemente zu durchsuchen und zu indexieren. Wenn Sie eine Vorlage verwenden, müssen Sie nur bestimmte Methoden in der Schnittstelle Repository überschreiben, um einen Inhaltsconnector zu erstellen. Welche das sind, hängt von der verwendeten Vorlage und der Durchlaufstrategie ab. Überschreiben Sie für ListingConnector die folgenden Methoden:

  • Die Methode init(). Wenn Sie ein Daten-Repository einrichten und initialisieren möchten, überschreiben Sie die Methode init().

  • Die Methode getIds(). Wenn Sie IDs und Hashwerte für alle Datensätze im Repository abrufen möchten, überschreiben Sie die Methode getIds().

  • Die Methode getDoc(). Wenn Sie im Index Elemente hinzufügen, bearbeiten oder löschen möchten, überschreiben Sie die Methode getDoc().

  • Optional: Die Methode getChanges(). Wenn Ihr Repository die Änderungserkennung unterstützt, überschreiben Sie die Methode getChanges(). Sie wird für jeden geplanten inkrementellen Durchlauf (wie in Ihrer Konfiguration definiert) einmal aufgerufen, um die geänderten Elemente abzurufen und zu indexieren.

  • Optional: Die Methode close(). Wenn Sie eine Repository-Bereinigung ausführen müssen, überschreiben Sie die Methode close(). Sie wird einmal beim Herunterfahren des Connectors aufgerufen.

Für jede der Methoden des Repository-Objekts wird ein Objekt des Typs ApiOperation zurückgegeben. Ein ApiOperation-Objekt führt eine Aktion in Form eines einzelnen oder möglicherweise mehrerer Aufrufe der Methode IndexingService.indexItem() aus, um die tatsächliche Indexierung Ihres Repositorys zu veranlassen.

Benutzerdefinierte Konfigurationsparameter abrufen

Im Rahmen der Konfiguration der Konnektivität des Connectors müssen Sie alle benutzerdefinierten Parameter aus dem Configuration-Objekt abrufen. Diese Aufgabe wird normalerweise in der Methode init() der Klasse Repository ausgeführt.

Die Klasse Configuration bietet Ihnen mehrere Methoden, unterschiedliche Datentypen aus einer Konfiguration abzurufen. Bei jeder Methode wird ein ConfigValue-Objekt zurückgegeben. Anschließend verwenden Sie die Methode get() des ConfigValue-Objekts, um den tatsächlichen Wert abzurufen. Der folgende Ausschnitt aus FullTraversalSample zeigt, wie eine einzelne benutzerdefinierte Ganzzahl aus einem Configuration-Objekt abgerufen wird:

FullTraversalSample.java
@Override
public void init(RepositoryContext context) {
  log.info("Initializing repository");
  numberOfDocuments = Configuration.getInteger("sample.documentCount", 10).get();
}

Wenn Sie einen Parameter abrufen und parsen möchten, der mehrere Werte enthält, verwenden Sie einen Typ-Parser der Klasse Configuration, um die Daten in einzelne Blöcke zu parsen. Das folgende Snippet aus dem Connectorbeispiel des Tutorials zeigt, wie Sie mithilfe der Methode getMultiValue eine Liste mit Namen von GitHub-Repositories erhalten:

GithubRepository.java
ConfigValue<List<String>> repos = Configuration.getMultiValue(
    "github.repos",
    Collections.emptyList(),
    Configuration.STRING_PARSER);

Listendurchlauf (List Traversal) durchführen

Überschreiben Sie die Methode getIds(), um IDs und Hashwerte für alle Datensätze im Repository abzurufen. An die Methode getIds() kann ein Prüfpunkt übergeben werden. Dieser ermöglicht es, die Indexierung bei einem bestimmten Element fortzusetzen, sollte der Prozess unterbrochen werden.

Als Nächstes überschreiben Sie die Methode getDoc(), um jedes Element in der Cloud Search-Indexierungswarteschlange zu verarbeiten.

Element-IDs und Hashwerte per Push übertragen

Überschreiben Sie getIds(), um die Element-IDs und die dazugehörigen Inhalts-Hashwerte aus dem Repository abzurufen. ID- und Hashwert-Paare werden dann in eine Push-Anfrage an die Cloud Search-Indexierungswarteschlange gepackt. Stamm- oder übergeordnete IDs werden normalerweise zuerst übertragen, gefolgt von untergeordneten IDs, bis die gesamte Hierarchie der Elemente verarbeitet wurde.

An die Methode getIds() kann ein Prüfpunkt übergeben werden, der das letzte zu indexierende Element darstellt. Dieser ermöglicht es, die Indexierung bei einem bestimmten Element fortzusetzen, sollte der Prozess unterbrochen werden. Führen Sie für jedes Element in Ihrem Repository die folgenden Schritte in der Methode getIds() aus:

  • Rufen Sie jede Element-ID und den zugehörigen Hashwert aus dem Repository ab.
  • Verpacken Sie jedes ID-Hashwert-Paar in eine PushItems-Klasse.
  • Kombinieren Sie alle PushItems in einem Iterator, der von der Methode getIds() zurückgegeben wird. Beachten Sie, dass getIds() genau genommen CheckpointCloseableIterable zurückgibt, eine Iteration des Objekts ApiOperation. Jedes Objekt steht für eine API-Anfrage gegenüber RepositoryDoc, z. B. für das Verschieben in die Warteschlange.

Im folgenden Code-Snippet sehen Sie, wie IDs und Hashwerte abgerufen und in eine PushItems-Klasse eingefügt werden. PushItems ist eine ApiOperation-Anfrage, mit der ein Element in die Cloud Search-Indexierungswarteschlange aufgenommen wird.

ListTraversalSample.java
PushItems.Builder allIds = new PushItems.Builder();
for (Map.Entry<Integer, Long> entry : this.documents.entrySet()) {
  String documentId = Integer.toString(entry.getKey());
  String hash = this.calculateMetadataHash(entry.getKey());
  PushItem item = new PushItem().setMetadataHash(hash);
  log.info("Pushing " + documentId);
  allIds.addPushItem(documentId, item);
}

Im folgenden Code-Snippet sehen Sie, wie Sie die Klasse PushItems.Builder verwenden, um die IDs und Hashwerte in eine einzige Push-ApiOperation zu verpacken.

ListTraversalSample.java
ApiOperation pushOperation = allIds.build();
CheckpointCloseableIterable<ApiOperation> iterator =
  new CheckpointCloseableIterableImpl.Builder<>(
      Collections.singletonList(pushOperation))
  .build();
return iterator;

Elemente werden zur weiteren Verarbeitung der Cloud Search-Indexierungswarteschlange hinzugefügt.

Alle Elemente abrufen und verarbeiten

Überschreiben Sie die Methode getDoc(), um jedes Element in der Indexierungswarteschlange von Cloud Search zu verarbeiten. Ein Element kann neu, geändert, unverändert oder nicht mehr im Quell-Repository vorhanden sein. Rufen Sie jedes neue oder geänderte Element ab und indexieren Sie es. Entfernen Sie Elemente aus dem Index, die nicht mehr im Quell-Repository vorhanden sind.

Die Methode getDoc() akzeptiert ein Element aus der Cloud Search-Indexierungswarteschlange. Führen Sie für jedes Element in der Warteschlange die folgenden Schritte in der Methode getDoc() aus:

  1. Prüfen Sie, ob im Repository die ID des Elements aus der Cloud Search-Indexierungswarteschlange vorhanden ist. Wenn nicht, löschen Sie das Element aus dem Index.

  2. Fragen Sie im Index den Status des Elements ab. Wenn er nicht geändert wurde (ACCEPTED), tun Sie nichts weiter.

  3. Indexieren Sie geänderte oder neu hinzugekommene Elemente:

    1. Legen Sie die Berechtigungen fest.
    2. Legen Sie die Metadaten für das zu indexierende Element fest.
    3. Kombinieren Sie die Metadaten und das Element in einer indexierbaren RepositoryDoc-Klasse.
    4. Geben Sie RepositoryDoc zurück.

Hinweis:Die Vorlage ListingConnector unterstützt nicht die Rückgabe von null für die Methode getDoc(). Die Rückgabe von null führt zu NullPointerException.

Umgang mit gelöschten Elementen

Im folgenden Code-Snippet wird gezeigt, wie Sie feststellen, ob ein Element im Repository vorhanden ist, und es gegebenenfalls löschen.

ListTraversalSample.java
String resourceName = item.getName();
int documentId = Integer.parseInt(resourceName);

if (!documents.containsKey(documentId)) {
  // Document no longer exists -- delete it
  log.info(() -> String.format("Deleting document %s", item.getName()));
  return ApiOperations.deleteItem(resourceName);
}

documents ist eine Datenstruktur, die das Repository darstellt. Wenn documentID nicht in documents gefunden wird, geben Sie APIOperations.deleteItem(resourceName) zurück, um das Element aus dem Index zu löschen.

Umgang mit unveränderten Elementen

Im folgenden Code-Snippet wird gezeigt, wie Sie den Status von Elementen in der Cloud Search-Indexierungswarteschlange abfragen und mit unveränderten Elementen umgehen.

ListTraversalSample.java
String currentHash = this.calculateMetadataHash(documentId);
if (this.canSkipIndexing(item, currentHash)) {
  // Document neither modified nor deleted, ack the push
  log.info(() -> String.format("Document %s not modified", item.getName()));
  PushItem pushItem = new PushItem().setType("NOT_MODIFIED");
  return new PushItems.Builder().addPushItem(resourceName, pushItem).build();
}

Um festzustellen, ob ein Element unverändert ist, überprüfen Sie seinen Status sowie andere Metadaten, die auf eine Änderung hinweisen können. In diesem Beispiel wird der Metadaten-Hash verwendet, um zu bestimmen, ob das Element geändert wurde.

ListTraversalSample.java
/**
 * Checks to see if an item is already up to date
 *
 * @param previousItem Polled item
 * @param currentHash  Metadata hash of the current github object
 * @return PushItem operation
 */
private boolean canSkipIndexing(Item previousItem, String currentHash) {
  if (previousItem.getStatus() == null || previousItem.getMetadata() == null) {
    return false;
  }
  String status = previousItem.getStatus().getCode();
  String previousHash = previousItem.getMetadata().getHash();
  return "ACCEPTED".equals(status)
      && previousHash != null
      && previousHash.equals(currentHash);
}

Berechtigungen für ein Element festlegen

In Ihrem Repository wird eine Zugriffssteuerungsliste (Access Control List, ACL) verwendet, um die Nutzer oder Gruppen zu identifizieren, die Zugriff auf ein Element haben. Eine ACL besteht aus einer Liste mit den IDs der Gruppen oder Nutzer, die Zugriff auf das Element haben.

Sie müssen die von Ihrem Repository verwendete ACL duplizieren. So sorgen Sie dafür, dass nur Nutzer, die Zugriff auf ein Element haben, es auch in den Suchergebnissen sehen können. Die ACL für ein Element muss beim Indexieren angegeben werden, damit Google Cloud Search über die erforderlichen Informationen verfügt, um die korrekten Zugriffsberechtigungen für das Element bereitzustellen.

Das Content Connector SDK bietet eine Vielzahl von ACL-Klassen und ‑Methoden, mit denen sich die ACLs der meisten Repositories modellieren lassen. Sie müssen die ACL jedes Elements in Ihrem Repository analysieren und eine entsprechende ACL für Google Cloud Search erstellen, wenn Sie ein Element indexieren. Wenn für die ACL Ihres Repositorys Konzepte wie die ACL-Vererbung verwendet werden, kann es schwierig sein, sie zu modellieren. Weitere Informationen zu ACLs von Google Cloud Search finden Sie im Leitfaden ACLs zuordnen.

Hinweis:Die Cloud Search Indexing API unterstützt nur ACLs für einzelne Domains. Domainübergreifende ACLs werden nicht unterstützt. Verwenden Sie die Klasse Acl.Builder, um den Zugriff auf jedes einzelne Element mithilfe einer ACL zu regeln. Mit dem folgenden Code-Snippet aus dem Beispiel zum Durchlauf mit vollständiger Indexierung erhalten alle Nutzer, auch bekannt als Hauptkonten oder „principals“ (getCustomerPrincipal()), bei einer Suche die Erlaubnis, alle Elemente zu lesen, also „reader“ zu sein (.setReaders()).

FullTraversalSample.java
// Make the document publicly readable within the domain
Acl acl = new Acl.Builder()
    .setReaders(Collections.singletonList(Acl.getCustomerPrincipal()))
    .build();

Sie müssen genau wissen, wie ACLs funktionieren, um sie für das Repository richtig zu modellieren. Es ist möglich, dass Sie Dateien in einem Dateisystem indexieren, das eine Art Vererbungsmodell verwendet, bei dem Unterordner Berechtigungen von übergeordneten Ordnern erben. Für die Modellierung der ACL-Vererbung sind zusätzliche Angaben erforderlich. Weitere Informationen hierzu finden Sie im Leitfaden ACLs zuordnen.

Metadaten für ein Element festlegen

Metadaten werden in einem Item-Objekt gespeichert. Um ein Item-Objekt zu erstellen, benötigen Sie mindestens die folgenden Angaben: die eindeutige String-ID, den Elementtyp, die ACL, die URL und die Elementversion. Das folgende Code-Snippet zeigt, wie ein Item-Objekt mithilfe der Helper-Klasse IndexingItemBuilder erstellt wird.

ListTraversalSample.java
// Url is required. Use google.com as a placeholder for this sample.
String viewUrl = "https://www.google.com";

// Version is required, set to current timestamp.
byte[] version = Longs.toByteArray(System.currentTimeMillis());

// Set metadata hash so queue can detect changes
String metadataHash = this.calculateMetadataHash(documentId);

// Using the SDK item builder class to create the document with
// appropriate attributes. This can be expanded to include metadata
// fields etc.
Item item = IndexingItemBuilder.fromConfiguration(Integer.toString(documentId))
    .setItemType(IndexingItemBuilder.ItemType.CONTENT_ITEM)
    .setAcl(acl)
    .setSourceRepositoryUrl(IndexingItemBuilder.FieldOrValue.withValue(viewUrl))
    .setVersion(version)
    .setHash(metadataHash)
    .build();

Indexierbares Element erstellen

Nachdem Sie die Metadaten für das Element festgelegt haben, können Sie mithilfe der Klasse RepositoryDoc.Builder das tatsächliche indexierbare Element erstellen. Im folgenden Beispiel wird die Vorgehensweise für ein einzelnes indexierbares Element gezeigt:

ListTraversalSample.java
// For this sample, content is just plain text
String content = String.format("Hello world from sample doc %d", documentId);
ByteArrayContent byteContent = ByteArrayContent.fromString("text/plain", content);

// Create the fully formed document
RepositoryDoc doc = new RepositoryDoc.Builder()
    .setItem(item)
    .setContent(byteContent, IndexingService.ContentFormat.TEXT)
    .build();

RepositoryDoc ist eine ApiOperation, die die eigentliche IndexingService.indexItem()-Anfrage ausführt.

Sie können auch die Methode setRequestMode() der Klasse RepositoryDoc.Builder verwenden, um die Indexierungsanfrage als ASYNCHRONOUS oder SYNCHRONOUS zu identifizieren:

ASYNCHRONOUS
Im asynchronen Modus ist die Latenz zwischen Indexierung und Ausgabe höher, dafür kann er größere Mengen an Indexierungsanfragen verarbeiten. Der asynchrone Modus empfiehlt sich für die anfängliche Indexierung (Backfill) des gesamten Repositorys.
SYNCHRONOUS
Im synchronen Modus ist die Latenz zwischen Indexierung und Ausgabe geringer, er eignet sich aber nur für begrenzte Durchsätze. Der synchrone Modus wird für die Indexierung von Updates und Änderungen am Repository empfohlen. Falls nichts festgelegt ist, wird standardmäßig der Modus SYNCHRONOUS verwendet.

Nächste Schritte

Als Nächstes könnten Sie Folgendes tun:

Graph Traversal-Connector mithilfe einer Vorlagenklasse erstellen

Diese Warteschlange enthält IDs und optionale Hashwerte für jedes Element im Repository. Mit dem Graph Traversal-Connector werden die Element-IDs in eine Cloud Search-Indexierungswarteschlange verschoben und nacheinander für die Indexierung abgerufen. In Google Cloud Search werden Warteschlangen verwaltet und Inhalte verglichen, um den Status der Elemente zu ermitteln, beispielsweise, ob eines aus dem Repository gelöscht wurde. Hier finden Sie weitere Informationen zur Indexierungswarteschlange in Google Cloud Search.

Während der Indexierung wird der Artikelinhalt aus dem Datenrepository abgerufen und alle untergeordneten Element-IDs werden in die Warteschlange verschoben. Der Connector verarbeitet rekursiv die übergeordneten und untergeordneten IDs, bis alle Elemente verarbeitet sind.

Dieser Abschnitt bezieht sich auf Code-Snippets aus dem Beispiel GraphTraversalSample.

Einstiegspunkt des Connectors implementieren

Der Einstiegspunkt für einen Connector ist die Methode main(). Sie dient hauptsächlich dazu, eine Instanz der Klasse Application zu erstellen und die Methode start() aufzurufen, um den Connector auszuführen.

Verwenden Sie die Klasse IndexingApplication.Builder, um die Vorlage ListingConnector zu instanziieren, bevor Sie application.start() aufrufen. Für ListingConnector wird ein Repository-Objekt akzeptiert, dessen Methoden Sie implementieren.

Das folgende Snippet zeigt, wie die Klasse ListingConnector und das dazugehörige Repository instanziiert werden:

GraphTraversalSample.java
/**
 * This sample connector uses the Cloud Search SDK template class for a graph
 * traversal connector.
 *
 * @param args program command line arguments
 * @throws InterruptedException thrown if an abort is issued during initialization
 */
public static void main(String[] args) throws InterruptedException {
  Repository repository = new SampleRepository();
  IndexingConnector connector = new ListingConnector(repository);
  IndexingApplication application = new IndexingApplication.Builder(connector, args).build();
  application.start();
}

Nachdem Application.build von der Methode main() des Connectors aufgerufen wurde, wird die Methode initConfig() vom SDK im Hintergrund aufgerufen. Die Methode initConfig():

  1. Die Methode Configuation.isInitialized() wird aufgerufen, um zu prüfen, ob Configuration noch nicht initialisiert wurde.
  2. Ein Configuration-Objekt wird mithilfe der von Google bereitgestellten Schlüssel/Wert-Paare initialisiert. Jedes dieser Paare wird in einem ConfigValue-Objekt innerhalb des Configuration-Objekts gespeichert.

Repository-Schnittstelle implementieren

Die einzige Aufgabe des Repository-Objekts besteht darin, Repository-Elemente zu durchsuchen und zu indexieren. Wenn Sie eine Vorlage verwenden, müssen Sie nur bestimmte Methoden in der Schnittstelle Repository überschreiben, um einen Inhaltsconnector zu erstellen. Welche das sind, hängt von der verwendeten Vorlage und der Durchlaufstrategie ab. Für ListingConnector überschreiben Sie die folgenden Methoden:

  • Die Methode init(). Wenn Sie ein Daten-Repository einrichten und initialisieren möchten, überschreiben Sie die Methode init().

  • Die Methode getIds(). Wenn Sie IDs und Hashwerte für alle Datensätze im Repository abrufen möchten, überschreiben Sie die Methode getIds().

  • Die Methode getDoc(). Wenn Sie im Index Elemente hinzufügen, bearbeiten oder löschen möchten, überschreiben Sie die Methode getDoc().

  • Optional: Die Methode getChanges(). Wenn Ihr Repository die Änderungserkennung unterstützt, überschreiben Sie die Methode getChanges(). Sie wird für jeden geplanten inkrementellen Durchlauf (wie in Ihrer Konfiguration definiert) einmal aufgerufen, um die geänderten Elemente abzurufen und zu indexieren.

  • Optional: Die Methode close(). Wenn Sie eine Repository-Bereinigung ausführen müssen, überschreiben Sie die Methode close(). Sie wird einmal beim Herunterfahren des Connectors aufgerufen.

Für jede der Methoden des Repository-Objekts wird ein Objekt des Typs ApiOperation zurückgegeben. Ein ApiOperation-Objekt führt eine Aktion in Form eines einzelnen oder möglicherweise mehrerer Aufrufe der Methode IndexingService.indexItem() aus, um die tatsächliche Indexierung Ihres Repositorys zu veranlassen.

Benutzerdefinierte Konfigurationsparameter abrufen

Im Rahmen der Konfiguration der Konnektivität des Connectors müssen Sie alle benutzerdefinierten Parameter aus dem Configuration-Objekt abrufen. Diese Aufgabe wird normalerweise in der Methode init() der Klasse Repository ausgeführt.

Die Klasse Configuration bietet Ihnen mehrere Methoden, unterschiedliche Datentypen aus einer Konfiguration abzurufen. Bei jeder Methode wird ein ConfigValue-Objekt zurückgegeben. Anschließend verwenden Sie die Methode get() des ConfigValue-Objekts, um den tatsächlichen Wert abzurufen. Der folgende Ausschnitt aus FullTraversalSample zeigt, wie eine einzelne benutzerdefinierte Ganzzahl aus einem Configuration-Objekt abgerufen wird:

FullTraversalSample.java
@Override
public void init(RepositoryContext context) {
  log.info("Initializing repository");
  numberOfDocuments = Configuration.getInteger("sample.documentCount", 10).get();
}

Wenn Sie einen Parameter abrufen und parsen möchten, der mehrere Werte enthält, verwenden Sie einen Typ-Parser der Klasse Configuration, um die Daten in einzelne Blöcke zu parsen. Das folgende Snippet aus dem Connectorbeispiel des Tutorials zeigt, wie Sie mithilfe der Methode getMultiValue eine Liste mit Namen von GitHub-Repositories erhalten:

GithubRepository.java
ConfigValue<List<String>> repos = Configuration.getMultiValue(
    "github.repos",
    Collections.emptyList(),
    Configuration.STRING_PARSER);

Graphendurchlauf durchführen

Überschreiben Sie die Methode getIds(), um IDs und Hashwerte für alle Datensätze im Repository abzurufen. An die Methode getIds() kann ein Prüfpunkt übergeben werden. Dieser ermöglicht es, die Indexierung bei einem bestimmten Element fortzusetzen, sollte der Prozess unterbrochen werden.

Als Nächstes überschreiben Sie die Methode getDoc(), um jedes Element in der Cloud Search-Indexierungswarteschlange zu verarbeiten.

Element-IDs und Hashwerte per Push übertragen

Überschreiben Sie getIds(), um die Element-IDs und die dazugehörigen Inhalts-Hashwerte aus dem Repository abzurufen. ID- und Hashwert-Paare werden dann in eine Push-Anfrage an die Cloud Search-Indexierungswarteschlange gepackt. Stamm- oder übergeordnete IDs werden normalerweise zuerst übertragen, gefolgt von untergeordneten IDs, bis die gesamte Hierarchie der Elemente verarbeitet wurde.

An die Methode getIds() kann ein Prüfpunkt übergeben werden, der das letzte zu indexierende Element darstellt. Dieser ermöglicht es, die Indexierung bei einem bestimmten Element fortzusetzen, sollte der Prozess unterbrochen werden. Führen Sie für jedes Element in Ihrem Repository die folgenden Schritte in der Methode getIds() aus:

  • Rufen Sie jede Element-ID und den zugehörigen Hashwert aus dem Repository ab.
  • Verpacken Sie jedes ID-Hashwert-Paar in eine PushItems-Klasse.
  • Kombinieren Sie alle PushItems in einem Iterator, der von der Methode getIds() zurückgegeben wird. Beachten Sie, dass getIds() genau genommen CheckpointCloseableIterable zurückgibt, eine Iteration des Objekts ApiOperation. Jedes Objekt steht für eine API-Anfrage gegenüber RepositoryDoc, z. B. für das Verschieben in die Warteschlange.

Im folgenden Code-Snippet sehen Sie, wie IDs und Hashwerte abgerufen und in eine PushItems-Klasse eingefügt werden. PushItems ist eine ApiOperation-Anfrage, mit der ein Element in die Cloud Search-Indexierungswarteschlange aufgenommen wird.

GraphTraversalSample.java
PushItems.Builder allIds = new PushItems.Builder();
PushItem item = new PushItem();
allIds.addPushItem("root", item);

Im folgenden Code-Snippet sehen Sie, wie Sie die Klasse PushItems.Builder verwenden, um die IDs und Hashwerte in eine einzige Push-ApiOperation zu verpacken.

GraphTraversalSample.java
ApiOperation pushOperation = allIds.build();
CheckpointCloseableIterable<ApiOperation> iterator =
  new CheckpointCloseableIterableImpl.Builder<>(
      Collections.singletonList(pushOperation))
  .build();

Elemente werden zur weiteren Verarbeitung der Cloud Search-Indexierungswarteschlange hinzugefügt.

Alle Elemente abrufen und verarbeiten

Überschreiben Sie die Methode getDoc(), um jedes Element in der Indexierungswarteschlange von Cloud Search zu verarbeiten. Ein Element kann neu, geändert, unverändert oder nicht mehr im Quell-Repository vorhanden sein. Rufen Sie jedes neue oder geänderte Element ab und indexieren Sie es. Entfernen Sie Elemente aus dem Index, die nicht mehr im Quell-Repository vorhanden sind.

Die Methode getDoc() akzeptiert ein Element aus der Cloud Search-Indexierungswarteschlange. Führen Sie für jedes Element in der Warteschlange die folgenden Schritte in der Methode getDoc() aus:

  1. Prüfen Sie, ob im Repository die ID des Elements aus der Cloud Search-Indexierungswarteschlange vorhanden ist. Wenn nicht, löschen Sie das Element aus dem Index. Wenn das Element vorhanden ist, fahren Sie mit dem nächsten Schritt fort.

  2. Indexieren Sie geänderte oder neu hinzugekommene Elemente:

    1. Legen Sie die Berechtigungen fest.
    2. Legen Sie die Metadaten für das zu indexierende Element fest.
    3. Kombinieren Sie die Metadaten und das Element in einer indexierbaren RepositoryDoc-Klasse.
    4. Fügen Sie die untergeordneten IDs zur weiteren Verarbeitung der Cloud Search-Indexierungswarteschlange hinzu.
    5. Geben Sie RepositoryDoc zurück.

Umgang mit gelöschten Elementen

Im folgenden Code-Snippet wird gezeigt, wie Sie feststellen, ob ein Element im Index vorhanden ist, und es gegebenenfalls löschen.

GraphTraversalSample.java
String resourceName = item.getName();
if (documentExists(resourceName)) {
  return buildDocumentAndChildren(resourceName);
}
// Document doesn't exist, delete it
log.info(() -> String.format("Deleting document %s", resourceName));
return ApiOperations.deleteItem(resourceName);

Berechtigungen für ein Element festlegen

In Ihrem Repository wird eine Zugriffssteuerungsliste (Access Control List, ACL) verwendet, um die Nutzer oder Gruppen zu identifizieren, die Zugriff auf ein Element haben. Eine ACL besteht aus einer Liste mit den IDs der Gruppen oder Nutzer, die Zugriff auf das Element haben.

Sie müssen die von Ihrem Repository verwendete ACL duplizieren. So sorgen Sie dafür, dass nur Nutzer, die Zugriff auf ein Element haben, es auch in den Suchergebnissen sehen können. Die ACL für ein Element muss beim Indexieren angegeben werden, damit Google Cloud Search über die erforderlichen Informationen verfügt, um die korrekten Zugriffsberechtigungen für das Element bereitzustellen.

Das Content Connector SDK bietet eine Vielzahl von ACL-Klassen und ‑Methoden, mit denen sich die ACLs der meisten Repositories modellieren lassen. Sie müssen die ACL jedes Elements in Ihrem Repository analysieren und eine entsprechende ACL für Google Cloud Search erstellen, wenn Sie ein Element indexieren. Wenn für die ACL Ihres Repositorys Konzepte wie die ACL-Vererbung verwendet werden, kann es schwierig sein, sie zu modellieren. Weitere Informationen zu ACLs von Google Cloud Search finden Sie im Leitfaden ACLs zuordnen.

Hinweis:Die Cloud Search Indexing API unterstützt nur ACLs für einzelne Domains. Domainübergreifende ACLs werden nicht unterstützt. Verwenden Sie die Klasse Acl.Builder, um den Zugriff auf jedes einzelne Element mithilfe einer ACL zu regeln. Mit dem folgenden Code-Snippet aus dem Beispiel zum Durchlauf mit vollständiger Indexierung erhalten alle Nutzer, auch bekannt als Hauptkonten oder „principals“ (getCustomerPrincipal()), bei einer Suche die Erlaubnis, alle Elemente zu lesen, also „reader“ zu sein (.setReaders()).

FullTraversalSample.java
// Make the document publicly readable within the domain
Acl acl = new Acl.Builder()
    .setReaders(Collections.singletonList(Acl.getCustomerPrincipal()))
    .build();

Sie müssen genau wissen, wie ACLs funktionieren, um sie für das Repository richtig zu modellieren. Es ist möglich, dass Sie Dateien in einem Dateisystem indexieren, das eine Art Vererbungsmodell verwendet, bei dem Unterordner Berechtigungen von übergeordneten Ordnern erben. Für die Modellierung der ACL-Vererbung sind zusätzliche Angaben erforderlich. Weitere Informationen hierzu finden Sie im Leitfaden ACLs zuordnen.

Metadaten für ein Element festlegen

Metadaten werden in einem Item-Objekt gespeichert. Um ein Item-Objekt zu erstellen, benötigen Sie mindestens die folgenden Angaben: die eindeutige String-ID, den Elementtyp, die ACL, die URL und die Elementversion. Das folgende Code-Snippet zeigt, wie ein Item-Objekt mithilfe der Helper-Klasse IndexingItemBuilder erstellt wird.

GraphTraversalSample.java
// Url is required. Use google.com as a placeholder for this sample.
String viewUrl = "https://www.google.com";

// Version is required, set to current timestamp.
byte[] version = Longs.toByteArray(System.currentTimeMillis());

// Using the SDK item builder class to create the document with
// appropriate attributes. This can be expanded to include metadata
// fields etc.
Item item = IndexingItemBuilder.fromConfiguration(documentId)
    .setItemType(IndexingItemBuilder.ItemType.CONTENT_ITEM)
    .setAcl(acl)
    .setSourceRepositoryUrl(IndexingItemBuilder.FieldOrValue.withValue(viewUrl))
    .setVersion(version)
    .build();

Indexierbares Element erstellen

Nachdem Sie die Metadaten für das Element festgelegt haben, können Sie mithilfe der Klasse RepositoryDoc.Builder das tatsächliche indexierbare Element erstellen. Im folgenden Beispiel wird die Vorgehensweise für ein einzelnes indexierbares Element gezeigt:

GraphTraversalSample.java
// For this sample, content is just plain text
String content = String.format("Hello world from sample doc %s", documentId);
ByteArrayContent byteContent = ByteArrayContent.fromString("text/plain", content);

RepositoryDoc.Builder docBuilder = new RepositoryDoc.Builder()
    .setItem(item)
    .setContent(byteContent, IndexingService.ContentFormat.TEXT);

RepositoryDoc ist eine ApiOperation, die die eigentliche IndexingService.indexItem()-Anfrage ausführt.

Sie können auch die Methode setRequestMode() der Klasse RepositoryDoc.Builder verwenden, um die Indexierungsanfrage als ASYNCHRONOUS oder SYNCHRONOUS zu identifizieren:

ASYNCHRONOUS
Im asynchronen Modus ist die Latenz zwischen Indexierung und Ausgabe höher, dafür kann er größere Mengen an Indexierungsanfragen verarbeiten. Der asynchrone Modus empfiehlt sich für die anfängliche Indexierung (Backfill) des gesamten Repositorys.
SYNCHRONOUS
Im synchronen Modus ist die Latenz zwischen Indexierung und Ausgabe geringer, er eignet sich aber nur für begrenzte Durchsätze. Der synchrone Modus wird für die Indexierung von Updates und Änderungen am Repository empfohlen. Falls nichts festgelegt ist, wird standardmäßig der Modus SYNCHRONOUS verwendet.

Untergeordnete IDs in der Cloud Search-Indexierungswarteschlange platzieren

Im folgenden Code-Snippet wird gezeigt, wie die untergeordneten IDs für das derzeit verarbeitete übergeordnete Element in die Warteschlange der Verarbeitung aufgenommen werden. Diese IDs werden verarbeitet, nachdem das übergeordnete Element indexiert wurde.

GraphTraversalSample.java
// Queue the child nodes to visit after indexing this document
Set<String> childIds = getChildItemNames(documentId);
for (String id : childIds) {
  log.info(() -> String.format("Pushing child node %s", id));
  PushItem pushItem = new PushItem();
  docBuilder.addChildId(id, pushItem);
}

RepositoryDoc doc = docBuilder.build();

Nächste Schritte

Als Nächstes könnten Sie Folgendes tun:

Mithilfe der REST API Inhaltsconnectors erstellen

In den folgenden Abschnitten wird erläutert, wie Sie mithilfe der REST API einen Inhaltsconnector erstellen.

Durchlaufstrategie festlegen

Die Hauptfunktion eines Inhaltsconnectors besteht darin, ein Repository zu durchsuchen und seine Daten zu indexieren. Die Durchlaufstrategie dafür muss auf die Größe und das Layout der Daten in Ihrem Repository abgestimmt sein. Es gibt drei gängige Durchlaufstrategien:

Durchlauf mit vollständiger Indexierung (Full Traversal)

Bei dieser Strategie wird das gesamte Repository gescannt und blind indexiert. Sie wird häufig verwendet, wenn das Repository klein ist und ein kompletter Durchlauf bei jeder Indexierung kein Problem darstellt.

Diese Durchlaufstrategie eignet sich für kleine Repositories, die mehr statische als nicht hierarchische Daten enthalten. Sie können sie auch verwenden, wenn die Änderungserkennung schwierig ist oder vom Repository nicht unterstützt wird.

Durchlauf mit Teilindexierung (List Traversal)

Bei dieser Strategie wird das gesamte Repository einschließlich aller untergeordneten Knoten gescannt, um den Status der einzelnen Elemente zu bestimmen. Anschließend führt der Connector einen zweiten Durchlauf aus und indexiert nur Elemente, die neu sind oder seit der letzten Indexierung aktualisiert wurden. Diese Strategie wird im Allgemeinen verwendet, um inkrementelle Updates an einem vorhandenen Index durchzuführen. So muss nicht bei jedem Update des Index ein vollständiger Durchlauf erfolgen.

Diese Durchlaufstrategie eignet sich, wenn die Änderungserkennung schwierig ist oder vom Repository nicht unterstützt wird. wenn Sie nicht hierarchische Daten haben oder wenn Sie mit sehr großen Datenmengen arbeiten.

Knotenbasierter Durchlauf mit Teilindexierung (Graph Traversal)

Bei dieser Strategie wird der gesamte übergeordnete Knoten gescannt, um den Status der einzelnen Elemente zu bestimmen. Anschließend führt der Connector einen zweiten Durchlauf aus und indexiert nur Elemente im Wurzelknoten, die neu sind oder seit der letzten Indexierung aktualisiert wurden. Dann übergibt der Connector alle untergeordneten IDs und indexiert die Elemente in den untergeordneten Knoten, die neu sind oder aktualisiert wurden. Der Connector geht rekursiv alle untergeordneten Knoten durch, bis alle Elemente abgearbeitet sind. Ein derartiger Durchlauf wird normalerweise für hierarchische Repositories verwendet, bei denen das Auflisten aller IDs nicht praktikabel ist.

Diese Strategie eignet sich, wenn Sie hierarchische Daten haben, die gecrawlt werden müssen, z. B. Serienverzeichnisse oder Webseiten.

Durchlaufstrategie und Indexelemente implementieren

Jedes indexierbare Element für Cloud Search wird in der Cloud Search API als Element bezeichnet. Ein Element kann eine Datei, ein Ordner, eine Zeile in einer CSV-Datei oder ein Datensatz sein.

Sobald Ihr Schema registriert ist, können Sie den Index so befüllen:

  1. Optional: Verwenden Sie items.upload, um Dateien mit mehr als 100 KiB für die Indexierung hochzuladen. Bei kleineren Dateien betten Sie die Inhalte als inlineContent mithilfe von items.index ein.

  2. Optional: Verwenden Sie media.upload, um Mediendateien für die Indexierung hochzuladen.

  3. Verwenden Sie items.index zum Indexieren des Elements. Wenn für Ihr Schema beispielsweise die Objektdefinition aus dem Filmschema verwendet wurde, würde eine Indexierungsanfrage für ein einzelnes Element folgendermaßen aussehen:

    {
      "name": "datasource/<data_source_id>/items/titanic",
      "acl": {
        "readers": [
          {
            "gsuitePrincipal": {
              "gsuiteDomain": true
            }
          }
        ]
      },
      "metadata": {
        "title": "Titanic",
        "viewUrl": "http://www.imdb.com/title/tt2234155/?ref_=nv_sr_1",
        "objectType": "movie"
      },
      "structuredData": {
        "object": {
          "properties": [
            {
              "name": "movieTitle",
              "textValues": {
                "values": [
                  "Titanic"
                ]
              }
            },
            {
              "name": "releaseDate",
              "dateValues": {
                "values": [
                  {
                    "year": 1997,
                    "month": 12,
                    "day": 19
                  }
                ]
              }
            },
            {
              "name": "actorName",
              "textValues": {
                "values": [
                  "Leonardo DiCaprio",
                  "Kate Winslet",
                  "Billy Zane"
                ]
              }
            },
            {
              "name": "genre",
              "enumValues": {
                "values": [
                  "Drama",
                  "Action"
                ]
              }
            },
            {
              "name": "userRating",
              "integerValues": {
                "values": [
                  8
                ]
              }
            },
            {
              "name": "mpaaRating",
              "textValues": {
                "values": [
                  "PG-13"
                ]
              }
            },
            {
              "name": "duration",
              "textValues": {
                "values": [
                  "3 h 14 min"
                ]
              }
            }
          ]
        }
      },
      "content": {
        "inlineContent": "A seventeen-year-old aristocrat falls in love with a kind but poor artist aboard the luxurious, ill-fated R.M.S. Titanic.",
        "contentFormat": "TEXT"
      },
      "version": "01",
      "itemType": "CONTENT_ITEM"
    }
    
  4. Optional: Mit items.get-Aufrufen können Sie prüfen, ob ein Element indexiert wurde.

Um das gesamte Repository regelmäßig neu zu indexieren, führen Sie einen Full Traversal durch. Für einen List Traversal oder Graph Traversal müssen Sie Code für den Umgang mit Repository-Änderungen implementieren.

Umgang mit Repository-Änderungen

Sie können jedes Element aus einem Repository regelmäßig abrufen und indexieren, um eine vollständige Indexierung zu erreichen. Mit einer vollständigen Indexierung lässt sich dafür sorgen, dass Ihr Index immer auf dem neuesten Stand ist. Sie kann jedoch sehr kostspielig sein, wenn das Repository sehr groß oder hierarchisch strukturiert ist.

Anstatt ein gesamtes Repository regelmäßig mit Indexaufrufen zu indexieren, können Sie auch die Cloud Search-Indexierungswarteschlange verwenden, um Änderungen nachzuverfolgen und nur geänderte Elemente zu indexieren. Mithilfe von items.push-Anfragen lassen sich der Warteschlange für spätere Abfragen und Updates Elemente hinzufügen. Weitere Informationen zur Cloud Search-Indexierungswarteschlange finden Sie in diesem Leitfaden.

Weitere Informationen zur Google Cloud Search API finden Sie in diesem Artikel.