Criar um conector de conteúdo

Um conector de conteúdo é um programa de software usado para transferir dados no repositório da empresa e preencher uma fonte de dados. O Google oferece as seguintes opções para desenvolvimento de conectores de conteúdo:

  • O SDK do Content Connector. Essa é uma boa opção se você está programando em Java. O SDK do Content Connector é um wrapper em torno da API REST que permite criar conectores rapidamente. Para criar um conector de conteúdo usando o SDK, consulte Criar um conector de conteúdo usando o SDK do Content Connector.

  • Uma API REST de baixo nível ou bibliotecas de API: use essas opções se você não estiver programando em Java ou se sua codebase funciona melhor com uma API REST ou biblioteca. Para criar um conector de conteúdo usando a API REST, consulte Criar um conector de conteúdo usando a API REST.

Um conector de conteúdo típico desempenha as seguintes tarefas:

  1. Leitura e processamento de parâmetros de configuração.
  2. Extração de blocos distintos de dados indexáveis, chamados de “itens”, do repositório de conteúdo de terceiros.
  3. Combinação de Access Control Lists (ACLs), metadados e dados de conteúdo em itens indexáveis.
  4. Indexação de itens com a fonte de dados do Cloud Search.
  5. (Opcional) Escuta de notificações sobre alterações do repositório de conteúdo de terceiros. As notificações sobre alterações são convertidas em solicitações de indexação para manter a fonte de dados do Cloud Search em sincronia com o repositório de terceiros. O conector desempenhará essa tarefa apenas se o repositório for compatível com a detecção de alterações.

Criar um conector de conteúdo usando o SDK do Content Connector

Nas seções a seguir, você verá explicações sobre como criar um conector de conteúdo usando o SDK do Content Connector.

Configurar dependências

É necessário incluir determinadas dependências no arquivo de criação para usar o SDK. Clique na guia abaixo para ver as dependências do ambiente de criação:

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'

Criar a configuração do conector

Cada conector tem um arquivo de configuração que contém os parâmetros usados pelo conector, como o código do repositório. Os parâmetros são definidos como pares de chave-valor, como api.sourceId=1234567890abcdef

O SDK do Google Cloud Search contém vários parâmetros de configuração fornecidos pelo Google que são usados por todos os conectores. É necessário declarar os parâmetros fornecidos pelo Google a seguir no arquivo de configuração:

  • Para um conector de conteúdo, é necessário declarar api.sourceId e api.serviceAccountPrivateKeyFile, porque esses parâmetros identificam o local do repositório e a chave privada necessárias para acessá-lo.
.
  • Para um conector de identidade, você precisa declarar api.identitySourceId como este: identifica o local da sua origem de identidade externa. Se você for sincronizando usuários, também é necessário declarar api.customerId como o ID exclusivo para a conta do Google Workspace da sua empresa.

A menos que você queira modificar os valores padrão dos outros parâmetros fornecidos pelo Google, não é necessário declará-los no arquivo de configuração. Para mais informações sobre os parâmetros de configuração fornecidos pelo Google, como como gerar determinados IDs e chaves, consulte Parâmetros de configuração fornecidos pelo Google.

Também é possível definir parâmetros específicos do repositório para usá-los no seu arquivo de configuração.

Transmitir o arquivo de configuração para o conector

Defina a propriedade do sistema config para transmitir o arquivo de configuração para o conector. É possível definir a propriedade usando o argumento -D ao iniciar o conector. Por exemplo, o comando a seguir inicia o conector com o arquivo de configuração MyConfig.properties:

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

Se esse argumento estiver ausente, o SDK tentará acessar uma configuração padrão arquivo chamado connector-config.properties.

Determinar a estratégia de travessia

A principal função do conector de conteúdo é percorrer um repositório e indexar os dados nele. Implemente uma estratégia de travessia com base no tamanho e no layout do volume de dados no seu repositório. Crie sua própria estratégia ou escolha uma das seguintes estratégias implementadas no SDK:

Estratégia de travessia completa

A estratégia de travessia completa verifica o repositório inteiro e indexa cada item às cegas. Essa estratégia é comumente usada quando se tem um repositório pequeno e a sobrecarga de fazer uma travessia completa toda vez que indexar não causa prejuízos.

Essa estratégia de travessia é adequada para repositórios pequenos com dados estáticos e não hierárquicos em sua maioria. Também é possível usar essa estratégia de travessia quando a detecção de alterações é difícil ou está indisponível no repositório.

Estratégia de travessia de listas

A estratégia de travessia de listas verifica o repositório inteiro, incluindo todos os nós filhos, e determina o status de cada item. Depois, o conector realiza uma segunda verificação e indexa apenas os itens novos ou que foram atualizados desde a última indexação. Essa estratégia é comumente usada para realizar atualizações incrementais em um índice atual, em vez de fazer uma travessia completa toda vez o índice é atualizado.

Essa estratégia de travessia é adequada para os casos em que a detecção de alterações é difícil ou está indisponível no repositório, os dados são não hierárquicos ou os conjuntos de dados são muito grandes.

Travessia de grafos

A estratégia de travessia de grafos verifica o nó pai inteiro e determina o status de cada item. Depois, o conector realiza uma segunda verificação e indexa apenas os itens no nó raiz que são novos ou foram atualizados desde a última indexação. Por fim, o conector transmite todos os códigos filhos e indexa os itens nos nós filhos que são novos ou foram atualizados. O conector continua a percorrer de maneira recorrente todos os nós filhos até que todos os itens tenham sido processados. Normalmente, esse tipo de estratégia de travessia é usada em repositórios hierárquicos, em que não é prático fazer a listagem de todos os códigos.

Essa estratégia é adequada quando se tem dados hierárquicos que precisam ser rastreados, como uma série de diretórios ou páginas da Web.

.

Cada uma dessas estratégias de travessia é implementada por um conector modelo no SDK. É possível implementar sua própria estratégia de travessia, mas essas aceleram bastante o desenvolvimento do seu conector. Para criar um conector usando um modelo, siga para a seção correspondente à sua estratégia de travessia:

Criar um conector de travessia completa usando uma classe de modelo

Nesta seção da documentação, são usados snippets de código do exemplo FullTraversalSample.

Implementar o ponto de entrada do conector

O ponto de entrada para um conector é o main(). A principal tarefa desse método é criar uma instância do Application e invoque a classe dela start() para executar o conector.

Antes de ligar application.start(), use o método IndexingApplication.Builder para instanciar a classe FullTraversalConnector modelo. A FullTraversalConnector aceita um Repository objeto cujos métodos você implementa. O snippet de código a seguir mostra como para implementar o método 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();
}

Em segundo plano, o SDK chama initConfig() depois das chamadas de método main() do seu conector Application.build A Método initConfig() executa as seguintes tarefas:

  1. Chama o método Configuation.isInitialized() para garantir que Configuration não foi inicializado.
  2. Inicializa um objeto Configuration com a chave-valor fornecida pelo Google pares. Cada par de chave-valor é armazenado em um ConfigValue dentro do objeto Configuration.

Implementar a interface Repository

A única finalidade do objeto Repository é realizar a travessia e a indexação de itens do repositório. Ao usar um modelo, substitua apenas determinados métodos na Repository. para criar um conector de conteúdo. A escolha dos métodos que você modificará dependerá do modelo e da estratégia de travessia usados. Para o FullTraversalConnector , substitua os seguintes métodos:

  • A init() . Para configurar e inicializar o repositório de dados, modifique o init().

  • A getAllDocs() . Para percorrer e indexar todos os itens no repositório de dados, modifique o getAllDocs(). Esse método é chamado uma vez em cada travessia programada, conforme definido por sua configuração.

  • (opcional) O campo getChanges() . Se o repositório oferecer suporte à detecção de alterações, modifique o getChanges(). Esse método é chamado uma vez em cada travessia incremental programada, conforme definido por sua configuração, para recuperar os itens modificados e indexá-los.

  • (opcional) O campo close() . Se você precisar realizar a limpeza do repositório, modifique o close() . Esse método é chamado uma vez durante o encerramento do conector.

Cada um dos métodos da O objeto Repository retorna algum tipo de ApiOperation objeto. Um objeto ApiOperation realiza uma ação na forma de um único objeto ou talvez vários, IndexingService.indexItem() para fazer a indexação real do seu repositório.

Receber parâmetros de configuração personalizados

Como parte da configuração do seu conector, será necessário receber parâmetros personalizados Configuration objeto. Essa tarefa geralmente é realizada Repository da classe init().

A classe Configuration tem vários métodos para receber diferentes tipos de dados. de uma configuração. Cada método retorna um objeto ConfigValue. Em seguida, você vai use o método ConfigValue get() para recuperar o valor real. O snippet a seguir, de FullTraversalSample, mostra como recuperar um único valor inteiro personalizado de um objeto Configuration:

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

Para receber e analisar um parâmetro que contém diversos valores, use um dos Analisadores de tipo da classe Configuration para analisar os dados em blocos distintos. O snippet a seguir, do conector do tutorial, usa a propriedade getMultiValue para receber uma lista de nomes de repositórios do GitHub:

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

Realizar uma travessia completa

Substituir getAllDocs() para realizar uma travessia completa e indexar seu repositório. O getAllDocs() aceita um checkpoint. O checkpoint é usado para retomar a indexação em um item específico, caso o processo seja interrompido. Para cada item repositório, execute estas etapas no método getAllDocs():

  1. Defina as permissões.
  2. Defina os metadados para o item que você está indexando.
  3. Combine os metadados e o item em um indexável RepositoryDoc
  4. Empacote cada item indexável em um iterador retornado pelo getAllDocs(). . Observe que getAllDocs() retorna uma CheckpointCloseableIterable que é uma iteração do ApiOperation objetos, cada um representando uma solicitação de API realizada em um RepositoryDoc, como a indexação dele.

Se o conjunto de itens for muito grande para ser processado em uma única chamada, inclua um um checkpoint e definir hasMore(true) para indicar que mais itens estão disponíveis para indexação.

Definir as permissões para um item

Seu repositório usa uma lista de controle de acesso (ACL, na sigla em inglês) para identificar os usuários ou grupos que têm acesso a um item. Uma ACL é uma lista de códigos de grupos ou usuários que podem acessar o item.

É preciso duplicar a ACL usada pelo repositório para garantir que apenas esses usuários com acesso a um item podem vê-lo em um resultado da pesquisa. A A ACL de um item precisa ser incluída ao indexá-lo para que o Google Cloud Search tenha as informações necessárias para fornecer o nível de acesso correto. o item.

O SDK do Content Connector oferece um conjunto variado de classes e métodos para modelar as ACLs da maioria dos repositórios. Analise a ACL de cada item no seu repositório e crie uma ACL correspondente para o Google Cloud Search ao indexar um item. Se a ACL do seu repositório utiliza conceitos como herança de ACL, a modelagem pode ser complicada. Para mais informações sobre as ACLs do Google Cloud Search, consulte as ACLs do Google Cloud Search.

Observação: a API Cloud Search Indexing aceita ACLs de domínio único. No entanto, ela não é compatível com ACLs de domínios cruzados. Use o Acl.Builder para definir o acesso a cada item usando uma ACL. O snippet de código a seguir, usado da amostra de travessia completa, permite todos os usuários ou "principals" (getCustomerPrincipal()) sejam “leitores” de todos os itens (.setReaders()) ao realizar uma pesquisa.

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

É preciso entender as ACLs para modelá-las corretamente para o repositório. Por exemplo, se você estiver indexando arquivos em um sistema de arquivos que usa algum tipo de modelo de herança em que as pastas filho herdam as permissões das pastas pai. Modelar a herança da ACL requer informações adicionais que estão inclusas na página sobre ACLs do Google Cloud Search.

Definir os metadados de um item

Os metadados são armazenados em um objeto Item. Para criar um Item, você precisa de um mínimo de um ID de string exclusivo, um tipo de item, uma ACL, um URL e uma versão para o item. O snippet de código abaixo mostra como criar uma Item usando a IndexingItemBuilder classe auxiliar.

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();

Criar o item indexável

Depois de definir os metadados para o item, você pode criar o arquivo real indexável item usando o método RepositoryDoc.Builder . O exemplo a seguir mostra como criar um único item indexável.

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();

Um RepositoryDoc é um tipo de ApiOperation que executa o IndexingService.indexItem().

Você também pode usar o Método setRequestMode() da RepositoryDoc.Builder para identificar a solicitação de indexação como ASYNCHRONOUS ou SYNCHRONOUS:

ASYNCHRONOUS
O modo assíncrono resulta em maior latência de indexação para exibição e acomoda uma grande cota de capacidade de processamento para solicitações de indexação. O modo assíncrono é recomendado para a indexação inicial (preenchimento) de todo o repositório.
SYNCHRONOUS
O modo síncrono resulta em uma latência de indexação para exibição menor e acomoda uma cota limitada de capacidade de processamento. O modo síncrono é recomendado para a indexação de atualizações e alterações no repositório. Se não especificado, o modo de solicitação será definido como SYNCHRONOUS por padrão.

Empacotar cada item indexável em um iterador

O getAllDocs() retorna um Iterator, especificamente um CheckpointCloseableIterable, de RepositoryDoc objetos. Você pode usar o CheckpointClosableIterableImpl.Builder para construir e retornar um iterador. O snippet de código a seguir mostra como construir e retornar um iterador.

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

O SDK executa cada chamada de indexação incluída no iterador.

Próximas etapas

Veja a seguir algumas das próximas etapas:

Criar um conector de travessia de listas usando uma classe de modelo

O Cloud Search Indexing Queue é usado para armazenar códigos e, opcionalmente, valores de hash de cada item no repositório. Um conector de travessia de listas envia códigos de itens ao Google Cloud Search Indexing Queue e os recupera, um de cada vez, para realizar a indexação. O Google Cloud Search mantém filas e compara o conteúdo delas para determinar o status dos itens, como por exemplo, se um item foi excluído do repositório. Para mais informações sobre a plataforma para indexação, consulte Fila de indexação do Cloud Search.

Nesta seção da documentação, são usados snippets de código do exemplo ListTraversalSample.

Implementar o ponto de entrada do conector

O ponto de entrada para um conector é o main(). A principal tarefa desse método é criar uma instância do Application e invoque a classe dela start() para executar o conector.

Antes de ligar application.start(), use o método IndexingApplication.Builder para instanciar a classe ListingConnector modelo. O ListingConnector aceita uma Repository objeto cujos métodos você implementa. O snippet a seguir mostra como Instancie o ListingConnector e o Repository associado a ele:

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();
}

Em segundo plano, o SDK chama initConfig() depois das chamadas de método main() do seu conector Application.build O método initConfig():

  1. Chama o método Configuation.isInitialized() para garantir que Configuration não foi inicializado.
  2. Inicializa um objeto Configuration com a chave-valor fornecida pelo Google pares. Cada par de chave-valor é armazenado em um ConfigValue dentro do objeto Configuration.

Implementar a interface Repository

A única finalidade do objeto Repository é realizar a travessia e a indexação de itens do repositório. Ao usar um modelo, você só precisa modificar determinados métodos na interface Repository para criar um conector de conteúdo. A escolha dos métodos que você modificará dependerá do modelo e da estratégia de travessia usados. Para o ListingConnector, substitua os seguintes métodos:

  • A init() . Para configurar e inicializar o repositório de dados, modifique o init().

  • O getIds() . Para recuperar IDs e valores de hash de todos os registros no repositório, modifique o método getIds().

  • O getDoc() . Para adicionar, atualizar, modificar ou excluir itens do índice, modifique o getDoc().

  • (opcional) O campo getChanges() . Se o repositório oferecer suporte à detecção de alterações, modifique o getChanges(). Esse método é chamado uma vez em cada travessia incremental programada, conforme definido por sua configuração, para recuperar os itens modificados e indexá-los.

  • (opcional) O campo close() . Se você precisar realizar a limpeza do repositório, modifique o close() . Esse método é chamado uma vez durante o encerramento do conector.

Cada um dos métodos do objeto Repository retorna algum tipo de ApiOperation objeto. Um objeto ApiOperation realiza uma ação na forma de um único objeto talvez vários, IndexingService.indexItem() para fazer a indexação real do seu repositório.

Receber parâmetros de configuração personalizados

Como parte da configuração do seu conector, será necessário receber parâmetros personalizados Configuration objeto. Essa tarefa geralmente é realizada em uma Repository da classe init().

A classe Configuration tem vários métodos para receber diferentes tipos de dados. de uma configuração. Cada método retorna um objeto ConfigValue. Em seguida, você vai use o método ConfigValue get() para recuperar o valor real. O snippet a seguir, de FullTraversalSample, mostra como recuperar uma único valor inteiro personalizado de um objeto Configuration:

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

Para receber e analisar um parâmetro que contém diversos valores, use um dos Analisadores de tipo da classe Configuration para analisar os dados em blocos distintos. O snippet a seguir, do conector do tutorial, usa a propriedade getMultiValue para receber uma lista de nomes de repositórios do GitHub:

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

Realizar a travessia de listas

Substituir getIds() para recuperar IDs e valores de hash de todos os registros no repositório. O método getIds() aceita um checkpoint. O checkpoint é usado para retomar a indexação em um item específico, caso o processo seja interrompido.

Em seguida, modifique o getDoc() para processar cada item no Cloud Search Index Queue.

Enviar IDs de itens e valores de hash

Substituir getIds() para buscar os IDs dos itens e seus valores de hash de conteúdo associados da repositório de dados. Os pares de código e valor de hash são empacotados em uma solicitação de operação de push para o Cloud Search Indexing Queue. Geralmente, os códigos raiz ou pai são enviados primeiro, seguidos pelos códigos filhos, até que toda a hierarquia de itens seja processada.

O método getIds() aceita um checkpoint que representa o último item a ser indexado. O checkpoint pode ser usado para retomar a indexação em um item específico, caso o processo seja interrompido. Para cada item no repositório, realize estas Etapas no método getIds():

  • Busque no repositório o ID de cada item e o valor de hash associado.
  • Empacote cada par de ID e valor de hash em um PushItems.
  • Combine cada PushItems em um iterador retornado pelo getIds() . Observe que getIds() retorna uma CheckpointCloseableIterable que é uma iteração do ApiOperation objetos, cada um representando uma solicitação de API realizada em um RepositoryDoc , como enviar os itens para a fila.

O snippet de código a seguir mostra como obter cada ID de item e valor de hash e inseri-los em um PushItems Um PushItems é uma solicitação ApiOperation para enviar um item ao Cloud Search. Fila de indexação.

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);
}

O snippet de código a seguir mostra como usar a função PushItems.Builder para empacotar os IDs e os valores de hash em um único push ApiOperation.

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

Os itens são enviados para a fila de indexação do Cloud Search para processamento adicional.

Recuperar e processar os itens

Substituir getDoc() para processar cada item no Cloud Search Index Queue. Um item pode ser novo, modificado, inalterado ou não existir mais no repositório de origem. Recupere e indexe cada item novo ou modificado. Remova os itens do índice que não existam mais no repositório de origem.

O método getDoc() aceita um item do Google Cloud Search. Fila de indexação. Para cada item na fila, execute essas etapas na Método getDoc():

  1. Verifique se o código do item no Cloud Search Indexing Queue existe no repositório. Se não existir, exclua o item do índice.

  2. Pesquise o índice pelo status do item e, se um item estiver inalterado (ACCEPTED), não faça nada.

  3. No caso de índice alterado ou itens novos, siga estas etapas:

    1. Defina as permissões.
    2. Defina os metadados para o item que você está indexando.
    3. Combine os metadados e o item em um indexável RepositoryDoc
    4. Retorne o RepositoryDoc.

Observação:o modelo ListingConnector não pode retornar null em o método getDoc(). Retornar null resulta em uma NullPointerException.

Processar itens excluídos

O snippet de código a seguir mostra como determinar se um item existe no repositório e, se não existir, como excluí-lo.

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);
}

Observe que documents é uma estrutura de dados que representa o repositório. Se documentID não encontrado em documents. Retornar APIOperations.deleteItem(resourceName) para excluir o item do índice.

Processar itens inalterados

O snippet de código a seguir mostra como pesquisar o status dos itens no Cloud Search Indexing Queue e processar um item inalterado.

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();
}

Para determinar se o item não foi modificado, verifique o status do item e outros metadados que possam indicar uma alteração. No exemplo, é usado o hash de metadados para determinar se o item foi alterado.

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);
}

Definir as permissões para um item

Seu repositório usa uma lista de controle de acesso (ACL, na sigla em inglês) para identificar os usuários ou grupos que têm acesso a um item. Uma ACL é uma lista de códigos de grupos ou usuários que podem acessar o item.

É preciso duplicar a ACL usada pelo repositório para garantir que apenas esses usuários com acesso a um item podem vê-lo em um resultado da pesquisa. A A ACL de um item precisa ser incluída ao indexá-lo para que o Google Cloud Search tenha as informações necessárias para fornecer o nível de acesso correto. o item.

O SDK do Content Connector oferece um conjunto variado de classes e métodos para modelar as ACLs da maioria dos repositórios. Analise a ACL de cada item no seu repositório e crie uma ACL correspondente para o Google Cloud Search ao indexar um item. Se a ACL do seu repositório utiliza conceitos como herança de ACL, a modelagem pode ser complicada. Para mais informações sobre as ACLs do Google Cloud Search, consulte as ACLs do Google Cloud Search.

Observação: a API Cloud Search Indexing aceita ACLs de domínio único. No entanto, ela não é compatível com ACLs de domínios cruzados. Use o Acl.Builder para definir o acesso a cada item usando uma ACL. O snippet de código a seguir, usado da amostra de travessia completa, permite todos os usuários ou "principals" (getCustomerPrincipal()) sejam “leitores” de todos os itens (.setReaders()) ao realizar uma pesquisa.

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

É preciso entender as ACLs para modelá-las corretamente para o repositório. Por exemplo, se você estiver indexando arquivos em um sistema de arquivos que usa algum tipo de modelo de herança em que as pastas filho herdam as permissões das pastas pai. Modelar a herança da ACL requer informações adicionais que estão inclusas na página sobre ACLs do Google Cloud Search.

Definir os metadados de um item

Os metadados são armazenados em um objeto Item. Para criar um Item, você precisa de um mínimo de um ID de string exclusivo, um tipo de item, uma ACL, um URL e uma versão para o item. O snippet de código abaixo mostra como criar uma Item usando a IndexingItemBuilder classe auxiliar.

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();

Criar um item indexável

Depois de definir os metadados para o item, você pode criar o arquivo real indexável item usando o método RepositoryDoc.Builder O exemplo a seguir mostra como criar um único item indexável.

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();

Uma RepositoryDoc é um tipo de ApiOperation que executa IndexingService.indexItem() solicitação.

Você também pode usar o Método setRequestMode() da RepositoryDoc.Builder para identificar a solicitação de indexação como ASYNCHRONOUS ou SYNCHRONOUS:

ASYNCHRONOUS
O modo assíncrono resulta em maior latência de indexação para exibição e acomoda uma grande cota de capacidade de processamento para solicitações de indexação. O modo assíncrono é recomendado para a indexação inicial (preenchimento) de todo o repositório.
SYNCHRONOUS
O modo síncrono resulta em uma latência de indexação para exibição menor e acomoda uma cota limitada de capacidade de processamento. O modo síncrono é recomendado para a indexação de atualizações e alterações no repositório. Se não especificado, o modo de solicitação será definido como SYNCHRONOUS por padrão.
.

Próximas etapas

Veja a seguir algumas das próximas etapas:

Criar um conector de travessia de grafos usando uma classe de modelo

O Cloud Search Indexing Queue é usado para armazenar códigos e, opcionalmente, valores de hash de cada item no repositório. Um conector de travessia de grafos envia IDs de itens para fila de indexação do Google Cloud Search e os recupera, um de cada vez, para indexação. O Google Cloud Search mantém filas e compara o conteúdo delas para determinar o status dos itens, como por exemplo, se um item foi excluído do repositório. Para mais informações sobre esse recurso, consulte para Fila de indexação do Google Cloud Search.

Durante a indexação, o conteúdo do item é buscado no repositório de dados e todos os códigos de itens são enviados para a fila. O conector continua a processar os códigos pai e filhos de modo recorrente até que todos os itens sejam verificados.

Nesta seção da documentação, são usados snippets de código do exemplo GraphTraversalSample.

Implementar o ponto de entrada do conector

O ponto de entrada para um conector é o main(). A principal tarefa desse método é criar uma instância do Application e invoque a classe dela start() para executar o conector.

Antes de ligar application.start(), use o método IndexingApplication.Builder para instanciar o modelo ListingConnector. A ListingConnector aceita um Repository objeto cujos métodos você implementa.

O snippet a seguir mostra como Instancie o ListingConnector e o Repository associado a ele:

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();
}

Em segundo plano, o SDK chama initConfig() depois das chamadas de método main() do seu conector Application.build O método initConfig():

  1. Chama o método Configuation.isInitialized() para garantir que Configuration não foi inicializado.
  2. Inicializa um objeto Configuration com a chave-valor fornecida pelo Google pares. Cada par de chave-valor é armazenado em um ConfigValue dentro do objeto Configuration.

Implementar a interface Repository

O único propósito do O objeto Repository realiza a travessia e a indexação do repositório itens. Ao usar um modelo, é preciso substituir apenas determinados métodos na Repository para criar um conector de conteúdo. A escolha dos métodos que você modificará dependerá do modelo e da estratégia de travessia usados. Para o ListingConnector, você substitui os seguintes métodos:

  • A init() . Para configurar e inicializar o repositório de dados, modifique o init().

  • O getIds() . Para recuperar IDs e valores de hash de todos os registros no repositório, modifique o método getIds().

  • O getDoc() . Para adicionar, atualizar, modificar ou excluir itens do índice, modifique o getDoc().

  • (opcional) O campo getChanges() . Se o repositório oferecer suporte à detecção de alterações, modifique o getChanges(). Esse método é chamado uma vez em cada travessia incremental programada, conforme definido por sua configuração, para recuperar os itens modificados e indexá-los.

  • (opcional) O campo close() . Se você precisar realizar a limpeza do repositório, modifique o close() . Esse método é chamado uma vez durante o encerramento do conector.

Cada um dos métodos da O objeto Repository retorna algum tipo de objeto ApiOperation. Um ApiOperation executa uma ação na forma de uma única ação IndexingService.indexItem() para fazer a indexação real do seu repositório.

Receber parâmetros de configuração personalizados

Como parte da configuração do seu conector, será necessário receber parâmetros personalizados Configuration objeto. Essa tarefa geralmente é realizada Repository da classe init().

A classe Configuration tem vários métodos para receber diferentes tipos de dados. de uma configuração. Cada método retorna um objeto ConfigValue. Em seguida, você vai use o método ConfigValue get() para recuperar o valor real. O snippet a seguir, de FullTraversalSample, mostra como recuperar um único valor inteiro personalizado de um objeto Configuration:

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

Para receber e analisar um parâmetro que contém diversos valores, use um dos Analisadores de tipo da classe Configuration para analisar os dados em blocos distintos. O snippet a seguir, do conector do tutorial, usa a propriedade getMultiValue para receber uma lista de nomes de repositórios do GitHub:

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

Realizar a travessia de gráficos

Substituir getIds() para recuperar IDs e valores de hash de todos os registros no repositório. O método getIds() aceita um checkpoint. O checkpoint é usado para retomar a indexação em um item específico, caso o processo seja interrompido.

Em seguida, modifique o getDoc() para processar cada item no Cloud Search Index Queue.

Enviar IDs de itens e valores de hash

Substituir getIds() para buscar os IDs dos itens e seus valores de hash de conteúdo associados da repositório de dados. Os pares de código e valor de hash são empacotados em uma solicitação de operação de push para o Cloud Search Indexing Queue. Geralmente, os códigos raiz ou pai são enviados primeiro, seguidos pelos códigos filhos, até que toda a hierarquia de itens seja processada.

O método getIds() aceita um checkpoint que representa o último item a ser indexado. O checkpoint pode ser usado para retomar a indexação em um item específico, caso o processo seja interrompido. Para cada item no repositório, realize estas Etapas no método getIds():

  • Busque no repositório o ID de cada item e o valor de hash associado.
  • Empacote cada par de ID e valor de hash em um PushItems.
  • Combine cada PushItems em um iterador retornado pelo getIds(). Observe que getIds() retorna uma CheckpointCloseableIterable que é uma iteração do ApiOperation objetos, cada um representando uma solicitação de API realizada em um RepositoryDoc , como enviar os itens para a fila.

O snippet de código a seguir mostra como obter cada ID de item e valor de hash e inseri-los em um PushItems: Um PushItems é ApiOperation para enviar um item para a fila de indexação do Cloud Search.

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

O snippet de código a seguir mostra como usar a função PushItems.Builder para empacotar os IDs e os valores de hash em um único push ApiOperation

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

Os itens são enviados para a fila de indexação do Cloud Search para processamento adicional.

Recuperar e processar os itens

Substituir getDoc() para processar cada item no Cloud Search Index Queue. Um item pode ser novo, modificado, inalterado ou não existir mais no repositório de origem. Recupere e indexe cada item novo ou modificado. Remova os itens do índice que não existam mais no repositório de origem.

O método getDoc() aceita um item da indexação do Cloud Search Fila. Para cada item na fila, execute essas etapas na Método getDoc():

  1. Verifique se o código do item no Cloud Search Indexing Queue existe no repositório. Se não existir, exclua o item do índice. Se o item existir, siga para a próxima etapa.

  2. No caso de índice alterado ou itens novos:

    1. Defina as permissões.
    2. Defina os metadados para o item que você está indexando.
    3. Combine os metadados e o item em um indexável RepositoryDoc
    4. Coloque os IDs filhos na fila de indexação do Cloud Search para processamento adicional.
    5. Retorne o RepositoryDoc.

Processar itens excluídos

O snippet de código a seguir mostra como determinar se um item existe no índice e, se não existir, como excluí-lo.

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);

Definir as permissões para um item

Seu repositório usa uma lista de controle de acesso (ACL, na sigla em inglês) para identificar os usuários ou grupos que têm acesso a um item. Uma ACL é uma lista de códigos de grupos ou usuários que podem acessar o item.

É preciso duplicar a ACL usada pelo repositório para garantir que apenas esses usuários com acesso a um item podem vê-lo em um resultado da pesquisa. A A ACL de um item precisa ser incluída ao indexá-lo para que o Google Cloud Search tenha as informações necessárias para fornecer o nível de acesso correto. o item.

O SDK do Content Connector oferece um conjunto variado de classes e métodos para modelar as ACLs da maioria dos repositórios. Analise a ACL de cada item no seu repositório e crie uma ACL correspondente para o Google Cloud Search ao indexar um item. Se a ACL do seu repositório utiliza conceitos como herança de ACL, a modelagem pode ser complicada. Para mais informações sobre as ACLs do Google Cloud Search, consulte as ACLs do Google Cloud Search.

Observação: a API Cloud Search Indexing aceita ACLs de domínio único. No entanto, ela não é compatível com ACLs de domínios cruzados. Use o Acl.Builder para definir o acesso a cada item usando uma ACL. O snippet de código a seguir, usado da amostra de travessia completa, permite todos os usuários ou "principals" (getCustomerPrincipal()) sejam “leitores” de todos os itens (.setReaders()) ao realizar uma pesquisa.

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

É preciso entender as ACLs para modelá-las corretamente para o repositório. Por exemplo, se você estiver indexando arquivos em um sistema de arquivos que usa algum tipo de modelo de herança em que as pastas filho herdam as permissões das pastas pai. Modelar a herança da ACL requer informações adicionais que estão inclusas na página sobre ACLs do Google Cloud Search.

Definir os metadados de um item

Os metadados são armazenados em um objeto Item. Para criar um Item, você precisa de um mínimo de um ID de string exclusivo, um tipo de item, uma ACL, um URL e uma versão para o item. O snippet de código abaixo mostra como criar uma Item usando a IndexingItemBuilder classe auxiliar.

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();

Criar o item indexável

Depois de definir os metadados para o item, você pode criar o arquivo real indexável item usando o método RepositoryDoc.Builder O exemplo a seguir mostra como criar um único item indexável.

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);

Um RepositoryDoc é um tipo de ApiOperation que executa o IndexingService.indexItem().

Você também pode usar o Método setRequestMode() da RepositoryDoc.Builder para identificar a solicitação de indexação como ASYNCHRONOUS ou SYNCHRONOUS:

ASYNCHRONOUS
O modo assíncrono resulta em maior latência de indexação para exibição e acomoda uma grande cota de capacidade de processamento para solicitações de indexação. O modo assíncrono é recomendado para a indexação inicial (preenchimento) de todo o repositório.
SYNCHRONOUS
O modo síncrono resulta em uma latência de indexação para exibição menor e acomoda uma cota limitada de capacidade de processamento. O modo síncrono é recomendado para a indexação de atualizações e alterações no repositório. Se não especificado, o modo de solicitação será definido como SYNCHRONOUS por padrão.

Colocar os IDs filhos na fila de indexação do Cloud Search

O snippet de código a seguir mostra como incluir na fila os códigos filhos de um item pai atualmente em processamento. Esses códigos são processados depois que o item pai é indexado.

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();

Próximas etapas

Veja a seguir algumas das próximas etapas:

Criar um conector de conteúdo usando a API REST

Nas seções a seguir, você aprenderá como criar um conector de conteúdo usando a API REST.

Determinar a estratégia de travessia

A principal função do conector de conteúdo é percorrer um repositório e indexar os dados nele. Implemente uma estratégia de travessia com base no tamanho e no layout do volume de dados no seu repositório. Estas são a três estratégias de travessia mais comuns:

Estratégia de travessia completa

A estratégia de travessia completa verifica o repositório inteiro e indexa cada item às cegas. Essa estratégia é comumente usada quando se tem um repositório pequeno e a sobrecarga de fazer uma travessia completa toda vez que indexar não causa prejuízos.

Essa estratégia de travessia é adequada para repositórios pequenos com dados estáticos e não hierárquicos em sua maioria. Também é possível usar essa estratégia de travessia quando a detecção de alterações é difícil ou está indisponível no repositório.

Estratégia de travessia de listas

A estratégia de travessia de listas verifica o repositório inteiro, incluindo todos os nós filhos, e determina o status de cada item. Depois, o conector realiza uma segunda verificação e indexa apenas os itens novos ou que foram atualizados desde a última indexação. Essa estratégia é comumente usada para realizar atualizações incrementais em um índice atual, em vez de fazer uma travessia completa toda vez o índice é atualizado.

Essa estratégia de travessia é adequada para os casos em que a detecção de alterações é difícil ou está indisponível no repositório, os dados são não hierárquicos ou os conjuntos de dados são muito grandes.

Travessia de grafos

A estratégia de travessia de grafos verifica o nó pai inteiro e determina o status de cada item. Depois, o conector realiza uma segunda verificação e indexa apenas os itens no nó raiz que são novos ou foram atualizados desde a última indexação. Por fim, o conector transmite todos os códigos filhos e indexa os itens nos nós filhos que são novos ou foram atualizados. O conector continua a percorrer de maneira recorrente todos os nós filhos até que todos os itens tenham sido processados. Normalmente, esse tipo de estratégia de travessia é usada em repositórios hierárquicos, em que não é prático fazer a listagem de todos os códigos.

Essa estratégia é adequada quando se tem dados hierárquicos que precisam ser rastreados, como uma série de diretórios ou páginas da Web.

.

Implementar a estratégia de travessia e indexar itens

Todos os elementos indexáveis do Cloud Search são chamados de item no a API Cloud Search. Um item pode ser um arquivo, uma pasta, uma linha em um arquivo CSV ou um registro de banco de dados.

Depois de registrar um esquema, é possível preencher o índice das seguintes maneiras:

  1. (opcional) Usando items.upload fazer upload de arquivos maiores que 100 KiB para indexação. Para arquivos menores, incorpore o conteúdo como inlineContent usando items.index.

  2. (opcional) Usando media.upload para fazer upload de arquivos de mídia para indexação.

  3. Usando items.index para indexar o item. Por exemplo, caso seu esquema use a definição de objeto da série movie schema, uma solicitação de indexação para um único item seria semelhante a:

    {
      "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. (Opcional) Usando items.get chamadas para verificar um item foi indexado.

Para realizar uma travessia completa, seria necessário indexar novamente o repositório inteiro periodicamente. Para realizar uma travessia de listas ou grafos, é preciso implementar o código para processar as alterações no repositório.

Processar alterações no repositório

É possível coletar e indexar periodicamente cada item do repositório para realizar uma indexação completa. Isso é eficaz para garantir que o índice esteja atualizado, mas uma indexação completa pode ser dispendiosa quando é necessário trabalhar com repositórios grandes ou hierárquicos.

Em vez de usar chamadas de indexação para indexar o repositório de vez em quando, uma alternativa é usar o Google Cloud Indexing Queue como mecanismo de rastreio de alterações e indexar apenas os itens que foram alterados. Você pode usar o items.push solicitações para enviar itens para a fila para pesquisa e atualização posteriores. Para mais informações sobre a fila de indexação do Google Cloud, consulte Fila de indexação do Google Cloud.

Para mais informações sobre a API Google Cloud Search, consulte API Cloud Search.