Создание соединителя содержимого

Коннектор контента — это программа, используемая для перемещения данных в корпоративном репозитории и заполнения источника данных. Google предоставляет следующие возможности для разработки коннекторов контента:

  • SDK Content Connector. Это хороший вариант, если вы программируете на Java. Content Connector SDK — это оболочка REST API, позволяющая быстро создавать соединители. Чтобы создать соединитель контента с помощью SDK, см. раздел Создание соединителя контента с помощью SDK Content Connector .

  • Низкоуровневый REST API или библиотеки API. Используйте эти параметры, если вы не программируете на Java или если ваша кодовая база лучше подходит для REST API или библиотеки. Чтобы создать соединитель контента с помощью REST API, см. раздел Создание соединителя контента с помощью REST API .

Типичный соединитель контента выполняет следующие задачи:

  1. Считывает и обрабатывает параметры конфигурации.
  2. Извлекает отдельные фрагменты индексируемых данных, называемые « элементами », из стороннего репозитория контента.
  3. Объединяет списки управления доступом, метаданные и данные контента в индексируемые элементы.
  4. Индексирует элементы в источник данных Cloud Search.
  5. (необязательно) Прослушивает уведомления об изменениях из стороннего репозитория контента. Уведомления об изменениях преобразуются в запросы на индексирование, чтобы обеспечить синхронизацию источника данных Cloud Search со сторонним репозиторием. Соединитель выполняет эту задачу только в том случае, если репозиторий поддерживает обнаружение изменений.

Создайте соединитель контента с помощью SDK Content Connector.

В следующих разделах объясняется, как создать соединитель контента с помощью Content Connector SDK.

Настройка зависимостей

Чтобы использовать SDK, вы должны включить определенные зависимости в файл сборки. Нажмите на вкладку ниже, чтобы просмотреть зависимости для вашей среды сборки:

Мавен

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

Градл

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

Создайте конфигурацию соединителя

У каждого соединителя есть файл конфигурации, содержащий параметры, используемые соединителем, например идентификатор вашего репозитория. Параметры определяются как пары ключ-значение , например api.sourceId= 1234567890abcdef .

SDK Google Cloud Search содержит несколько предоставленных Google параметров конфигурации, используемых всеми соединителями. Вы должны объявить следующие параметры, предоставленные Google, в вашем файле конфигурации:

  • Для соединителя контента необходимо объявить api.sourceId и api.serviceAccountPrivateKeyFile , поскольку эти параметры определяют расположение вашего репозитория и закрытый ключ, необходимый для доступа к репозиторию.
  • Для соединителя удостоверений необходимо объявить api.identitySourceId , поскольку этот параметр определяет расположение вашего внешнего источника удостоверений. Если вы синхронизируете пользователей, вы также должны объявить api.customerId в качестве уникального идентификатора учетной записи Google Workspace вашего предприятия.

Если вы не хотите переопределить значения по умолчанию для других параметров, предоставленных Google, вам не нужно объявлять их в файле конфигурации. Дополнительную информацию о параметрах конфигурации, предоставляемых Google, например о том, как генерировать определенные идентификаторы и ключи, см. в разделе Параметры конфигурации, предоставляемые Google .

Вы также можете определить свои собственные параметры, специфичные для репозитория, для использования в файле конфигурации.

Передайте файл конфигурации в коннектор

Настройте системное свойство config для передачи файла конфигурации в соединитель. Вы можете установить это свойство, используя аргумент -D при запуске коннектора. Например, следующая команда запускает соединитель с файлом конфигурации MyConfig.properties :

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

Если этот аргумент отсутствует, SDK пытается получить доступ к файлу конфигурации по умолчанию с именем connector-config.properties .

Определите свою стратегию обхода

Основная функция соединителя контента — перемещение по репозиторию и индексирование его данных. Вы должны реализовать стратегию обхода, основанную на размере и расположении данных в вашем репозитории. Вы можете разработать собственную стратегию или выбрать одну из следующих стратегий, реализованных в SDK:

Полная стратегия обхода

Стратегия полного обхода сканирует весь репозиторий и слепо индексирует каждый элемент. Эта стратегия обычно используется, когда у вас небольшой репозиторий и вы можете позволить себе полный обход при каждом индексировании.

Эта стратегия обхода подходит для небольших репозиториев, в основном содержащих статичные, неиерархические данные. Вы также можете использовать эту стратегию обхода, когда обнаружение изменений затруднено или не поддерживается репозиторием.

Стратегия обхода списка

Стратегия обхода списка сканирует весь репозиторий, включая все дочерние узлы, определяя статус каждого элемента. Затем соединитель выполняет второй проход и индексирует только те элементы, которые являются новыми или были обновлены с момента последней индексации. Эта стратегия обычно используется для выполнения дополнительных обновлений существующего индекса (вместо необходимости выполнять полный обход каждый раз при обновлении индекса).

Эта стратегия обхода подходит, когда обнаружение изменений затруднено или не поддерживается репозиторием, у вас есть неиерархические данные и вы работаете с очень большими наборами данных.

Обход графа

Стратегия обхода графа сканирует весь родительский узел, определяя статус каждого элемента. Затем соединитель выполняет второй проход и индексирует только элементы в корневом узле, которые являются новыми или были обновлены с момента последней индексации. Наконец, соединитель передает все дочерние идентификаторы, а затем индексирует новые или обновленные элементы в дочерних узлах. Соединитель продолжает рекурсивно проходить через все дочерние узлы, пока все элементы не будут адресованы. Такой обход обычно используется для иерархических репозиториев, где перечисление всех идентификаторов нецелесообразно.

Эта стратегия подходит, если у вас есть иерархические данные, которые необходимо сканировать, например ряд каталогов или веб-страниц.

Каждая из этих стратегий обхода реализуется классом соединителя шаблонов в SDK. Хотя вы можете реализовать свою собственную стратегию обхода, эти шаблоны значительно ускоряют разработку вашего соединителя. Чтобы создать коннектор по шаблону, перейдите в раздел, соответствующий вашей стратегии обхода:

Создайте соединитель полного обхода, используя класс шаблона.

Этот раздел документации относится к фрагментам кода из примера FullTraversalSample .

Реализация точки входа соединителя

Точкой входа в коннектор является метод main() . Основная задача этого метода — создать экземпляр класса Application и вызвать его метод start() для запуска соединителя.

Прежде чем вызывать application.start() , используйте класс IndexingApplication.Builder для создания экземпляра шаблона FullTraversalConnector . FullTraversalConnector принимает объект Repository , методы которого вы реализуете. Следующий фрагмент кода показывает, как реализовать метод main() :

Фуллтраверсалсампле.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();
}

За кулисами SDK вызывает метод initConfig() после того, как метод main() вашего соединителя вызывает Application.build . Метод initConfig() выполняет следующие задачи:

  1. Вызывает метод Configuation.isInitialized() , чтобы убедиться, что Configuration не была инициализирована.
  2. Инициализирует объект Configuration с помощью пар ключ-значение, предоставленных Google. Каждая пара ключ-значение хранится в объекте ConfigValue внутри объекта Configuration .

Реализовать интерфейс Repository

Единственная цель объекта Repository — выполнять обход и индексацию элементов репозитория. При использовании шаблона вам нужно только переопределить определенные методы в интерфейсе Repository , чтобы создать соединитель контента. Методы, которые вы переопределяете, зависят от используемого вами шаблона и стратегии обхода. Для FullTraversalConnector переопределите следующие методы:

  • Метод init() . Чтобы выполнить настройку и инициализацию хранилища данных, переопределите метод init() .

  • Метод getAllDocs() . Чтобы просмотреть и индексировать все элементы в репозитории данных, переопределите метод getAllDocs() . Этот метод вызывается один раз для каждого запланированного обхода (как определено вашей конфигурацией).

  • (необязательно) Метод getChanges() . Если ваш репозиторий поддерживает обнаружение изменений, переопределите метод getChanges() . Этот метод вызывается один раз для каждого запланированного инкрементального обхода (как определено вашей конфигурацией) для получения измененных элементов и их индексации.

  • (необязательно) Метод close() . Если вам нужно выполнить очистку репозитория, переопределите метод close() . Этот метод вызывается один раз во время завершения работы коннектора.

Каждый из методов объекта Repository возвращает объект ApiOperation определенного типа. Объект ApiOperation выполняет действие в форме одного или, возможно, нескольких вызовов IndexingService.indexItem() для фактического индексирования вашего репозитория.

Получить пользовательские параметры конфигурации

В рамках обработки конфигурации вашего соединителя вам потребуется получить любые пользовательские параметры из объекта Configuration . Эта задача обычно выполняется в методе init() класса Repository .

Класс Configuration имеет несколько методов для получения различных типов данных из конфигурации. Каждый метод возвращает объект ConfigValue . Затем вы будете использовать метод get() объекта ConfigValue для получения фактического значения. В следующем фрагменте из FullTraversalSample показано, как получить одно пользовательское целочисленное значение из объекта Configuration :

Фуллтраверсалсампле.java
@Override
public void init(RepositoryContext context) {
  log.info("Initializing repository");
  numberOfDocuments = Configuration.getInteger("sample.documentCount", 10).get();
}

Чтобы получить и проанализировать параметр, содержащий несколько значений, используйте один из анализаторов типов класса Configuration для анализа данных на отдельные фрагменты. В следующем фрагменте из соединителя учебника используется метод getMultiValue для получения списка имен репозиториев GitHub:

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

Выполнить полный обход

Переопределите getAllDocs() , чтобы выполнить полный обход и индексацию вашего репозитория. Метод getAllDocs() принимает контрольную точку. Контрольная точка используется для возобновления индексации определенного элемента в случае прерывания процесса. Для каждого элемента в вашем репозитории выполните следующие шаги в методе getAllDocs() :

  1. Установите разрешения.
  2. Задайте метаданные для индексируемого элемента.
  3. Объедините метаданные и элемент в один индексируемый RepositoryDoc .
  4. Упакуйте каждый индексируемый элемент в итератор, возвращаемый методом getAllDocs() . Обратите внимание, что getAllDocs() фактически возвращает CheckpointCloseableIterable , который представляет собой итерацию объектов ApiOperation , каждый объект представляет собой запрос API, выполненный в RepositoryDoc , например, его индексацию.

Если набор элементов слишком велик для обработки за один вызов, включите контрольную точку и установите hasMore(true) , чтобы указать, что для индексации доступно больше элементов.

Установите разрешения для элемента

В вашем репозитории используется список контроля доступа (ACL) для идентификации пользователей или групп, имеющих доступ к элементу. ACL — это список идентификаторов групп или пользователей, которые могут получить доступ к элементу.

Вы должны дублировать ACL, используемый вашим репозиторием, чтобы гарантировать, что только те пользователи, у которых есть доступ к элементу, смогут видеть этот элемент в результатах поиска. ACL для элемента должен быть включен при индексировании элемента, чтобы Google Cloud Search имел информацию, необходимую для обеспечения правильного уровня доступа к элементу.

Content Connector SDK предоставляет богатый набор классов и методов ACL для моделирования списков ACL большинства репозиториев. Вы должны проанализировать ACL для каждого элемента в вашем репозитории и создать соответствующий ACL для Google Cloud Search при индексировании элемента. Если в ACL вашего репозитория используются такие концепции, как наследование ACL, моделирование этого ACL может оказаться сложной задачей. Дополнительную информацию о списках ACL Google Cloud Search см. в разделе ACL Google Cloud Search .

Примечание. API индексирования Cloud Search поддерживает однодоменные списки управления доступом. Он не поддерживает междоменные списки управления доступом. Используйте класс Acl.Builder , чтобы настроить доступ к каждому элементу с помощью ACL. Следующий фрагмент кода, взятый из полного примера обхода, позволяет всем пользователям или «принципалам» ( getCustomerPrincipal() ) быть «читателями» всех элементов ( .setReaders() ) при выполнении поиска.

Фуллтраверсалсампле.java
// Make the document publicly readable within the domain
Acl acl = new Acl.Builder()
    .setReaders(Collections.singletonList(Acl.getCustomerPrincipal()))
    .build();

Вам необходимо понимать ACL, чтобы правильно моделировать ACL для репозитория. Например, вы можете индексировать файлы в файловой системе, использующей какую-то модель наследования, при которой дочерние папки наследуют разрешения от родительских папок. Для моделирования наследования ACL требуется дополнительная информация, описанная в ACL Google Cloud Search.

Установите метаданные для элемента

Метаданные хранятся в объекте Item . Чтобы создать Item , вам потребуется как минимум уникальный строковый идентификатор, тип элемента, список управления доступом, URL-адрес и версия элемента. В следующем фрагменте кода показано, как создать Item с помощью вспомогательного класса IndexingItemBuilder .

Фуллтраверсалсампле.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();

Создайте индексируемый элемент

После того как вы установили метаданные для элемента, вы можете создать фактический индексируемый элемент, используя класс RepositoryDoc.Builder . В следующем примере показано, как создать один индексируемый элемент.

Фуллтраверсалсампле.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 — это тип ApiOperation , который выполняет фактический запрос IndexingService.indexItem() .

Вы также можете использовать метод setRequestMode() класса RepositoryDoc.Builder , чтобы определить запрос на индексацию как ASYNCHRONOUS или SYNCHRONOUS :

ASYNCHRONOUS
Асинхронный режим приводит к увеличению задержки между индексированием и обслуживанием и обеспечивает большую квоту пропускной способности для запросов индексирования. Асинхронный режим рекомендуется для первоначальной индексации (засыпки) всего репозитория.
SYNCHRONOUS
Синхронный режим приводит к сокращению задержки между индексированием и обслуживанием и обеспечивает ограниченную квоту пропускной способности. Синхронный режим рекомендуется для индексации обновлений и изменений в репозитории. Если не указано, режим запроса по умолчанию SYNCHRONOUS .

Упакуйте каждый индексируемый элемент в итератор

Метод getAllDocs() возвращает Iterator , в частности CheckpointCloseableIterable , объектов RepositoryDoc . Вы можете использовать класс CheckpointClosableIterableImpl.Builder для создания и возврата итератора. В следующем фрагменте кода показано, как создать и вернуть итератор.

Фуллтраверсалсампле.java
CheckpointCloseableIterable<ApiOperation> iterator =
  new CheckpointCloseableIterableImpl.Builder<>(allDocs).build();

SDK выполняет каждый вызов индексации, заключенный в итераторе.

Следующие шаги

Вот несколько следующих шагов, которые вы можете предпринять:

Создайте соединитель обхода списка, используя класс шаблона.

Очередь индексирования Cloud Search используется для хранения идентификаторов и дополнительных хеш-значений для каждого элемента в репозитории. Соединитель обхода списка помещает идентификаторы элементов в очередь индексирования Google Cloud Search и извлекает их по одному для индексации. Google Cloud Search поддерживает очереди и сравнивает их содержимое, чтобы определить статус элемента, например, был ли элемент удален из хранилища. Дополнительную информацию об очереди индексирования Cloud Search см. в разделе Очередь индексирования Cloud Search .

Этот раздел документации относится к фрагментам кода из примера ListTraversalSample .

Реализация точки входа соединителя

Точкой входа в коннектор является метод main() . Основная задача этого метода — создать экземпляр класса Application и вызвать его метод start() для запуска соединителя.

Прежде чем вызывать application.start() , используйте класс IndexingApplication.Builder для создания экземпляра шаблона ListingConnector . ListingConnector принимает объект Repository , методы которого вы реализуете. В следующем фрагменте показано, как создать экземпляр ListingConnector и связанного с ним Repository :

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

За кулисами SDK вызывает метод initConfig() после того, как метод main() вашего соединителя вызывает Application.build . Метод initConfig() :

  1. Вызывает метод Configuation.isInitialized() , чтобы убедиться, что Configuration не была инициализирована.
  2. Инициализирует объект Configuration с помощью пар ключ-значение, предоставленных Google. Каждая пара ключ-значение хранится в объекте ConfigValue внутри объекта Configuration .

Реализовать интерфейс Repository

Единственная цель объекта Repository — выполнять обход и индексацию элементов репозитория. При использовании шаблона вам нужно только переопределить определенные методы в интерфейсе Repository , чтобы создать соединитель контента. Методы, которые вы переопределяете, зависят от используемого вами шаблона и стратегии обхода. Для ListingConnector переопределите следующие методы:

  • Метод init() . Чтобы выполнить настройку и инициализацию хранилища данных, переопределите метод init() .

  • Метод getIds() . Чтобы получить идентификаторы и хеш-значения для всех записей в репозитории, переопределите метод getIds() .

  • Метод getDoc() . Чтобы добавить новые, обновить, изменить или удалить элементы из индекса, переопределите метод getDoc() .

  • (необязательно) Метод getChanges() . Если ваш репозиторий поддерживает обнаружение изменений, переопределите метод getChanges() . Этот метод вызывается один раз для каждого запланированного инкрементального обхода (как определено вашей конфигурацией) для получения измененных элементов и их индексации.

  • (необязательно) Метод close() . Если вам нужно выполнить очистку репозитория, переопределите метод close() . Этот метод вызывается один раз во время завершения работы коннектора.

Каждый из методов объекта Repository возвращает объект ApiOperation определенного типа. Объект ApiOperation выполняет действие в форме одного или, возможно, нескольких вызовов IndexingService.indexItem() для фактического индексирования вашего репозитория.

Получить пользовательские параметры конфигурации

В рамках обработки конфигурации вашего соединителя вам потребуется получить любые пользовательские параметры из объекта Configuration . Эта задача обычно выполняется в методе init() класса Repository .

Класс Configuration имеет несколько методов для получения различных типов данных из конфигурации. Каждый метод возвращает объект ConfigValue . Затем вы будете использовать метод get() объекта ConfigValue для получения фактического значения. В следующем фрагменте из FullTraversalSample показано, как получить одно пользовательское целочисленное значение из объекта Configuration :

Фуллтраверсалсампле.java
@Override
public void init(RepositoryContext context) {
  log.info("Initializing repository");
  numberOfDocuments = Configuration.getInteger("sample.documentCount", 10).get();
}

Чтобы получить и проанализировать параметр, содержащий несколько значений, используйте один из анализаторов типов класса Configuration для анализа данных на отдельные фрагменты. В следующем фрагменте из соединителя учебника используется метод getMultiValue для получения списка имен репозиториев GitHub:

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

Выполнить обход списка

Переопределить метод getIds() для получения идентификаторов и хеш-значений для всех записей в репозитории. Метод getIds() принимает контрольную точку. Контрольная точка используется для возобновления индексации определенного элемента в случае прерывания процесса.

Затем переопределите метод getDoc() для обработки каждого элемента в очереди индексирования Cloud Search.

Отправка идентификаторов элементов и хеш-значений

Переопределите getIds() для получения идентификаторов элементов и связанных с ними хеш-значений контента из репозитория. Пары идентификаторов и хеш-значений затем упаковываются в запрос операции push в очередь индексирования Cloud Search. Корневые или родительские идентификаторы обычно передаются первыми, а затем дочерние идентификаторы, пока не будет обработана вся иерархия элементов.

Метод getIds() принимает контрольную точку, представляющую последний индексируемый элемент. Контрольную точку можно использовать для возобновления индексации определенного элемента, если процесс будет прерван. Для каждого элемента в вашем репозитории выполните следующие шаги в методе getIds() :

  • Получите идентификатор каждого элемента и связанное с ним значение хеш-функции из репозитория.
  • Упакуйте каждую пару идентификаторов и хеш-значений в PushItems .
  • Объедините каждый PushItems в итератор, возвращаемый методом getIds() . Обратите внимание, что getIds() фактически возвращает CheckpointCloseableIterable , который представляет собой итерацию объектов ApiOperation , каждый объект представляет собой запрос API, выполняемый в RepositoryDoc , например, помещает элементы в очередь.

В следующем фрагменте кода показано, как получить идентификатор каждого элемента и значение хеш-функции и вставить их в PushItems . PushItems — это запрос ApiOperation для отправки элемента в очередь индексирования Cloud Search.

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

В следующем фрагменте кода показано, как использовать класс PushItems.Builder для упаковки идентификаторов и хэш-значений в одну операцию push ApiOperation .

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

Элементы помещаются в очередь индексирования Cloud Search для дальнейшей обработки.

Извлекайте и обрабатывайте каждый элемент

Переопределите getDoc() для обработки каждого элемента в очереди индексирования Cloud Search. Элемент может быть новым, измененным, неизмененным или больше не существовать в исходном репозитории. Извлекайте и индексируйте каждый новый или измененный элемент. Удалите из индекса элементы, которых больше нет в исходном репозитории.

Метод getDoc() принимает элемент из очереди индексирования Google Cloud Search. Для каждого элемента в очереди выполните следующие шаги в методе getDoc() :

  1. Проверьте, существует ли в репозитории идентификатор элемента в очереди индексирования Cloud Search. Если нет, удалите элемент из индекса.

  2. Опросите индекс на предмет статуса элемента и, если элемент не изменился ( ACCEPTED ), ничего не делайте.

  3. Индекс изменен или добавлены элементы:

    1. Установите разрешения.
    2. Задайте метаданные для индексируемого элемента.
    3. Объедините метаданные и элемент в один индексируемый RepositoryDoc .
    4. Верните RepositoryDoc .

Примечание. Шаблон ListingConnector не поддерживает возврат значения null в методе getDoc() . Возврат null результатов приводит к NullPointerException.

Обработка удаленных элементов

В следующем фрагменте кода показано, как определить, существует ли элемент в репозитории, и если нет, удалить его.

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 — это структура данных, представляющая репозиторий. Если documentID не найден в documents , верните APIOperations.deleteItem(resourceName) , чтобы удалить элемент из индекса.

Обработка неизмененных элементов

В следующем фрагменте кода показано, как опросить статус элемента в очереди индексирования Cloud Search и обработать неизмененный элемент.

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

Чтобы определить, является ли элемент неизмененным, проверьте статус элемента, а также другие метаданные, которые могут указывать на изменение. В этом примере хэш метаданных используется для определения того, был ли изменен элемент.

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

Установите разрешения для элемента

В вашем репозитории используется список контроля доступа (ACL) для идентификации пользователей или групп, имеющих доступ к элементу. ACL — это список идентификаторов групп или пользователей, которые могут получить доступ к элементу.

Вы должны дублировать ACL, используемый вашим репозиторием, чтобы гарантировать, что только те пользователи, у которых есть доступ к элементу, смогут видеть этот элемент в результатах поиска. ACL для элемента должен быть включен при индексировании элемента, чтобы Google Cloud Search имел информацию, необходимую для обеспечения правильного уровня доступа к элементу.

Content Connector SDK предоставляет богатый набор классов и методов ACL для моделирования списков ACL большинства репозиториев. Вы должны проанализировать ACL для каждого элемента в вашем репозитории и создать соответствующий ACL для Google Cloud Search при индексировании элемента. Если в ACL вашего репозитория используются такие концепции, как наследование ACL, моделирование этого ACL может оказаться сложной задачей. Дополнительную информацию о списках ACL Google Cloud Search см. в разделе ACL Google Cloud Search .

Примечание. API индексирования Cloud Search поддерживает однодоменные списки управления доступом. Он не поддерживает междоменные списки управления доступом. Используйте класс Acl.Builder , чтобы настроить доступ к каждому элементу с помощью ACL. Следующий фрагмент кода, взятый из полного примера обхода, позволяет всем пользователям или «принципалам» ( getCustomerPrincipal() ) быть «читателями» всех элементов ( .setReaders() ) при выполнении поиска.

Фуллтраверсалсампле.java
// Make the document publicly readable within the domain
Acl acl = new Acl.Builder()
    .setReaders(Collections.singletonList(Acl.getCustomerPrincipal()))
    .build();

Вам необходимо понимать ACL, чтобы правильно моделировать ACL для репозитория. Например, вы можете индексировать файлы в файловой системе, использующей какую-то модель наследования, при которой дочерние папки наследуют разрешения от родительских папок. Для моделирования наследования ACL требуется дополнительная информация, описанная в ACL Google Cloud Search.

Установите метаданные для элемента

Метаданные хранятся в объекте Item . Чтобы создать Item , вам потребуется как минимум уникальный строковый идентификатор, тип элемента, список управления доступом, URL-адрес и версия элемента. В следующем фрагменте кода показано, как создать Item с помощью вспомогательного класса IndexingItemBuilder .

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

Создать индексируемый элемент

После того как вы установили метаданные для элемента, вы можете создать фактический индексируемый элемент с помощью RepositoryDoc.Builder . В следующем примере показано, как создать один индексируемый элемент.

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 — это тип ApiOperation , который выполняет фактический запрос IndexingService.indexItem() .

Вы также можете использовать метод setRequestMode() класса RepositoryDoc.Builder , чтобы определить запрос на индексацию как ASYNCHRONOUS или SYNCHRONOUS :

ASYNCHRONOUS
Асинхронный режим приводит к увеличению задержки между индексированием и обслуживанием и обеспечивает большую квоту пропускной способности для запросов индексирования. Асинхронный режим рекомендуется для первоначальной индексации (засыпки) всего репозитория.
SYNCHRONOUS
Синхронный режим приводит к сокращению задержки между индексированием и обслуживанием и обеспечивает ограниченную квоту пропускной способности. Синхронный режим рекомендуется для индексации обновлений и изменений в репозитории. Если не указано, режим запроса по умолчанию SYNCHRONOUS .

Следующие шаги

Вот несколько следующих шагов, которые вы можете предпринять:

Создайте соединитель обхода графа, используя класс шаблона.

Очередь индексирования Cloud Search используется для хранения идентификаторов и дополнительных хеш-значений для каждого элемента в репозитории. Соединитель обхода графа передает идентификаторы элементов в очередь индексирования Google Cloud Search и извлекает их по одному для индексации. Google Cloud Search поддерживает очереди и сравнивает их содержимое, чтобы определить статус элемента, например, был ли элемент удален из хранилища. Дополнительную информацию об очереди индексирования Cloud Search см. в разделе Очередь индексирования Google Cloud Search .

Во время индексирования содержимое элемента извлекается из хранилища данных, а идентификаторы всех дочерних элементов помещаются в очередь. Соединитель продолжает рекурсивно обрабатывать родительские и дочерние идентификаторы, пока не будут обработаны все элементы.

Этот раздел документации относится к фрагментам кода из примера GraphTraversalSample .

Реализация точки входа соединителя

Точкой входа в коннектор является метод main() . Основная задача этого метода — создать экземпляр класса Application и вызвать его метод start() для запуска соединителя.

Прежде чем вызывать application.start() , используйте класс IndexingApplication.Builder для создания экземпляра шаблона ListingConnector . ListingConnector принимает объект Repository , методы которого вы реализуете.

В следующем фрагменте показано, как создать экземпляр ListingConnector и связанного с ним Repository :

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

За кулисами SDK вызывает метод initConfig() после того, как метод main() вашего соединителя вызывает Application.build . Метод initConfig() :

  1. Вызывает метод Configuation.isInitialized() , чтобы убедиться, что Configuration не была инициализирована.
  2. Инициализирует объект Configuration с помощью пар ключ-значение, предоставленных Google. Каждая пара ключ-значение хранится в объекте ConfigValue внутри объекта Configuration .

Реализовать интерфейс Repository

Единственная цель объекта Repository — выполнять обход и индексацию элементов репозитория. При использовании шаблона вам нужно только переопределить определенные методы в интерфейсе Repository , чтобы создать соединитель контента. Методы, которые вы переопределяете, зависят от используемого вами шаблона и стратегии обхода. Для ListingConnector вы переопределяете следующие методы:

  • Метод init() . Чтобы выполнить настройку и инициализацию хранилища данных, переопределите метод init() .

  • Метод getIds() . Чтобы получить идентификаторы и хеш-значения для всех записей в репозитории, переопределите метод getIds() .

  • Метод getDoc() . Чтобы добавить новые, обновить, изменить или удалить элементы из индекса, переопределите метод getDoc() .

  • (необязательно) Метод getChanges() . Если ваш репозиторий поддерживает обнаружение изменений, переопределите метод getChanges() . Этот метод вызывается один раз для каждого запланированного инкрементального обхода (как определено вашей конфигурацией) для получения измененных элементов и их индексации.

  • (необязательно) Метод close() . Если вам нужно выполнить очистку репозитория, переопределите метод close() . Этот метод вызывается один раз во время завершения работы коннектора.

Каждый из методов объекта Repository возвращает объект ApiOperation определенного типа. Объект ApiOperation выполняет действие в форме одного или, возможно, нескольких вызовов IndexingService.indexItem() для фактического индексирования вашего репозитория.

Получить пользовательские параметры конфигурации

В рамках обработки конфигурации вашего соединителя вам потребуется получить любые пользовательские параметры из объекта Configuration . Эта задача обычно выполняется в методе init() класса Repository .

Класс Configuration имеет несколько методов для получения различных типов данных из конфигурации. Каждый метод возвращает объект ConfigValue . Затем вы будете использовать метод get() объекта ConfigValue для получения фактического значения. В следующем фрагменте из FullTraversalSample показано, как получить одно пользовательское целочисленное значение из объекта Configuration :

Фуллтраверсалсампле.java
@Override
public void init(RepositoryContext context) {
  log.info("Initializing repository");
  numberOfDocuments = Configuration.getInteger("sample.documentCount", 10).get();
}

Чтобы получить и проанализировать параметр, содержащий несколько значений, используйте один из анализаторов типов класса Configuration для анализа данных на отдельные фрагменты. В следующем фрагменте из соединителя учебника используется метод getMultiValue для получения списка имен репозиториев GitHub:

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

Выполнить обход графа

Переопределить метод getIds() для получения идентификаторов и хеш-значений для всех записей в репозитории. Метод getIds() принимает контрольную точку. Контрольная точка используется для возобновления индексации определенного элемента в случае прерывания процесса.

Затем переопределите метод getDoc() для обработки каждого элемента в очереди индексирования Cloud Search.

Отправка идентификаторов элементов и хеш-значений

Переопределите getIds() для получения идентификаторов элементов и связанных с ними хеш-значений контента из репозитория. Пары идентификаторов и хеш-значений затем упаковываются в запрос операции push в очередь индексирования Cloud Search. Корневые или родительские идентификаторы обычно передаются первыми, а затем дочерние идентификаторы, пока не будет обработана вся иерархия элементов.

Метод getIds() принимает контрольную точку, представляющую последний индексируемый элемент. Контрольную точку можно использовать для возобновления индексации определенного элемента, если процесс будет прерван. Для каждого элемента в вашем репозитории выполните следующие шаги в методе getIds() :

  • Получите идентификатор каждого элемента и связанное с ним значение хеш-функции из репозитория.
  • Упакуйте каждую пару идентификаторов и хеш-значений в PushItems .
  • Объедините каждый PushItems в итератор, возвращаемый методом getIds() . Обратите внимание, что getIds() фактически возвращает CheckpointCloseableIterable , который представляет собой итерацию объектов ApiOperation , каждый объект представляет собой запрос API, выполняемый в RepositoryDoc , например, помещает элементы в очередь.

В следующем фрагменте кода показано, как получить идентификатор каждого элемента и значение хеш-функции и вставить их в PushItems . PushItems — это запрос ApiOperation для отправки элемента в очередь индексирования Cloud Search.

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

В следующем фрагменте кода показано, как использовать класс PushItems.Builder для упаковки идентификаторов и хэш-значений в одну операцию push ApiOperation .

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

Элементы помещаются в очередь индексирования Cloud Search для дальнейшей обработки.

Извлекайте и обрабатывайте каждый элемент

Переопределите getDoc() для обработки каждого элемента в очереди индексирования Cloud Search. Элемент может быть новым, измененным, неизмененным или больше не существовать в исходном репозитории. Извлекайте и индексируйте каждый новый или измененный элемент. Удалите из индекса элементы, которых больше нет в исходном репозитории.

Метод getDoc() принимает элемент из очереди индексирования Cloud Search. Для каждого элемента в очереди выполните следующие шаги в методе getDoc() :

  1. Проверьте, существует ли в репозитории идентификатор элемента в очереди индексирования Cloud Search. Если нет, удалите элемент из индекса. Если элемент существует, перейдите к следующему шагу.

  2. Индекс изменен или добавлены элементы:

    1. Установите разрешения.
    2. Задайте метаданные для индексируемого элемента.
    3. Объедините метаданные и элемент в один индексируемый RepositoryDoc .
    4. Поместите дочерние идентификаторы в очередь индексирования Cloud Search для дальнейшей обработки.
    5. Верните RepositoryDoc .

Обработка удаленных элементов

В следующем фрагменте кода показано, как определить, существует ли элемент в индексе, и, если нет, удалить его.

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

Установите разрешения для элемента

В вашем репозитории используется список контроля доступа (ACL) для идентификации пользователей или групп, имеющих доступ к элементу. ACL — это список идентификаторов групп или пользователей, которые могут получить доступ к элементу.

Вы должны дублировать ACL, используемый вашим репозиторием, чтобы гарантировать, что только те пользователи, у которых есть доступ к элементу, смогут видеть этот элемент в результатах поиска. ACL для элемента должен быть включен при индексировании элемента, чтобы Google Cloud Search имел информацию, необходимую для обеспечения правильного уровня доступа к элементу.

Content Connector SDK предоставляет богатый набор классов и методов ACL для моделирования списков ACL большинства репозиториев. Вы должны проанализировать ACL для каждого элемента в вашем репозитории и создать соответствующий ACL для Google Cloud Search при индексировании элемента. Если в ACL вашего репозитория используются такие концепции, как наследование ACL, моделирование этого ACL может оказаться сложной задачей. Дополнительную информацию о списках ACL Google Cloud Search см. в разделе ACL Google Cloud Search .

Примечание. API индексирования Cloud Search поддерживает однодоменные списки управления доступом. Он не поддерживает междоменные списки управления доступом. Используйте класс Acl.Builder , чтобы настроить доступ к каждому элементу с помощью ACL. Следующий фрагмент кода, взятый из полного примера обхода, позволяет всем пользователям или «принципалам» ( getCustomerPrincipal() ) быть «читателями» всех элементов ( .setReaders() ) при выполнении поиска.

Фуллтраверсалсампле.java
// Make the document publicly readable within the domain
Acl acl = new Acl.Builder()
    .setReaders(Collections.singletonList(Acl.getCustomerPrincipal()))
    .build();

Вам необходимо понимать ACL, чтобы правильно моделировать ACL для репозитория. Например, вы можете индексировать файлы в файловой системе, использующей какую-то модель наследования, при которой дочерние папки наследуют разрешения от родительских папок. Для моделирования наследования ACL требуется дополнительная информация, описанная в ACL Google Cloud Search.

Установите метаданные для элемента

Метаданные хранятся в объекте Item . Чтобы создать Item , вам потребуется как минимум уникальный строковый идентификатор, тип элемента, список управления доступом, URL-адрес и версия элемента. В следующем фрагменте кода показано, как создать Item с помощью вспомогательного класса IndexingItemBuilder .

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

Создайте индексируемый элемент

После того как вы установили метаданные для элемента, вы можете создать фактический индексируемый элемент с помощью RepositoryDoc.Builder . В следующем примере показано, как создать один индексируемый элемент.

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 — это тип ApiOperation , который выполняет фактический запрос IndexingService.indexItem() .

Вы также можете использовать метод setRequestMode() класса RepositoryDoc.Builder , чтобы определить запрос на индексацию как ASYNCHRONOUS или SYNCHRONOUS :

ASYNCHRONOUS
Асинхронный режим приводит к увеличению задержки между индексированием и обслуживанием и обеспечивает большую квоту пропускной способности для запросов индексирования. Асинхронный режим рекомендуется для первоначальной индексации (засыпки) всего репозитория.
SYNCHRONOUS
Синхронный режим приводит к сокращению задержки между индексированием и обслуживанием и обеспечивает ограниченную квоту пропускной способности. Синхронный режим рекомендуется для индексации обновлений и изменений в репозитории. Если не указано, режим запроса по умолчанию SYNCHRONOUS .

Поместите дочерние идентификаторы в очередь индексирования Cloud Search.

В следующем фрагменте кода показано, как включить дочерние идентификаторы обрабатываемого в данный момент родительского элемента в очередь для обработки. Эти идентификаторы обрабатываются после индексации родительского элемента.

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

Следующие шаги

Вот несколько следующих шагов, которые вы можете предпринять:

Создайте соединитель контента с помощью REST API.

В следующих разделах объясняется, как создать соединитель контента с помощью REST API.

Определите свою стратегию обхода

Основная функция соединителя контента — перемещение по репозиторию и индексирование его данных. Вы должны реализовать стратегию обхода, основанную на размере и расположении данных в вашем репозитории. Ниже приведены три распространенные стратегии обхода:

Полная стратегия обхода

Стратегия полного обхода сканирует весь репозиторий и слепо индексирует каждый элемент. Эта стратегия обычно используется, когда у вас небольшой репозиторий и вы можете позволить себе полный обход при каждом индексировании.

Эта стратегия обхода подходит для небольших репозиториев, в основном содержащих статичные, неиерархические данные. Вы также можете использовать эту стратегию обхода, когда обнаружение изменений затруднено или не поддерживается репозиторием.

Стратегия обхода списка

Стратегия обхода списка сканирует весь репозиторий, включая все дочерние узлы, определяя статус каждого элемента. Затем соединитель выполняет второй проход и индексирует только те элементы, которые являются новыми или были обновлены с момента последней индексации. Эта стратегия обычно используется для выполнения дополнительных обновлений существующего индекса (вместо необходимости выполнять полный обход каждый раз при обновлении индекса).

Эта стратегия обхода подходит, когда обнаружение изменений затруднено или не поддерживается репозиторием, у вас есть неиерархические данные и вы работаете с очень большими наборами данных.

Обход графа

Стратегия обхода графа сканирует весь родительский узел, определяя статус каждого элемента. Затем соединитель выполняет второй проход и индексирует только элементы в корневом узле, которые являются новыми или были обновлены с момента последней индексации. Наконец, соединитель передает все дочерние идентификаторы, а затем индексирует новые или обновленные элементы в дочерних узлах. Соединитель продолжает рекурсивно проходить через все дочерние узлы, пока все элементы не будут адресованы. Такой обход обычно используется для иерархических репозиториев, где перечисление всех идентификаторов нецелесообразно.

Эта стратегия подходит, если у вас есть иерархические данные, которые необходимо сканировать, например каталоги серий или веб-страницы.

Реализуйте свою стратегию обхода и индексируйте элементы

Каждый индексируемый элемент Cloud Search в Cloud Search API называется элементом . Элементом может быть файл, папка, строка в CSV-файле или запись базы данных.

После регистрации вашей схемы вы можете заполнить индекс следующим образом:

  1. (необязательно) Использование items.upload для загрузки файлов размером более 100 КБ для индексации. Для файлов меньшего размера встраивайте содержимое как inlineContent с помощью items.index .

  2. (необязательно) Использование media.upload для загрузки медиафайлов для индексирования.

  3. Использование items.index для индексации элемента. Например, если ваша схема использует определение объекта в схеме фильма , запрос на индексацию одного элемента будет выглядеть следующим образом:

    {
      "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. (Необязательно) Использование вызовов items.get для проверки индексации элемента .

Чтобы выполнить полный обход, вам придется периодически переиндексировать весь репозиторий. Чтобы выполнить обход списка или графа, вам необходимо реализовать код для обработки изменений репозитория .

Обработка изменений в репозитории

Вы можете периодически собирать и индексировать каждый элемент из репозитория, чтобы выполнить полную индексацию. Несмотря на то, что полная индексация эффективна для обеспечения актуальности вашего индекса, она может оказаться дорогостоящей при работе с более крупными или иерархическими репозиториями.

Вместо того, чтобы время от времени использовать вызовы индекса для индексации всего репозитория, вы также можете использовать очередь индексирования Google Cloud в качестве механизма для отслеживания изменений и индексирования только тех элементов, которые изменились. Вы можете использовать запросы items.push для помещения элементов в очередь для последующего опроса и обновления. Дополнительную информацию об очереди индексирования Google Cloud см. в разделе Очередь индексирования Google Cloud .

Дополнительную информацию об API Google Cloud Search см. в разделе Cloud Search API .