En el post anterior vimos un poco de historia y cómo crear nuestro primer servicio, hoy vamos a ver cómo usar este servicio desde .NET.
Instalar el SDK oficial
Al momento de escribir este post, el SDK oficial se encuentra en la versión 0.9.7-preview
, con lo cual soporta sólo una parte de la funcionalidad disponible en la API 2015-02-28
, pero es suficiente para hacer las tareas más comunes. Está disponible en NuGet, bajo el nombre Microsoft.Azure.Search
(no olvidarse de seleccionar «Include Prerelease» para que aparezca en el listado de búsqueda).
Escenarios
Los escenarios que vamos a estar viendo son:
- Creación del índice.
- Inserción de documentos en el índice.
- Búsqueda de documentos usando la búsqueda de texto completo y los filtros.
Creación del índice
Lo primero que vamos a necesitar es crear nuestro SearchIndexClient:
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
public SearchServiceClient GetSearchServiceClient() | |
{ | |
// El nombre del servicio es solamente la primera parte de la URL del servicio, | |
// ej.: https://miservicio.search.windows.net/ | |
string searchServiceName = "miservicio"; | |
string apiKey = "Aquí va una de las keys de administración." | |
SearchServiceClient serviceClient = new SearchServiceClient(searchServiceName, new SearchCredentials(apiKey)); | |
return serviceClient; | |
} |
Luego crearemos nuestro índice, como ejemplo, vamos a usar un índice muy simple de películas:
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
public void CreateIndex(SearchServiceClient searchServiceClient) | |
{ | |
var index = new Index | |
{ | |
Name = "peliculas", | |
Fields = new [] | |
{ | |
new Field("peliculaId", DataType.String) { IsKey = true }, | |
new Field("titulo", DataType.String) { IsSearchable = true, IsFilterable = true }, | |
new Field("director", DataType.String) { IsSearchable = true, IsFilterable = true, IsFacetable = true }, | |
new Field("actores", DataType.Collection(DataType.String)) { IsSearchable = true, IsFilterable = true, IsFacetable = true }, | |
new Field("genero", DataType.String) { IsFilterable = true, IsSortable = true, IsFacetable = true }, | |
new Field("rating", DataType.Int32) { IsFilterable = true, IsSortable = true, IsFacetable = true }, | |
new Field("fechaEstreno", DataType.DateTimeOffset) { IsFilterable = true, IsSortable = true, IsFacetable = true } | |
} | |
}; | |
serviceClient.Indexes.Create(index); | |
} |
Inserción de documentos en el índice
Para insertar documentos en el índice, primero vamos a ver cómo es el formato de esos documentos:
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
[SerializePropertyNamesAsCamelCase] | |
public class Pelicula | |
{ | |
public string PeliculaId { get; set; } | |
public string Titulo { get; set; } | |
public string Director { get; set; } | |
public string[] Actores { get; set; } | |
public string Genero { get; set; } | |
public int? Rating { get; set; } | |
public DateTimeOffset? FechaEstreno { get; set; } | |
} |
El atributo SerializePropertyNamesAsCamelCase
nos permite usar los nombres en Pascal case para nuestro código C#, y que sean convertidas a Camel case para ser serializados en JSON.
Debemos tener en cuenta que las propiedades Rating
y FechaEstreno
de nuestra clase son un int?
y DateTimeOffset?
respectivamente, esto es porque todos los campos primitivos de Azure Search son nullables.
Para poder insertar documentos en el índice, vamos a necesitar primero obtener un SearchIndexClient
:
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
public SearchIndexClient GetIndexClientForPeliculas(SearchServiceClient serviceClient) | |
{ | |
SearchIndexClient indexClient = serviceClient.Indexes.GetClient("peliculas"); | |
return indexClient; | |
} |
Y luego lo usamos para insertar documentos en el índice:
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
public void UploadDocuments(SearchIndexClient indexClient) | |
{ | |
var documents = new Pelicula[] | |
{ | |
new Pelicula | |
{ | |
PeliculaId = "tt2084970", | |
Titulo = "El código enigma", | |
Director = "Morten Tyldum", | |
Actores = new [] { "Benedict Cumberbatch", "Keira Knightley", "Matthew Goode" }, | |
Genero = "Drama", | |
Rating = 8, | |
FechaEstreno = new DateTimeOffset(2014, 12, 25, 0, 0, 0, TimeSpan.Zero), | |
}, | |
new Pelicula | |
{ | |
PeliculaId = "tt0816692", | |
Titulo = "Interestelar", | |
Director = "Christopher Nolan", | |
Actores = new [] { "Matthew McConaughey", "Anne Hathaway", "Jessica Chastain" }, | |
Genero = "Ciencia Ficción", | |
Rating = 9, | |
FechaEstreno = new DateTimeOffset(2014, 11, 7, 0, 0, 0, TimeSpan.Zero), | |
}, | |
new Pelicula | |
{ | |
PeliculaId = "tt1809398", | |
Titulo = "Inquebrantable", | |
Director = "Angelina Jolie", | |
Actores = new [] { "Jack O'Connell", "Takamasa Ishihara", "Domhnall Gleeson" }, | |
Genero = "Drama", | |
Rating = 7, | |
FechaEstreno = new DateTimeOffset(2014, 12, 25, 0, 0, 0, TimeSpan.Zero), | |
}, | |
new Pelicula | |
{ | |
PeliculaId = "tt2278388", | |
Titulo = "El gran hotel Budapest", | |
Director = "Wes Anderson", | |
Actores = new [] { "Ralph Fiennes", "F. Murray Abraham", "Mathieu Amalric" }, | |
Genero = "Comedia", | |
Rating = 8, | |
FechaEstreno = new DateTimeOffset(2014, 3, 28, 0, 0, 0, TimeSpan.Zero), | |
}, | |
new Pelicula | |
{ | |
PeliculaId = "tt2562232", | |
Titulo = "Birdman o (La inesperada virtud de la ignorancia)", | |
Director = "Alejandro González Iñárritu", | |
Actores = new [] { "Michael Keaton", "Zach Galifianakis", "Edward Norton" }, | |
Genero = "Drama", | |
Rating = 8, | |
FechaEstreno = new DateTimeOffset(2014, 11, 14, 0, 0, 0, TimeSpan.Zero), | |
}, | |
}; | |
try | |
{ | |
indexClient.Documents.Index(IndexBatch.Create(documents.Select(doc => IndexAction.Create(doc)))); | |
} | |
catch (IndexBatchException e) | |
{ | |
// Si el servicio está bajo carga, el indexado puede fallar para alguno de los documentos en el lote. | |
// Dependiendo de nuestra aplicación, deberemos tomar medidas para compensar este problema, como | |
// esperar y reintentar, para el ejemplo, simplemente los mostramos en la consola. | |
Console.WriteLine( | |
"No se pudo indexar los siguientes documentos: {0}", | |
String.Join(", ", e.IndexResponse.Results.Where(r => !r.Succeeded).Select(r => r.Key))); | |
} | |
// Esperamos que se complete el indexado (ya que es asíncrono). | |
Thread.Sleep(2000); | |
} |
Búsqueda de documentos
Finalmente, podremos buscar documentos en nuestro índice, usando la búsqueda de texto completo y algunos filtros (opcionales):
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
public IEnumerable<Pelicula> SearchDocuments(SearchIndexClient indexClient, string searchText, string filter = null) | |
{ | |
// Ejecutamos la búsqueda basada en un texto de búsqueda y filtros opcionales | |
var sp = new SearchParameters(); | |
if (!String.IsNullOrEmpty(filter)) | |
{ | |
sp.Filter = filter; | |
} | |
DocumentSearchResponse<Pelicula> response = indexClient.Documents.Search<Pelicula>(searchText, sp); | |
foreach (SearchResult<Pelicula> result in response) | |
{ | |
yield return result.Document; | |
} | |
} |
Espero que les sirva para poder empezar a incorporar búsqueda en sus aplicaciones y sitios web.
Pingback: Introducción a Azure Search | Guillermo Bellmann
Pingback: Sincronización de DocumentDB a Azure Search usando indexadores | Guillermo Bellmann
Pingback: Sincronización de Azure SQL Database a Azure Search usando indexadores | Guillermo Bellmann