A partir de la versión 2.0, el servidor Couchbase ofrece una potente forma de crear índices para documentos JSON a través del concepto de vistas.
Mediante las vistas, es posible definir índices primarios, índices compuestos y agregaciones que permitan:
. consultar documentos en función de distintas propiedades JSON
. crear estadísticas y agregados
Las vistas generan índices materializados, por lo que proporcionan una forma rápida y eficaz de ejecutar consultas predefinidas.
Este blog proporciona un ejemplo sencillo de cómo se puede crear una vista utilizando map and reduce para indexar un atributo de documento JSON pero también para determinar la clasificación del documento en función de ese atributo.
El uso de map and reduce es una forma muy rápida y eficiente de determinar la clasificación y puede escalar a millones de usuarios y proporcionar una búsqueda de clasificación muy rápida. Gracias Aaron ¡por enseñarme esto!
Puede utilizarse, por ejemplo, para clasificar a los usuarios en función de su puntuación o experiencia.
Este blog ilustra ese concepto para un documento de usuario con 2 atributos: nombre y experiencia, indexa este documento en función de la experiencia y permite determinar la clasificación en función del atributo experiencia.
Primero escribiremos algo de código Java que permita conectar con el servidor Couchbase y crear documentos de usuario. El siguiente código Java es autónomo y creará los usuarios.
Aprovecha las bibliotecas de código Gson de Google para crear objetos JSON.
blog del paquete;
import com.couchbase.client.CouchbaseClient;
import com.couchbase.client.CouchbaseConnectionFactoryBuilder;
import com.google.gson.Gson;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.util.ArrayList;
clase UserDoc {
Nombre de cadena;
larga experiencia;
UserDoc(String nombre, long experiencia) {
this.name = nombre;
this.experience = experiencia;
}
}
/**
*
* @author alexis
*/
public class RankView {
private static CouchbaseClient client;
public static void main(String[] args) throws UnsupportedEncodingException, IOException {
ArrayList
// Añade uno o más nodos de tu cluster (intercambia la IP con la tuya)
nodes.add(URI.create("http://127.0.0.1:8091/pools"));
// Intentar conectar con el cliente
CouchbaseConnectionFactoryBuilder cfb = new CouchbaseConnectionFactoryBuilder();
cfb.setOpTimeout(10000);
cfb.setReadBufferSize(1024);
cfb.setShouldOptimize(true);
cfb.setTimeoutExceptionThreshold(100);
intentar {
client = new CouchbaseClient(cfb.buildCouchbaseConnection(nodes, "default", ""));
} catch (Exception e) {
System.err.println("Error al conectar con Couchbase: " + e.getMessage());
System.exit(1);
}
UserDoc usuario = null;
// Crea usuarios
for (int i = 0; i < 10; i++) {
user = new UserDoc("Usuario" + i, Math.round(Math.random()*1000));
Gson json = new Gson();
String jsonString = json.toJson(usuario);
client.set(user.name, 0, jsonString);
}
client.shutdown();
}
}
Después de ejecutar este programa (por favor, cambie la URL o el nombre del bucket según corresponda) ahora debería tener 10 usuarios en su bucket.
El siguiente paso es un documento de diseño de usuario con una vista de rango.
El primer paso es crear un Mapa simple para la vista Rango que emitirá el atributo experiencia:
function (doc, meta) {
si (doc.experiencia)
emit(doc.experiencia, null);
}
Al hacerlo, se creará un índice basado en el atributo de experiencia, pero no permitirá determinar la clasificación.
Aquí es donde encaja añadir un Reduce. Vamos a añadir simple incorporado _count reducir.
La vista completa debería tener este aspecto:
La función Reducir permite agregar el número de documentos de usuario con un valor de experiencia conocido (si doc.experiencia).
Al no especificar ningún parámetro de consulta, el resultado será 10, que es el número de documentos que hemos creado.
Para consultar la clasificación de un usuario concreto, lo primero que tenemos que hacer es consultar la clasificación de un usuario determinado (Usuario5 en este ejemplo):
// Buscar un usuario específico
String jsonString = (String) client.get("Usuario5");
user = json.fromJson(jsonString, UserDoc.class);
A partir de ahí, podemos crear una consulta que filtrará este recuento con una consulta de rango con un orden descendente que comenzará por el valor máximo para capturar todos los usuarios que tienen una mayor experienciala experiencia y terminar con el valor para el usuario:
Vista vista = client.getView("Usuario", "Rango");
Consulta consulta = nueva consulta();
query.setIncludeDocs(true).setLimit(10000);
query.setRangeStart(Long.toString(Long.MAX_VALUE));
query.setRangeEnd(Long.toString(user.experience));
query.setDescending(true);
query.setReduce(true);
Por lo tanto, la reducción mostrará el número de usuarios que tienen una experiencia superior a la de ese usuario. La clasificación es simplemente ese número + 1.
ViewResponse response = client.query(view, query);
Iterador
while (itr.hasNext()) {
ViewRow fila = itr.next();
System.out.println("Rango: " + Long.parseLong(row.getValue()) + 1 );
}
Esto mostrará el rango basado en la experiencia de ese usuario, por ejemplo:
Clasificación: 7
El código Java completo (de nuevo autocontenido) es:
blog del paquete;
import com.couchbase.client.CouchbaseClient;
import com.couchbase.client.CouchbaseConnectionFactoryBuilder;
import com.couchbase.client.protocol.views.Query;
import com.couchbase.client.protocol.views.View;
import com.couchbase.client.protocol.views.ViewResponse;
import com.couchbase.client.protocol.views.ViewRow;
import com.google.gson.Gson;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.util.ArrayList;
import java.util.Iterator;
clase UserDoc {
Nombre de cadena;
larga experiencia;
UserDoc(String nombre, long experiencia) {
this.name = nombre;
this.experience = experiencia;
}
}
/**
*
* @author alexis
*/
public class RankView {
private static CouchbaseClient client;
public static void main(String[] args) throws UnsupportedEncodingException, IOException {
ArrayList
// Añade uno o más nodos de tu cluster (intercambia la IP con la tuya)
nodes.add(URI.create("http://127.0.0.1:8091/pools"));
// Intentar conectar con el cliente
CouchbaseConnectionFactoryBuilder cfb = new CouchbaseConnectionFactoryBuilder();
cfb.setOpTimeout(10000);
cfb.setReadBufferSize(1024);
cfb.setShouldOptimize(true);
cfb.setTimeoutExceptionThreshold(100);
intentar {
client = new CouchbaseClient(cfb.buildCouchbaseConnection(nodes, "default", ""));
} catch (Exception e) {
System.err.println("Error al conectar con Couchbase: " + e.getMessage());
System.exit(1);
}
UserDoc usuario = null;
Gson json = null;
// Crea usuarios
for (int i = 0; i < 10; i++) {
user = new UserDoc("Usuario" + i, Math.round(Math.random() * 1000));
json = nuevo Gson();
String jsonString = json.toJson(usuario);
client.set(user.name, 0, jsonString);
}
// Buscar un usuario específico
String jsonString = (String) client.get("Usuario5");
user = json.fromJson(jsonString, UserDoc.class);
Vista vista = client.getView("Usuario", "Rango");
Consulta consulta = nueva consulta();
query.setIncludeDocs(true).setLimit(10000);
query.setRangeStart(Long.toString(Long.MAX_VALUE));
query.setRangeEnd(Long.toString(user.experience));
query.setDescending(true);
query.setReduce(true);
ViewResponse response = client.query(view, query);
Iterador
while (itr.hasNext()) {
ViewRow fila = itr.next();
System.out.println("Rango: " + Long.parseLong(row.getValue()) + 1 );
}
client.shutdown();
}
}
El uso de una vista de mapa y reducción para la clasificación permite buscar una clasificación de forma rápida y muy eficaz sin tener que realizar un procesamiento adicional en el lado del cliente.
Para saber más sobre vistas y consultas en Couchbase, lee: http://www.couchbase.com/docs/couchbase-devguide-2.1.0/indexing-querying-data.html
Para preguntas y comentarios: alexis@couchbase.com o @alexisroos en Twitter.
Me pregunto la sintaxis en la biblioteca C emparejado para \ 'setIncludeDocs\' en java..
Una visión general del almacenamiento de datos de juegos en couchbase: http://www.couchbase.com/work…
Si varias personas están en el mismo rango, por ejemplo, el rango 1, 2 y 3 tienen una puntuación de 100, entonces siempre devolverá su rango como el 3er. No estoy seguro de cómo solucionarlo.
Para devolver los jugadores con valores user.experience coincidentes como el rango más alto en lugar del más bajo, utilicé la solución de consultar sobre (user.experience+1), y luego añadir 1 al rango derivado. Parece que funciona.