En mi última piezaEn este artículo, hemos visto la mecánica básica de MySQL y Couchbase Server 2.0, y hemos comparado las formas en las que modelarías los datos, y cómo operan las consultas básicas y las listas de registros, desde la sentencia SQL de MySQL, hasta la Vista de Couchbase Server.
Esta vez, empezaremos viendo cómo escribir esas Vistas y elementos específicos de las consultas SQL, como las cláusulas WHERE y GROUP BY, y el proceso de migrar realmente tus datos y lógica de aplicación a Couchbase Server.
Piense en las consultas que desea ejecutar
Como ya hemos visto, consultar una base de datos de Couchbase Server es en realidad un proceso de dos etapas. La primera etapa consiste en crear una vista sobre tus datos que soporte la búsqueda o selección sobre los documentos de tu base de datos. La segunda parte es la URL y los valores clave que quieres seleccionar de la vista. Esto significa que cuando pienses en cómo quieres obtener la información de tu base de datos Couchbase necesitas pensar en cómo quieres buscar los datos, y eso te permitirá definir la estructura de la vista que necesita ser escrita.
Couchbase Server utiliza vistas para crear listas de documentos de la base de datos, y la salida de una vista es una clave y un valor correspondiente. Tanto las claves como los valores pueden ser cualquier valor JSON. La clave en la salida es significativa porque forma la base del mecanismo de búsqueda, ordenación y paginación.
Por ejemplo, una función de vista que sólo muestre todos los documentos de recetas de la base de datos, utilizando el título de la receta como clave, podría tener este aspecto:
if (doc.type === 'receta' &&
doc.title !== null) {
emit(doc.title, null);
}
}
Esto se denomina función de mapeo: mapea la información de los documentos en el formato que se desee utilizar. Un segundo paso opcional se denomina función de reducción, y es análoga a las funciones de agregación y la cláusula GROUP BY de MySQL.
Al migrar desde MySQL, la construcción de sus vistas para que coincidan con la información que desea mostrar o consultar también puede afectar a la forma de almacenar la información. Volvamos al ejemplo de la receta. En MySQL, utilizaría una consulta en la tabla de ingredientes para hacerla coincidir con zanahoria y obtener una lista de recetas coincidentes. Por ejemplo, como consulta SQL se expresaría como :
(ingredients.recipeid = recipe.id) donde ingredient = 'zanahoria'
En Couchbase, una forma de conseguir el mismo resultado es escribir una vista que genere una fila por cada ingrediente de nuestro documento de receta, de esta forma:
if (doc.type == 'receta' &&
doc.title !== null) {
para id en doc.ingredientes {
emit(doc.ingredients[id].ingredient, null);
}
}
}
Para realizar una consulta, debe especificar la clave de la salida que desea comparar. La consulta se realiza a través de la API REST, o a través de su biblioteca cliente, pero la especificación es la misma. Por ejemplo, si desea buscar "zanahorias", debe especificar ésta como la clave que busca. Uso de la API REST:
Recuerde que la clave es cualquier valor JSON, por lo que los valores clave que proporcione a la consulta también deben estar codificados correctamente en JSON. Como puedes ver en este ejemplo, la vista proporciona la base de tu consulta, y la base de datos accede al mecanismo de selección.
El uso de vistas de este modo significa que la mayoría de las aplicaciones acabarán construyéndose con varias vistas simultáneas. El proceso de creación de vistas no difiere en nada del de creación de consultas principales dentro de la aplicación y, a continuación, optimización de las consultas y los índices que producen el resultado. La principal diferencia es que la definición de la vista se almacena en la base de datos, no como una consulta dentro del código de la aplicación.
Agregaciones
En MySQL la agregación se utiliza en varios lugares diferentes. La agregación se maneja mediante una combinación de la cláusula GROUP BY y funciones que recogen o resumen la información. Utilizando de nuevo nuestro ejemplo de la receta, podríamos ejecutar una consulta que proporcione un recuento de las diferentes recetas por los ingredientes que contienen. Por ejemplo, una consulta como ésta
nos va a proporcionar una lista de ingredientes, con un recuento al lado de cada uno para mostrar cuántas recetas tienen ese ingrediente. En una aplicación final esto va a conformar los 'ingredientes más calientes de la receta', o en otras apps 'la entrada más popular del blog' y así sucesivamente.
Por ejemplo, para obtener el equivalente de lo anterior podemos utilizar la misma función map que hemos utilizado anteriormente. A continuación, podemos utilizar una de las funciones de reducción incorporadas, _count, que producirá un recuento basado en el número de claves únicas emitidas por la función emit(). Si existe una función de reducción, se utiliza automáticamente cuando se accede a la vista. El acceso a la vista produce una lista del número de recetas para ingredientes individuales:
{"clave": "plátano", "valor":20},
{"clave": "plátanos", "valor":33},
{"clave": "baps", "valor":1},
{"clave": "salsa barbacoa", "valor":1},
{"clave": "arroz basmati", "valor":16},
{"clave": "laurel", "valor":58},
{"clave": "hojas de laurel", "valor":35},
{"clave": "brotes de soja", "valor":18},
{"key": "bean thread noodles", "value":1},
{"clave": "filete de ternera a la brasa", "valor":17}
]
}
Las funciones de agregación y reducción también pueden utilizarse para otras operaciones. Por ejemplo, en la parte 1 mostré una receta con información sobre el tiempo de preparación y cocción. Podríamos utilizar una función map y una función reduce para obtener el tiempo total de cocción de cada receta. En primer lugar, escribe una función map que muestre el título de la receta como clave y la información sobre el tiempo de cocción como valor:
if (doc.title) {
emit(doc.title, parseInt(doc.preptime));
emit(doc.title, parseInt(doc.cooktime));
}
}
{"clave": "Tarta de manzana", "valor":55},
{"clave": "Tarta de queso y albaricoque", "valor":70},
{"clave": "Berenjena asada", "valor":10},
{"clave": "Hamburguesas de ternera a la barbacoa", "valor":30},
{"key": "Rodajas de mazorca de maíz a la barbacoa", "value":13},
{"clave": "Carne en vino tinto", "valor":144},
{"key": "Salsa de queso azul y tomate", "value":5},
{"clave": "Pollo cajún", "valor":20},
{"key": "Caribbean cobbler stew", "value":95},
{"key": "Chappati o roti", "value":45}
]
En SQL podríamos simplemente almacenar el tiempo total de cocción en la tabla para facilitar la consulta de esta información. En Couchbase, podemos hacer uso de la capacidad de procesar y combinar información al construir la vista.
Consultas por rangos
Para consultas más complejas, en las que se seleccionan varios campos, es necesario crear una vista adecuada y utilizar el argumento de consulta clave para especificar lo que se busca. Si desea obtener información sobre un intervalo de valores, puede utilizar la clave de inicio y la clave final para especificar el intervalo que debe devolver la vista. Por ejemplo, si construyera una vista con el tiempo de cocción como clave, obtendría una lista de todas las recetas coincidentes en las que el tiempo de cocción estuviera comprendido entre 5 y 25 minutos:
Esto es análogo a:
Consulta de varios campos
Para consultar varios campos, debe crear una vista que muestre los dos (o más) campos que desea consultar. Al buscar recetas, por ejemplo, es bastante común querer buscar recetas con un determinado ingrediente, pero también dentro de un cierto límite de tiempo. Cuando abres la nevera 30 minutos antes de salir y encuentras tomates, quieres saber qué puedes cocinar en 20 minutos con tomates. Para ello, damos salida a una vista que emite una clave con el ingrediente, y el tiempo necesario para cocinar la receta, así:
si (doc.ingredientes) {
para (i=0; i < doc.ingredientes.longitud; i++) { si (doc.ingredientes[i].ingrediente != null)
{
emite([doc.ingredientes[i].ingrediente, parseInt(doc.tiempo total)], null);
}
}
}
}
{“id”:”4997AFDE-3027-11E2-BB0D-B67A7E241592″,”key”:[“tomatoes”,5],”value”:null},
{“id”:”79C16D8A-3027-11E2-BB0D-B67A7E241592″,”key”:[“tomatoes”,5],”value”:null},
{“id”:”CF52D23E-3027-11E2-BB0D-B67A7E241592″,”key”:[“tomatoes”,5],”value”:null},
{“id”:”42F5D520-3027-11E2-BB0D-B67A7E241592″,”key”:[“tomatoes”,6],”value”:null},
{“id”:”1A0AB61C-3027-11E2-BB0D-B67A7E241592″,”key”:[“tomatoes”,8],”value”:null},
{“id”:”4D0F9DF2-3027-11E2-BB0D-B67A7E241592″,”key”:[“tomatoes”,8],”value”:null},
{“id”:”50CE1676-3027-11E2-BB0D-B67A7E241592″,”key”:[“tomatoes”,10],”value”:null},
{“id”:”564A66CC-3027-11E2-BB0D-B67A7E241592″,”key”:[“tomatoes”,10],”value”:null},
{“id”:”95E9464A-3027-11E2-BB0D-B67A7E241592″,”key”:[“tomatoes”,10],”value”:null},
{“id”:”9A78477E-3027-11E2-BB0D-B67A7E241592″,”key”:[“tomatoes”,10],”value”:null}
]
}
Genial. Comparado con la sentencia SQL:
Por cierto, tenga en cuenta que obtenemos el ID de cada documento para poder cargar el documento y, por tanto, la receta. Puede que no tengamos el título de la receta en nuestra salida, pero las bibliotecas cliente pueden cargar automáticamente la información del documento por nosotros. La parte difícil es realizar la búsqueda.
Ordenar la salida de la vista
La ordenación de la salida de una vista es automática. La salida de cada vista se ordena automáticamente por la clave generada por cada vista. Esto es necesario porque, sin ella, la consulta de rangos sería imposible de realizar. Esto hace que algunas operaciones sean rápidas y sencillas. Si desea obtener una lista de recetas ordenadas alfabéticamente por su título, debe crear una vista cuya clave sea el título de la receta. Esto significa que la función map:
{
emit(doc.title, null);
}
Es análogo a:
Para obtener una lista en orden descendente en MySQL se utiliza la palabra clave DESC:
En Couchbase Server se utiliza el parámetro descendente a la URL:
Paginación
En MySQL, la paginación se gestiona utilizando una combinación de las cláusulas LIMIT y OFFSET, por ejemplo para obtener los 10 primeros registros de nuestra consulta sobre el título de la receta:
Para obtener los siguientes 10 registros:
Con Couchbase Server se utiliza una configuración similar, proporcionando los argumentos limit y skip a la consulta de la vista. Para obtener los diez primeros registros:
Y los 10 discos siguientes:
Cuando se trata de bloques de páginas relativamente cortos, esto funciona bien. Para páginas más largas, o cuando se salta potencialmente sobre un gran número de filas de salida, se puede utilizar startkey_docid para saltar hacia adelante dentro de la vista. Esto es más eficiente para estos escenarios de paginación más largos. Compruebe el documentación para más información.
Carga del objeto central
En nuestra base de datos de recetas de ejemplo en MySQL, hay múltiples tablas necesarias para cargar la información de la base de datos sobre una sola receta para que pueda ser mostrada. Dentro de Couchbase Server, una vez que tienes el ID del documento para una receta dada, tienes acceso a toda la estructura de registros de la receta, ya que ha sido almacenada dentro de la base de datos de Couchbase Server.
Con MySQL la necesidad de simplificar el mecanismo de carga para objetos tan complejos ha llevado a una serie de diferentes proyectos de apoyo que pueden ser como una forma de almacenar en caché los datos complejos cargados para que sean más accesibles (memcached, por ejemplo). Couchbase Server no elimina la necesidad de cargar la información desde la base de datos, pero hace que cargar el registro de la receta sea una sola operación, en lugar de múltiples consultas y formateo de esos datos en la estructura utilizada para la visualización.
En SQL, por ejemplo, podría cargar los datos de la receta consultando las tablas individuales y construyendo su objeto, ejecutando una serie de consultas diferentes:
SELECT * FROM ingredientes WHERE recipeid=23434
SELECT * FROM métodos WHERE recipeid=23434
SELECT * FROM palabras clave WHERE recipeid=23434
El resultado son los datos de la receta en formato JSON:
{
"title" : "Pollo asado aromático",
"preptime" : "15",
"raciones" : "6",
"totaltime" : "120",
"subtitle" : "Un relleno de cuscús, y especias aromáticas con lima fragante y ajo asado, convierten un simple pollo asado en algo especial",
"cooktime" : "105",
"palabras clave" : [
"diet@dairy-free",
"método de cocción.placa, horno, grill@horno",
"dieta@sin cacahuetes",
"colecciones especiales@cheffy recomienda",
"diet@corn-free",
"colectas especiales@comida fin de semana",
"ocasión@entretenida",
"colecciones especiales@muy fácil",
"dieta@sin levadura",
"dieta@sin marisco",
"colecciones especiales@sentir el picante",
"ingrediente principal@aves de corral",
"dieta@demi-veg",
"meal type@main",
"diet@egg-free",
"dieta@vaca sin lácteos"
],
"ingredientes" : [
…
],
"método" : [
…
],
}
Una consulta, una petición a la base de datos para cargar todo lo necesario para mostrar la receta en una sola página. Por supuesto, también podría incluirse otro contenido, como comentarios de los usuarios o metadatos adicionales, todo ello almacenado en el mismo documento y a una sola petición de distancia.
Migración de datos
El formato de los datos trae a colación otro punto destacado al pensar en esa migración cuando inicié el proceso. Piensa en tus datos y en cómo se van a utilizar. Si muestras información que, en MySQL, proviene de múltiples fuentes, entonces tiene sentido agrupar esta información y almacenarla en Couchbase Sever como un único documento.
Como ya se ha mencionado, muchos mecanismos de aceleración utilizados con MySQL funcionan sobre la base de almacenar en caché la información una vez que ha sido cargada desde múltiples fuentes para acelerar la carga de estructuras e información tan complejas.
El mismo principio básico es cierto con Couchbase Server, teniendo en cuenta las advertencias que he mencionado anteriormente sobre la estructura. Necesitas estar seguro de que la estructura que creas te permite construir una vista que hace que el contenido sea buscable, si esos datos son la forma en que quieres sacar los documentos de la base de datos.
Por ejemplo, en nuestra estructura de recetas, no tiene sentido almacenar los ingredientes como un único campo de texto y perder el detalle del contenido. Esto es similar a poner todo en una sola columna de texto dentro de MySQL y tiene las mismas trampas; dificulta la búsqueda y consulta de los contenidos, y complica tanto la vista como las posibilidades de visualización.
El proceso de migración en sí debería ser bastante sencillo. Carga la información de MySQL, construye un documento para cada objeto principal de tu base de datos, y luego escribe los documentos en un Couchbase Server. De hecho, puedes incluso usar este método para migrar la información de una aplicación en ejecución. En su lugar, intenta laod el elemento desde Couchbase, y si no existe, cárgalo desde MySQL, luego almacena el objeto construido en Couchbase.
Los documentos en Couchbase se almacenan por su ID. El ID puede ser cualquier cadena que quieras, lo que significa que puedes usar algo identificable para ti o tu aplicación sin tener que depender siempre de una vista para encontrarlo. Para utilizar nuestra siempre presente base de datos de recetas, podrías utilizar el título de la receta, por ejemplo 'Estofado de pescado'. La limitación de este enfoque (al igual que con MySQL y los índices únicos) es que no se pueden almacenar dos documentos con el mismo ID, y hay un montón de recetas diferentes de estofado de pescado por ahí. Como alternativa se podría utilizar un UUID o utilizar el título de la receta con un sufijo para permitir múltiples recetas de "Estofado de Pescado".
Al igual que con la opción de campo AUTO_INCREMENT de MySQL, Couchbase generará automáticamente un UUID para cada documento. Esto no es obligatorio; puedes almacenar tanto documentos un ID de documento específico como IDs autogenerados en la misma base de datos, lo que significa que puedes usar IDs conocidos para almacenar información específica, e IDs autogenerados para el cuerpo principal de datos.
Conclusión
La principal diferencia entre Couchbase y MySQL es la representación de los datos y cómo se accede a ellos. Para ciertos modelos de datos, Couchbase proporciona una solución más simple al problema de cargar los datos de estilo objeto único que hemos visto demostrado en estas piezas. Las recetas son un buen ejemplo donde el elemento clave del almacén de datos es la receta en su conjunto (nuestro documento). La capacidad de buscar y encontrar datos de recetas y presentarlos como una lista es un requisito en términos de la forma en que necesitamos presentar y acceder a los datos, no un requisito relacionado con la forma en que se almacenan.
Esperemos que estos dos posts te hayan dado algunas ideas sobre cómo mover tus datos de MySQL a Couchase Server, y cómo modelar y desarrollar tus datos y código de aplicación de Couchbase Server para hacer que el sistema funcione y opere como tu infraestructura existente basada en MySQL.
#next_pages_container { width: 5px; hight: 5px; position: absolute; top: -100px; left: -100px; z-index: 2147483647 !important; }
#next_pages_container { width: 5px; hight: 5px; position: absolute; top: -100px; left: -100px; z-index: 2147483647 !important; }
#next_pages_container { width: 5px; hight: 5px; position: absolute; top: -100px; left: -100px; z-index: 2147483647 !important; }
#next_pages_container { width: 5px; hight: 5px; position: absolute; top: -100px; left: -100px; z-index: 2147483647 !important; }
#next_pages_container { width: 5px; hight: 5px; position: absolute; top: -100px; left: -100px; z-index: 2147483647 !important; }
#next_pages_container { width: 5px; hight: 5px; position: absolute; top: -100px; left: -100px; z-index: 2147483647 !important; }
#next_pages_container { width: 5px; hight: 5px; position: absolute; top: -100px; left: -100px; z-index: 2147483647 !important; }
Este es un gran artículo. Así que dado lo simple que es el mapeo ¿por qué no podéis proporcionar un lenguaje de consulta SQL, o "SQL like" encima de Couchbase? Quiero decir que Sun fue capaz de hacerlo usando JPQL sobre su proveedor de persistencia :-)
Hola Frank,
Hoy nuestra API de consulta es la vista, y esta expone un conjunto muy simple de métodos para crear consultas, establecer algunos criterios, y ordenar los resultados. Esto se basa en una API REST bajo el capó. Esto es lo que se ve en esta entrada del blog. Esta API aprovecha el concepto de Views, indexado creado usando la función MapReduce en Couchbase. También es importante tener en cuenta que la consulta a Couchbase es casi la misma en todos los idiomas.
Para su segundo punto, usted habla de JPQL, que no es directamente Sun, sino más bien el JCP - por lo que toda la industria de Java -, Couchbase ha trabajado en un esfuerzo de normalización en torno a un lenguaje de consulta para bases de datos NoSQL : http://www.unqlspec.org/
El equipo de I+D de Couchbase está trabajando activamente para ofrecer más opciones de consulta y API en futuras versiones.
Esta serie fue genial para la lectura de datos, pero ¿qué tal un post o dos sobre la escritura de datos? Por ejemplo: la actualización de un solo elemento en una matriz en un documento.
Steve,
Las APIs de escritura a Couchbase son bastante sencillas por el momento usando las operaciones set o delete. Para actualizar el valor de un atributo necesitas establecer el documento. Las actualizaciones a nivel de sub-documento son algo que nos gustaría soportar en el futuro. También estamos investigando un lenguaje de consulta que facilite tanto la consulta de datos como su manipulación. Es probable que primero nos ocupemos de la consulta de datos y después de la manipulación.
Si tiene sugerencias sobre las cláusulas obligatorias que deberíamos apoyar, háganoslo saber. Nos encantaría conocer su opinión.
Me has ayudado mucho :-) Gracias.