Introducción
Si usamos DocumentDB para almacenar los datos de nuestra aplicación, y queremos habilitar la búsqueda de texto completo, mediante un servicio de Azure Search, la mejor opción es utilizar indexadores, que hagan el trabajo de sincronización de nuestros datos hacia el servicio de búsqueda. Actualmente esta funcionalidad no está disponible en el SDK de Azure Search, así que deberemos usar la API.
Conceptos
Azure Search soporta la creación y administración de orígenes de datos (data sources) (incluyendo DocumentDB) e indexadores (indexers) que operan contra estos orígenes de datos.
Un origen de datos especifica qué datos deben ser indexados, las credenciales para acceder a estos datos, y ls políticas para que Azure Search identifique eficientemente los cambios en los datos. Un origen de datos se define de forma independiente para poder ser usado con más de un indexador.
Un idexador describe como fluyen los datos desde un origen de datos hacia el índice de búsqueda. Debería considerarse la creación de un idexador por cada combinación de índice destino y origen de datos. Se pueden tener múltiples indexadores escribiendo en un mismo índice, pero un indexador puede escribir solamente en un índice. Un indexador se usa para:
- Ejecutar una copia de única vez para poblar el índice.
- Sincronizar un índice con los cambios en el origen de datos en un horario programado. Este horario es parte de la definición del indexador.
- Invocar actualizaciones del índice bajo demanda cuando sea necesario.
Paso 1: Crear el origen de datos
Para crear el origen de datos, tenemos que hacer un HTTP POST con los siguientes headers:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
POST https://%5BNombre del servicio de Search].search.windows.net/datasources?api-version=[api-version] | |
Content-Type: application/json | |
api-key: [Key de administrador del servicio de Search] |
El valor de api-version
es obligatorio, y debe ser versión 2015-02-28
o superior.
El body del request contiene la definición del origen de datos, que debe incluir los siguientes campos:
- name: el nombre del origen de datos (debe ser en minúsculas).
- type: usar documentdb.
- credentials:
- connectionString: Requerido. Especificar la información de conexión a la base de datos de Azure DocumentDB con el siguiente formato:
AccountEndpoint=<url del endpoint de DocumentDB>;AccountKey=<key de autorización de DocumentDB>;Database=<id de la base de datos de DocumentDB>
- connectionString: Requerido. Especificar la información de conexión a la base de datos de Azure DocumentDB con el siguiente formato:
- container:
- name: Requerido. Especificar la collection de DocumentDB a indexar.
- query: Opcional. Se puede especificar una query para aplanar un JSON arbitrario a un esquema plano que Azure Search pueda indexar.
- dataChangeDetectionPolicy: Opcional. Explicación a continuación.
- dataDeletionDetectionPolicy: Opcional. Explicación a continuación.
Capturando los documentos modificados
El propósito de la política de detección de cambios es el de identificar eficientemente los items cambiados. Actualmente la única política soportada es la política High Water Mark
usando la propiedad _ts
de timestamp de última modificación provista por DocumentDB, y se especifica de la siguiente manera:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"@odata.type" : "#Microsoft.Azure.Search.HighWaterMarkChangeDetectionPolicy", | |
"highWaterMarkColumnName" : "_ts" | |
} |
También deberemos agregar el campo _ts
en nuestra proyección y en el WHERE
de nuestra consulta. Por ejemplo:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
SELECT p.id, p.Titulo, p.Director, p.Genero, p._ts FROM Peliculas p WHERE p._ts > @HighWaterMark |
Capturando los documentos eliminados
Cuando se borran elementos de nuestra base de datos, debemos eliminarlo también de nuestro índice. El propósito de la política de detección de eliminaciones es el de identificar eficientemente los documentos eliminados. Actualmente, la única política soportada es la de Soft Delete
(el borrado lógico marcado de alguna manera), que se especifica como:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"@odata.type" : "#Microsoft.Azure.Search.SoftDeleteColumnDeletionDetectionPolicy", | |
"softDeleteColumnName" : "la propiedad que especifica si un documento fue eliminado", | |
"softDeleteMarkerValue" : "el valor que identifica a un documento como borrado" | |
} |
Deberemos incluir esta propiedad en la cláusula SELECT
si estamos haciendo una proyección custom.
Ejemplo del body completo del Request
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"name": "miorigendedatosdocumentdb", | |
"type": "documentdb", | |
"credentials": { | |
"connectionString": "AccountEndpoint=https://miServicioDocumentDb.documents.azure.com;AccountKey=miKeyDeAutorizacionDocDb;Database=idDeMiBaseDeDatosDocDb" | |
}, | |
"container": { | |
"name": "idDeLaColeccionDocDb", | |
"query": "SELECT p.id, p.Titulo, p.Director, p.Genero, p._ts FROM Peliculas p WHERE p._ts > @HighWaterMark" | |
}, | |
"dataChangeDetectionPolicy": { | |
"@odata.type": "#Microsoft.Azure.Search.HighWaterMarkChangeDetectionPolicy", | |
"highWaterMarkColumnName": "_ts" | |
}, | |
"dataDeletionDetectionPolicy": { | |
"@odata.type": "#Microsoft.Azure.Search.SoftDeleteColumnDeletionDetectionPolicy", | |
"softDeleteColumnName": "borrado", | |
"softDeleteMarkerValue": "true" | |
} | |
} |
Response
Si el origen de datos se creó correctamente, se recibirá un response HTTP 201 Created.
Paso 2: Crear un índice
Si todavía no tenemos un índice en nuestro servicio de Azure Search, deberemos crear uno. Podemos crearlo desde el nuevo portal de Azure, o vía API, con un POST HTTP:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
POST https://%5BNombre del servicio de Search].search.windows.net/indexes?api-version=[api-version] | |
Content-Type: application/json | |
api-key: [Key de administrador del servicio de Search] |
Deberemos asegurarnos que el schema de nuestro índice sea compatible con el schema de los documentos JSON de nuestra consulta:
Tipo de dato JSON | Tipo de campo compatible en el índice destino |
---|---|
Bool | Edm.Boolean, Edm.String |
Números que se ven como enteros | Edm.Int32, Edm.Int64, Edm.String |
Números que se ven como de punto flotante | Edm.Double, Edm.String |
Cadenas de texto | Edm.String |
Vectores de datos primitivos (EJ.: [«a», «b», «c»]) | Collection(Edm.String) |
Cadenas de texto que se vean como fechas | Edm.DateTimeOffset, Edm.String |
Objetos JSON | No disponible |
Ejemplo del body del Request
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"name": "miindicedesearch", | |
"fields": [{ | |
"name": "id", | |
"type": "Edm.String", | |
"key": true, | |
"searchable": false | |
}, { | |
"name": "descripcion", | |
"type": "Edm.String", | |
"filterable": false, | |
"sortable": false, | |
"facetable": false, | |
"suggestions": true | |
}] | |
} |
Response
Si el índice se creó correctamente, recibiremos un response HTTP 201 Created.
Paso 3: Crear el indexador
Podemos crear un nuevo indexador haciendo un POST HTTP con los siguientes headers:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
POST https://%5BNombre del servicio de Search].search.windows.net/indexers?api-version=[api-version] | |
Content-Type: application/json | |
api-key: [Key de administrador del servicio de Search] |
En el body del request deberemos incluir la definición del indexador, que deberá incluir:
- name: Requerido. El nombre del indexador.
- dataSourceName: Requerido. El nombre del origen de datos.
- targetIndexName: Requerido. El nombre del índice destino.
- schedule: Opcional. Veremos esto a continuación.
Correr un indexador en forma recurrente
Si lo deseamos, podemos hacer que nuestro indexador se ejecute recurrentemente cada cierto tiempo, usando el campo schedule, junto con los siguientes datos:
- interval: Requerido. Un valor de tiempo que indica cada cuando correrá el indexador. El menor intervalo permitido es de 5 minutos, y el más largo de 1 día. Debe estar formateado como un valor XSD «dayTimeDuration» (un subconjunto restringido del valor de duración ISO 8601). El patrón para esto es:
P[nD][T[nH][nM]]
. Por ejemplo:PT15M
para ejecutar cada 15 minutos,PT2H
para ejecutar cada 2 horas. - startTime: Requerido. Una especificación de fecha y hora UTC que especifica cuándo debería comenzar a ejecutarse el indexador.
Ejemplo del body del Request
El ejemplo crea un indexador que copia los datos del origen de datos creado en el Paso 1, al índice creado en el Paso 2, comenzando el 1 de abril de 2015, y corriendo una vez por hora.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"name" : "miindexadordesearch", | |
"dataSourceName" : "miorigendedatosdocumentdb", | |
"targetIndexName" : "miindicedesearch", | |
"schedule" : { "interval" : "PT1H", "startTime" : "2015-04-01T00:00:00Z" } | |
} |
Response
Si el indexador fue creado correctamente recibiremos un response HTTP 201 Created.
Paso 4: Correr el indexador
Aparte de poder correr periódicamente, a horarios programados, un indexador puede ser invocado bajo demanda a través de un POST HTTP:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
POST https://%5BNombre del servicio de Search].search.windows.net/indexers/[nombre del indexador]/run?api-version=[api-version] | |
api-key: [Key de administrador del servicio de Search] |
Response
Si se invocó exitosamente el indexador, recibiremos un response HTTP 202 Accepted.
Paso 5: Obtener el estado del indexador
Con un GET HTTP podemos conocer el estado actual y el hostorial de ejecución de un indexador:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
GET https://%5BNombre del servicio de Search].search.windows.net/indexers/[nombre del indexador]/status?api-version=[api-version] | |
api-key: [Key de administrador del servicio de Search] |
Response
Recibiremos un response HTTP 200 OK, que en el body contiene el dato del estado del indexador, el resultado de la última corrida, y el historial de las invocaciones recientes (si existieran).
El response debería verse similar a lo siguiente:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"status":"running", | |
"lastResult": { | |
"status":"success", | |
"errorMessage":null, | |
"startTime":"2015-04-01T02:37:18.853Z", | |
"endTime":"2015-04-01T02:37:19.012Z", | |
"errors":[], | |
"itemsProcessed":2501, | |
"itemsFailed":0, | |
"initialTrackingState":null, | |
"finalTrackingState":null | |
}, | |
"executionHistory":[ { | |
"status":"success", | |
"errorMessage":null, | |
"startTime":"2015-04-01T02:37:18.853Z", | |
"endTime":"2015-04-01T02:37:19.012Z", | |
"errors":[], | |
"itemsProcessed":2501, | |
"itemsFailed":0, | |
"initialTrackingState":null, | |
"finalTrackingState":null | |
}] | |
} |
El historial de ejecución contiene las 50 ejecuciones completadas más recientes, en orden cronológico inverso.
Espero que les haya sido útil.
Más información
Si quieren aprender más sobre Azure Search, pueden ver una Introducción a Azure Search y Usando Azure Search desde .NET.
Si quieren aprender más sobre DocumentDB, pueden ver una Introducción a DocumentDB.
Pingback: Sincronización de Azure SQL Database a Azure Search usando indexadores | Guillermo Bellmann