Creación de vistas (MapReduce)
Visión general
Las vistas pueden ser estructuras de datos secundarias en IBM® Cloudant® for IBM Cloud®, que almacenan pares clave/valor derivados de los atributos del documento. Pueden utilizarse para consultar y agregar proyecciones de documentos.
Tienen dos finalidades principales:
- Indexación (proyección): Utilice vistas de sólo mapa para proyectar documentos en nuevos espacios clave. Esto permite realizar búsquedas y clasificaciones eficaces por campos distintos del ID del documento (por ejemplo, correo electrónico, fecha y hora o categoría).
- Agregación y análisis: Utilice las vistas de MapReduce para emitir y agregar datos entre documentos; por ejemplo, contar documentos por tipo, sumar valores o calcular promedios.
Cómo funcionan las vistas
Las vistas se definen en los documentos de diseño y consisten en:
- Una función de mapa ( JavaScript ): Ejecutada contra cada documento para determinar qué atributos forman la clave y el valor de la vista. Una función map puede emitir cero, una o muchas filas por documento.
- Una función de reducción opcional: Se utiliza para agregar valores emitidos, soportando operaciones como contar, sumar o promediar.
Una vez creadas, las vistas se mantienen y actualizan automáticamente en IBM Cloudant a medida que cambian los documentos.
Para bases de datos particionadas, las vistas pueden operar en una única partición cuando options.partitioned se establece en true en el documento de diseño.
Cuándo utilizar las vistas
Las vistas son ideales para:
- Búsquedas y consultas de rango eficaces en atributos de documentos distintos del ID (por ejemplo, buscar documentos por correo electrónico del cliente o estado del pedido).
- Índices de cobertura: Consultas que pueden satisfacerse utilizando únicamente los datos clave/valor de la vista, evitando la necesidad de obtener documentos completos.
- Resúmenes agregados: Genere totales, medias o recuentos agrupados por claves (por ejemplo, ventas por año/mes/día).
- Índices parciales: Incluyendo sólo un subconjunto de documentos (por ejemplo, una lista sólo de pedidos de comercio electrónico completados).
Cuándo no utilizar las vistas
Evitar vistas para:
- Consultas ad hoc- utilice Cloudant Search en su lugar.
- Búsquedas de texto libre o con comodines: utilice Cloudant Search.
Una vista simple
La forma más simple de vista es una función de correlación (map). La función de correlación genera datos de salida que representan un análisis (una correlación) de los documentos almacenados en la base de datos.
Por ejemplo, es posible que desee averiguar qué usuario ha completado el registro en línea y tiene un correo electrónico verificado de contacto. Para encontrar esta información, inspeccione cada documento, busque un campo en el documento denominado
"email_verified" y obtenga el valor de "email". Si el campo está presente y tiene el valor « true », significa que el usuario ha completado el registro y que puedes ponerte en contacto con él por correo electrónico.
Si el campo no está presente o tiene un valor distinto de true, el usuario no ha completado el registro.
El uso de la función emit en una función de vista facilita la creación de una lista como respuesta a la ejecución de una consulta utilizando la vista. La lista consta de pares de clave y valor, donde la clave le ayuda a identificar
el documento específico y el valor proporciona el detalle preciso que desea. La lista también incluye metadatos, como por ejemplo el número de pares key:value que se devuelven.
El _id del documento se incluye automáticamente en cada uno de los registros del resultado del par key:value. El _id del documento se incluye para facilitar el trabajo que llevará a cabo el cliente con
los resultados.
Consulte un ejemplo de una vista simple utilizando una función de correlación:
function(user) {
if(user.email_verified === true) {
emit(user.email, {name: user.name, email_verified: user.email_verified, joined: user.joined});
}
}
Consulte los datos de ejemplo para demostrar el ejemplo de vista simple:
[
{
"_id":"abc123",
"name": "Bob Smith",
"email": "bob.smith@aol.com",
"email_verified": true,
"joined": "2019-01-24T10:42:59.000Z"
},
{
"_id":"abc125",
"name": "Amelie Smith",
"email": "amelie.smith@aol.com",
"email_verified": true,
"joined": "2020-04-24T10:42:59.000Z"
}
]
Consulte una respuesta de ejemplo de la ejecución de la consulta de la vista simple:
{
"total_rows": 2,
"offset": 0,
"rows": [
{
"id": "abc125",
"key": "amelie.smith@aol.com",
"value": {
"name": "Amelie Smith",
"email_verified": true,
"joined": "2020-04-24T10:42:59.000Z"
}
},
{
"id": "abc123",
"key": "bob.smith@aol.com",
"value": {
"name": "Bob Smith",
"email_verified": true,
"joined": "2019-01-24T10:42:59.000Z"
}
}
]
}
Ejemplos de funciones de correlación
La definición de una vista en un documento de diseño también crea un índice basado en la información de claves. La producción y el uso del índice aumentan significativamente la velocidad de acceso y la búsqueda o la selección de documentos en la vista.
En las siguientes secciones, se describen la indexación con claves simples y complejas, y las funciones de reducción.
Las funciones de indexación funcionan en un entorno con restricciones de memoria donde el documento forma parte de la memoria utilizada en el entorno. La pila y el documento de su código deben caber dentro de la memoria. Limitamos los documentos a un tamaño máximo de 64 MB.
Indexación de un campo
La siguiente función de correlación comprueba si el objeto tiene un campo name y, si es así, emite el valor de este campo. Con esta comprobación, puede consultar el valor del campo name.
Consulte un ejemplo de indexación de un campo:
function(doc) {
if (doc.name) {
emit("name", doc.name);
}
}
Un índice para una relación entre uno y muchos
Si el objeto que se pasa a emit tiene un campo _id, una consulta de vista con include_docs establecida en true contiene el documento con el ID específico.
Consulte un ejemplo de indexación de una relación entre uno y muchos:
function(doc) {
if (doc.friends) {
for (friend in doc.friends) {
emit(doc._id, { "_id": friend });
}
}
}
Claves complejas
Las claves no están limitadas a valores simples. Puede utilizar valores JSON arbitrarios para influir sobre la clasificación.
Cuando la clave es una matriz, los resultados de una vista se pueden agrupar por una subsección de la clave. Por ejemplo, si las claves tienen el formato [year, month, day], los resultados se pueden reducir a un solo valor por
año, mes o día.
Para obtener más información, consulte Utilización de vistas.
Aprovechar el valor
El segundo parámetro de la función emit de una definición MapReduce es el "valor", que se almacena junto con la clave en el índice resultante. El valor tiene dos usos:
- En el caso de las vistas de sólo selección, el valor puede utilizarse para almacenar un subconjunto del documento y evitar tener que utilizar
?include_docs=trueen el momento de la consulta. Esto puede aumentar el rendimiento de la consulta a costa de tener un índice más grande. - Para las vistas que utilizan un reductor, el valor contendrá generalmente una única cantidad numérica, un pequeño objeto con claves fijas y valores numéricos, o una breve matriz de números. Los datos numéricos se suman (con el reductor
_sum) o producen datos estadísticos con el reductor_stats.
Algunos ejemplos:
// create a view to allow selection of orders by year/month/day,
// where a subset of the document is projected into the view's value.
function(doc) {
if (doc.type === 'order') {
const minidoc = {
customer_id: doc.customer_id,
date: doc.date,
status: doc.status
}
emit([doc.year, doc.month, doc.day], minidoc)
}
}
// create a view, designed for the _sum reducer which contains
// one row per order, in year/month/day order where the value
// is the order's total in USD. This can be summed at query-time
// with optional grouping by year, year/month or year/month/day.
function(doc) {
emit([doc.year, doc.month, doc.day], doc.order_total_usd)
}
// create a view, designed for the _sum reducer which contains
// one row per order, in year/month/day order where the value
// contains three numeric quantities (order total, tax and shipping)
// which will be summed at query-time with optional grouping by year,
// year/month or year/month/day.
function(doc) {
const value = {
total: doc.order_total_usd,
tax: doc.tax_usd,
shipping: doc.shipping_usd
}
emit([doc.year, doc.month, doc.day], value)
}
// create a view, designed for the _sum reducer which contains
// one row per order, with customer_id as the key. The numeric
// quantities are in array (order total and tax) which will be
// summed at query-time with optional grouping by customer_id
function(doc) {
emit(doc.customer_id, [doc.order_total_usd, doc.tax_usd])
}
No ponga claves de alta cardinalidad en el valor de una vista como order_id o
customer_id ya que esto provocará una ampliación del valor reducido de una vista en lugar de una reducción. Estas consultas pueden agotarse o ser rechazadas por el IBM Cloudant servicio. Para los reductores numéricos,
los datos de alta cardinalidad suelen ser un componente de la "clave" de una vista, y el "valor" se reserva para los datos numéricos.
Funciones de reducción
Los documentos de diseño con options.partitioned establecido en true no pueden contener funciones de reducción de JavaScript personalizadas. Solo se permiten las reducciones incorporadas.
Sin reductor
Una definición de vista dentro de un documento de diseño puede no tener ningún atributo de reducción, lo que indica que no se realiza ninguna agregación en tiempo de consulta.
{
"views": {
"getVerifiedEmails": {
"map": "function(user) { if(user.email_verified === true) { emit(user.email); } }"
}
}
}
La función de correlación anterior genera un índice secundario que solo se puede seleccionar. El índice siempre está ordenado por la clave (el primer parámetro de la función de emisión), que en este caso es user.email. Esta vista
es ideal para captar documentos por un correo electrónico de usuario conocido o por rangos de direcciones de correo electrónico de usuarios.
Funciones de reducción incorporadas
Por motivos de rendimiento, se crean algunas funciones de reducción simples. Siempre que sea posible, debe utilizar una de estas funciones en lugar de escribir la suya propia.
Para utilizar una de las funciones integradas, introduce el nombre del reductor en el campo « reduce » del objeto «view» de tu documento de diseño.
Reductor de recuento
El reductor _count cuenta las filas de una vista MapReduce y, opcionalmente, agrupa los recuentos por claves distintas.
{
"views": {
"teamCount": {
"map": "function(doc) { if (doc.email_verified === true) { emit(doc.team, doc.name); } }",
"reduce": "_count"
}
}
}
La vista MapReduce anterior crea un índice que tiene como clave la team a la que pertenece el usuario, pero sólo incluye a aquellos con una dirección de correo electrónico verificada. Como el reductor es _count,
la vista muestra el número de filas en la vista, por ejemplo, el número de usuarios verificados en la base de datos.
{"rows":[
{"key":null,"value":10010}
]}
Añadiendo ?group=true, los recuentos se agrupan por claves distintas para que la base de datos genere recuentos por pertenencia al equipo:
{"rows":[
{"key":"blue","value":1409},
{"key":"green","value":1439},
{"key":"indigo","value":1425},
{"key":"orange","value":1432},
{"key":"red","value":1414},
{"key":"violet","value":1443},
{"key":"yellow","value":1448}
]}
La desactivación del reductor permite utilizar la misma vista para la selección de los miembros de un solo equipo ?key="orange"&reduce=false&limit=5:
{"total_rows":10010,"offset":4273,"rows":[
{"id":"783173e102613c78d02a2b3304001642","key":"orange","value":"Bethel Lusk"},
{"id":"783173e102613c78d02a2b3304001b40","key":"orange","value":"Ethyl Dionne"},
{"id":"783173e102613c78d02a2b3304009c66","key":"orange","value":"Fredda Hendrix"},
{"id":"783173e102613c78d02a2b330401800d","key":"orange","value":"Bibi Page"},
{"id":"783173e102613c78d02a2b3304018ae7","key":"orange","value":"Marylou Lavender-Milton"}
]}
Suma reductora
El reductor _sum totaliza los valores numéricos emitidos por una vista MapReduce. El valor de la vista puede ser un número, una matriz de números o un objeto que contenga valores numéricos. Considere la siguiente definición
MapReduce en una base de datos de productos:
{
"views": {
"productPrices": {
"map": "function(doc) { emit(doc.type, { price: doc.price, tax: doc.tax }); }",
"reduce": "_sum"
}
}
}
La vista se basa en el tipo de producto, y el valor es un objeto que contiene dos valores: price y tax. El reductor _sum calcula los totales de los valores price y tax en toda
la vista:
{"rows":[
{"key":null,"value":{"price":144.97, "tax":7.32}}
]}
Añadiendo ?group=true al consultar la vista, la salida se agrupa y suma por una clave única, en este caso, el tipo de producto:
{"rows":[
{"key":"kitchen","value":{"price":14.99,"tax":1.14}},
{"key":"garden","value":{"price":129.98,"tax":6.18}}
]}
Reductor de estadísticas
Al igual que el reductor _sum, el reductor _stats trabaja con números, objetos con valores numéricos o matrices de números, devolviendo recuentos, sumas, valores mínimos y máximos y una suma del cuadrado de los
valores, lo que resulta útil para cálculos de varianza o desviación estándar:
{
"views": {
"salesByDate": {
"map": "function(doc) { emit(doc.date, [doc.price, doc.tax]); }",
"reduce": "_stats"
}
}
}
La definición anterior calcula estadísticas sobre los valores numéricos que encuentra en la matriz que se devuelve como valor del índice. Los valores se devuelven como una matriz en el mismo orden en que se proporciona en la función de correlación:
{"rows":[
{"key":"2025-01-01","value":[
{"sum":14.99,"count":1,"min":14.99,"max":14.99,"sumsqr":224.7001},
{"sum":1.14,"count":1,"min":1.14,"max":1.14,"sumsqr":1.2995}
]},
{"key":"2025-01-02","value":[
{"sum":129.98,"count":2,"min":29.99,"max":99.99,"sumsqr":10897.4002},
{"sum":6.18,"count":2,"min":1.62,"max":4.56,"sumsqr":23.418}
]}
]}
El recuento aproximado distinto reductor
A diferencia de los reductores numéricos _sum y _stats que actúan sobre el valor del índice, el reductor _approx_count_distinct utiliza la clave de la vista. Estima el número de claves distintas
encontradas en la vista MapReduce mediante un algoritmo que utiliza mucha menos memoria que la que consumiría un algoritmo de recuento exacto de claves distintas:
{
"views": {
"estimateIpCount": {
"map": "function (doc) {\n emit(doc.ip, 1);\n}",
"reduce": "_approx_count_distinct"
}
}
}
La definición de vista anterior pretende estimar el número de direcciones IP distintas en una base de datos de registros de servidores. El documento ip se emite como clave del índice para que el reductor _approx_count_distinct pueda estimar el recuento de claves distintas:
{"rows":[
{"key":null,"value":100528}
]}
Los reductores superior/inferior
Los reductores _top_x y _bottom_x (donde x es un número entre 1 y 100) devuelven una matriz de los valores x superior o x inferior de una agrupación de vistas, respectivamente. Por ejemplo,
en una aplicación de juegos, se puede crear una vista cuya clave sea el identificador de usuario y cuyo valor sea la puntuación que ha conseguido el usuario. Esta vista puede utilizarse para crear un marcador de las mejores o peores puntuaciones:
{
"views": {
"bestScores": {
"map": "function(doc) { emit(doc.user_id, doc.score); }",
"reduce": "_top_3"
}
}
}
Si consultamos la vista sin ningún parámetro, se devuelven las tres puntuaciones más altas de toda la vista:
{"rows":[
{"key":null,"value":[99,98,97]}
]}
Con la agrupación (?group=true), se devuelven las tres mejores puntuaciones de cada usuario:
{"rows":[
{"key":"user082","value":[99,98,97]},
{"key":"user291","value":[85,72,42]},
{"key":"user452","value":[55,51,30]}
]}
Los primeros/últimos reductores
Los reductores _first/_last devuelven el valor de la primera o última clave de una agrupación de vistas, respectivamente. Si tenemos una aplicación IoT que almacena lecturas de muchos dispositivos
periódicamente, podemos crear una vista con el identificador del dispositivo y la hora en que se tomó la lectura. El valor de la vista es el documento completo:
{
"views": {
"latestReading": {
"map": "function(doc) { emit([doc.deviceid, doc.timestamp], doc); }",
"reduce": "_last"
}
}
}
Esta vista produce claves y valores de esta forma, con la vista ordenada por deviceid y timestamp. Se resaltan las filas que consideran las lecturas "primera" y "última" de cada dispositivo:
| clave | valor | Primera lectura ( group_level=1 ) | Última lectura ( group_level=1 ) |
|---|---|---|---|
| ["A00", "2025-01-01T10:00:00.000Z"] | {"_id": "A00:5000","reading": 65,"timestamp":2025-01-01T10:00:00.000Z","deviceid":"A00"} | x | |
| ["A00", "2025-01-01T10:01:00.000Z"] | {"_id": "A00:5001","reading": 64,"timestamp":2025-01-01T10:01:00.000Z","deviceid":"A00"} | ||
| ["A00", "2025-01-01T10:02:00.000Z"] | {"_id": "A00:5002","reading": 59,"timestamp":2025-01-01T10:02:00.000Z","deviceid":"A00"} | x | |
| ["A01", "2025-01-01T10:00:00.000Z"] | {"_id": "A01:8000","reading": 12,"timestamp":2025-01-01T10:00:00.000Z","deviceid":"A01"} | x | |
| ["A01", "2025-01-01T10:01:00.000Z"] | {"_id": "A01:8001","reading": 15,"timestamp":2025-01-01T10:01:00.000Z","deviceid":"A01"} | ||
| ["A01", "2025-01-01T10:02:00.000Z"] | {"_id": "A01:8002","reading": 19,"timestamp":2025-01-01T10:02:00.000Z","deviceid":"A01"} | x | |
| ["A02", "2025-01-01T10:00:00.000Z"] | {"_id": "A02:4000","reading": 55,"timestamp":2025-01-01T10:00:00.000Z","deviceid":"A02"} | x | |
| ["A02", "2025-01-01T10:01:00.000Z"] | {"_id": "A02:4001","reading": 54,"timestamp":2025-01-01T10:01:00.000Z","deviceid":"A02"} | ||
| ["A02", "2025-01-01T10:02:00.000Z"] | {"_id": "A01:4002","reading": 56,"timestamp":2025-01-01T10:02:00.000Z","deviceid":"A02"} | x |
La consulta de la vista con group_level=1, utilizando el reductor _last, devolverá la lectura más reciente para cada device_id de la base de datos:
{"rows":[
{"key":["A00"],"value":{"_id":"93117567370d41d091b8dd160a3adf3f","_rev":"1-bc05e93e592d5a5a18e240240b581a55","deviceid":"A00","reading":13.8986,"timestamp":"2025-03-26T04:44:08.917Z","status":"red"}},
{"key":["A01"],"value":{"_id":"c9f53ac9e4a8444487ed0eaa11dc1c78","_rev":"1-1fcf121c73db03e49bac4c1981518b19","deviceid":"A01","reading":59.8453,"timestamp":"2025-04-01T01:52:34.254Z","status":"green"}},
{"key":["A02"],"value":{"_id":"577b7108a8a1458f9a17194ed1da398a","_rev":"1-71d345a773ab31f35ceb998f3c107c41","deviceid":"A02","reading":2.6208,"timestamp":"2025-03-31T00:22:17.175Z","status":"green"}},
{"key":["A03"],"value":{"_id":"150839b1d363427496a4f4e2917b8b1d","_rev":"1-860a2ed5f1f48aa642495dfb21dff3ce","deviceid":"A03","reading":55.8677,"timestamp":"2025-03-22T10:15:57.890Z","status":"red"}},
{"key":["A04"],"value":{"_id":"d3317bdc1f7b4466ae6bf7a30ca9e328","_rev":"1-a58762532f6980ca5b06a8d01d113814","deviceid":"A04","reading":44.1822,"timestamp":"2025-03-23T10:56:10.639Z","status":"green"}},
{"key":["A05"],"value":{"_id":"946754d3762f44e297ca20d13bbceb5e","_rev":"1-41fa2bb3ef8782c90b28ee44628abeab","deviceid":"A05","reading":13.2874,"timestamp":"2025-03-27T13:59:04.723Z","status":"blue"}},
{"key":["A06"],"value":{"_id":"bbcd8a5c0ae948baae713a9fcb5262d5","_rev":"1-66883211ee20a0772374672aa175dc50","deviceid":"A06","reading":7.9525,"timestamp":"2025-04-01T15:13:04.305Z","status":"blue"}},
{"key":["A07"],"value":{"_id":"a600caccdb82400698b158ecebfaa6f2","_rev":"1-68975a8d7133a13c6cc8ae34d28ea1c6","deviceid":"A07","reading":89.4818,"timestamp":"2025-03-07T02:12:59.934Z","status":"blue"}},
{"key":["A08"],"value":{"_id":"be20bae911db4da685f891fd01e07d3a","_rev":"1-d69b559627cf01e80fe85ea2f54d2f4b","deviceid":"A08","reading":97.6739,"timestamp":"2025-03-29T13:46:31.689Z","status":"green"}},
{"key":["A09"],"value":{"_id":"96526e80f2ff48e89e9e42aa47abae24","_rev":"1-85e56901f7113d7d6ff8ba573c535eb3","deviceid":"A09","reading":26.1597,"timestamp":"2025-03-18T03:22:19.848Z","status":"blue"}}
]}
Resumen de los reductores integrados
| Función | Descripción |
|---|---|
_count |
Genera el recuento de filas para una clave específica. Los valores pueden ser cualquier JSON válido. |
_stats |
Genera una estructura JSON que contiene la suma, el recuento y los valores mínimo, máximo y suma de cuadrados. Todos los valores deben ser numéricos. |
_sum |
Genera la suma de todos los valores para una clave. Los valores deben ser numéricos. |
_approx_count_distinct |
Calcula aproximadamente el número de claves distintas en un índice de vista utilizando una variante del HyperLogLog algoritmo. |
_top_x/_bottom_x |
Devuelve una matriz de los valores x superior o x inferior de la agrupación de vistas como una matriz, donde x es un número entre 1 y 100. |
_first/_last |
Devuelve los valores de la clave de ordenación más baja o más alta, respectivamente, para cada grupo de vistas. |
Funciones de reducción personalizadas
La mayoría de los clientes encuentran que los reductores integrados son suficientes para realizar agregaciones en los pares de clave y valor (key-value) de la vista emitidos desde sus funciones Map. Sin embargo, para casos inusuales,
se puede proporcionar una función de reducción de JavaScript en lugar del nombre de uno de los reductores incorporados.
Las funciones de reducción personalizadas son mucho más lentas y difíciles de mantener que los reductores integrados, así que comprueba si un caso de uso puede satisfacerse con un reductor integrado antes de escribir uno personalizado.
A las funciones de reducción se les pasan tres argumentos en el orden siguiente:
keysvaluesrereduce
Si una vista tiene una función de reducción de JavaScript personalizada, se utiliza para generar resultados de la agregación para esa vista. A una función de reducción se le pasa un conjunto de valores intermedios y los combina en un único valor. Una función de reducción debe aceptar, como entrada, los resultados emitidos por su función de correlación correspondiente, así como los resultados que devuelve la propia función de reducción. Este último caso se conoce como "rereducción".
En el ejemplo siguiente se muestra una descripción de las funciones de reducción.
Consulte el ejemplo siguiente de una función de reducción personalizada:
function (keys, values, rereduce) {
return sum(values);
}
Las funciones de reducción deben gestionar dos casos:
-
Cuando
rereducetiene el valor false:keyses una matriz cuyos elementos son matrices con el formato[key, id], dondekeyes una clave emitida por la función de correlación eididentifica el documento a partir del que se ha generado la clave yvalueses una matriz de los valores emitidos para los elementos correspondientes enkeys, por ejemplo:reduce([ [key1,id1], [key2,id2], [key3,id3] ], [value1,value2,value3], false).
-
Si
rereducetiene el valor true:keysesnull.valueses una matriz de valores que devuelven las llamadas anteriores a la función de reducción, como por ejemplo:reduce(null, [intermediate1,intermediate2,intermediate3], true).
Las funciones de reducción deben devolver un solo valor, adecuado para el campo value de la vista final y como miembro de la matriz values que se pasa a la función reduce.
A menudo se pueden escribir funciones de reducción para manejar las llamadas rereduce sin necesidad de código adicional, como la función de suma del ejemplo anterior. En estos casos, el argumento rereduce se puede pasar por alto.
Al devolver los resultados de las funciones de reduce de nuevo a la función reduce, MapReduce puede dividir el análisis de conjuntos de datos enormes en tareas menores y paralelas, que se pueden completar mucho más
rápido.
Cuando utilice la función de reducción incorporada, si la entrada no es válida se devuelve el error builtin_reduce_error. Encontrará información más detallada sobre el error en el campo reason. Los datos originales
que han causado el error se devuelven en el campo caused_by.
Consulte un ejemplo de respuesta:
{
"rows": [
{
"key": null,
"value": {
"error": "builtin_reduce_error",
"reason": "The _sum function requires that map values be numbers, arrays of numbers, or objects. Objects can't be mixed with other data structures. Objects can be arbitrarily nested, if the values for all fields are themselves numbers, arrays of numbers, or objects.",
"caused_by": [
{
"a": 1
},
{
"a": 2
},
{
"a": 3
},
{
"a": 4
}
]
}
}
]
}
Restricciones de la correlación y de la función de reducción
Aquí se describen las restricciones de la correlación y de la función de reducción.
Transparencia referencial
La función de correlación (map) debe ser referencialmente transparente. La transparencia referencial significa que una expresión se puede sustituir por el mismo valor sin cambiar el resultado, en este caso un documento y un par de key-value.
Debido a la transparencia referencial, las vistas de IBM Cloudant se pueden actualizar de forma incremental y volver a indexar solo la parte diferencial (delta) desde la última actualización.
Propiedades conmutativas y asociativas
Además de la transparencia referencial, la función reduce también debe tener propiedades acumulativas y asociativas para la entrada. Estas propiedades hacen posible que la función MapReduce reduzca su propia salida y genere la misma respuesta, por ejemplo:
f(Key, Values) == f(Key, [ f(Key, Values) ] )
Como resultado, IBM Cloudant puede almacenar resultados intermedios en los nodos internos de los índices B-tree. Estas restricciones también permiten que los índices se propaguen entre máquinas y se reduzcan en el momento de la consulta.
Particionamiento de documentos
Debido a la fragmentación, IBM Cloudant no puede garantizar que la salida de dos funciones map específicas pase a la misma instancia de una llamada reduce. No debe confiar en ninguna ordenación. La función de reducción que utilice debe tener
en cuenta todos los valores que se le pasan y devolver la respuesta correcta independientemente del orden. También se garantiza que IBM Cloudant llame a su función de reducción con rereduce=true en el momento de la consulta,
incluso si no tenía que hacerlo cuando construyó el índice. Es esencial que sus funciones funcionen correctamente en ese caso (rereduce=true significa que el parámetro de claves es null y la matriz de valores se
llena con resultados de llamadas de función de reducción anteriores).
Tamaño del valor reducido
IBM Cloudant calcula los índices de vista y los valores de reducción correspondientes y luego almacena en memoria caché estos valores dentro de cada uno de los punteros del nodo B-tree. Ahora, IBM Cloudant puede reutilizar valores reducidos cuando actualiza el B-tree. Debe prestar atención a la cantidad de datos que se devuelven de las funciones reduce.
Es mejor que el tamaño del conjunto de datos devuelto sea pequeño y no crezca más rápido que log(num_rows_processed). Si omite esta restricción, IBM Cloudant no genera automáticamente un error, pero el rendimiento de B-tree se
degrada drásticamente. Si su vista funciona correctamente con pequeños conjuntos de datos pero deja de funcionar cuando se añaden más datos, es posible que su vista infrinja la restricción de la característica de tasa de crecimiento.
Entorno de ejecución
Las funciones de indexación funcionan en un entorno con restricciones de memoria donde el documento forma parte de la memoria utilizada en el entorno. La pila y el documento de su código deben caber dentro de la memoria. Limitamos los documentos a un tamaño máximo de 64 MB.
No hay reductores de JavaScript cuando options.partitioned es true
Los documentos de diseño con options.partitioned establecido en true no pueden contener funciones de reducción de JavaScript, sino solo reductores Erlang incorporados, como por ejemplo _stats.
Almacenamiento de la definición de vista
Cada vista es una función JavaScript. Las vistas se almacenan en documentos de diseño. Por lo tanto, para almacenar una vista, IBM Cloudant simplemente almacena la definición de función dentro de un documento de diseño. Un documento de diseño se puede crear o actualizar como cualquier otro documento.
Para guardar la definición de una vista,
PUT el contenido de la definición de la vista en un documento _design.
En el ejemplo siguiente, la vista de getVerifiedEmails se define como una función de correlación y está disponible en el campo views del documento de diseño.
Utilice el método PUT para añadir una vista a un documento de diseño:
PUT $SERVICE_URL/$DATABASE/_design/$DDOC HTTP/1.1
Content-Type: application/json
El siguiente ejemplo añade una nueva getVerifiedEmails función llamada vista al allusers documento de diseño con definición de vista:
{
"views": {
"getVerifiedEmails": {
"map": "function(user) { if(user.email_verified === true){ emit(doc.email, {name: user.name, email_verified: user.email_verified, joined: user.joined}) }} "
}
}
}
Consulte los ejemplos de solicitud:
curl -X PUT "$SERVICE_URL/users/_design/allusers" --data '{
"views": {
"getVerifiedEmails": {
"map": "function(user) { if(user.email_verified === true){ emit(doc.email, {name: user.name, email_verified: user.email_verified, joined: user.joined}) }}"
}
}
}'
import com.ibm.cloud.cloudant.v1.Cloudant;
import com.ibm.cloud.cloudant.v1.model.DesignDocument;
import com.ibm.cloud.cloudant.v1.model.DesignDocumentViewsMapReduce;
import com.ibm.cloud.cloudant.v1.model.DocumentResult;
import com.ibm.cloud.cloudant.v1.model.PutDesignDocumentOptions;
import java.util.Collections;
Cloudant service = Cloudant.newInstance();
DesignDocumentViewsMapReduce emailViewMapReduce =
new DesignDocumentViewsMapReduce.Builder()
.map("function(user) { if(user.email_verified === true){ emit(doc.email,{name: user.name, email_verified: user.email_verified, joined: user.joined}) }")
.build();
DesignDocument designDocument = new DesignDocument();
designDocument.setViews(
Collections.singletonMap("getVerifiedEmails", emailViewMapReduce));
PutDesignDocumentOptions designDocumentOptions =
new PutDesignDocumentOptions.Builder()
.db("users")
.designDocument(designDocument)
.ddoc("allusers")
.build();
DocumentResult response =
service.putDesignDocument(designDocumentOptions).execute()
.getResult();
System.out.println(response);
import { CloudantV1 } from '@ibm-cloud/cloudant';
const service = CloudantV1.newInstance({});
const emailViewMapReduce: CloudantV1.DesignDocumentViewsMapReduce = {
map: 'function(user) { if(user.email_verified === true){ emit(doc.email, {name: user.name, email_verified: user.email_verified, joined: user.joined}) }}'
}
const designDocument: CloudantV1.DesignDocument = {
views: {'getVerifiedEmails': emailViewMapReduce}
}
service.putDesignDocument({
db: 'users',
designDocument: designDocument,
ddoc: 'allusers'
}).then(response => {
console.log(response.result);
});
from ibmcloudant.cloudant_v1 import CloudantV1
service = CloudantV1.new_instance()
email_view_map_reduce = DesignDocumentViewsMapReduce(
map='function(user) { if(user.email_verified === true){ emit(doc.email, {name: user.name, email_verified: user.email_verified, joined: user.joined}) }}'
)
design_document = DesignDocument(
views={'getVerifiedEmails': email_view_map_reduce}
)
response = service.put_design_document(
db='users',
design_document=design_document,
ddoc='allusers'
).get_result()
print(response)
emailViewMapReduce, err := service.NewDesignDocumentViewsMapReduce(
"function(user) { if(user.email_verified === true){ emit(doc.email, {name: user.name, email_verified: user.email_verified, joined: user.joined}) }}",
)
if err != nil {
panic(err)
}
designDocument := &cloudantv1.DesignDocument{
Views: map[string]cloudantv1.DesignDocumentViewsMapReduce{
"getVerifiedEmails": *emailViewMapReduce,
},
}
putDesignDocumentOptions := service.NewPutDesignDocumentOptions(
"users",
"allusers",
designDocument,
)
documentResult, _, err := service.PutDesignDocument(putDesignDocumentOptions)
if err != nil {
panic(err)
}
b, _ := json.MarshalIndent(documentResult, "", " ")
fmt.Println(string(b))
El ejemplo Go anterior requiere el siguiente bloque de importación:
import (
"encoding/json"
"fmt"
"github.com/IBM/cloudant-go-sdk/cloudantv1"
)
Todos los ejemplos de Go requieren que se inicialice el objeto service. Para obtener más información, consulte los ejemplos de la Sección de autenticación de la documentación de la API.