Couchbase FTS es nuestro nuevo motor de Índice y Consulta de Texto Completo. Ya lo presentamos el año pasado, le invito a leer esta entrada y el documentación de referencia para comprender mejor lo que puede hacer por usted.
Si todavía estás aquí, o quizás ya has vuelto, aquí tienes las novedades de FTS en esta versión para desarrolladores de Couchbase.
Mapa de tipos
En el pasado sólo había una forma de declarar un mapeo de tipos y era diciéndole a FTS qué campo (por defecto el campo "tipo") quería utilizar para distinguir los tipos de documentos. Aunque utilizar un campo común como selector de tipo para todos sus documentos es útil y una práctica habitual, no es la única. Por eso hemos añadido otra forma de distinguir tipos entre documentos.
- DOC ID hasta el separador: El identificador de tipo es el prefijo de la clave del documento, hasta el carácter dado, pero sin incluirlo.
- DOC ID con regex: Para usuarios avanzados, puede especificar una expresión regular que coincida con el identificador de tipo.
¿Cómo se traduce esto en nuestra muestra de viaje? Todos los documentos clave siguen el mismo patrón. He aquí algunos ejemplos:
airline_10, airline_10748, hotel_6445, hotel_9905, landmark_10019, landmark_9838, route_10009, route_14273, route_9807
Como puedes ver todos empiezan con un tipo, luego un guión bajo, luego un número. Si usamos el guión bajo como separador, todos empiezan con su tipo como String, que el guión bajo y el número. Así que podemos utilizar la opción DOC ID hasta el separador poniendo la opción a '_'. Esto equivaldrá a decir que el campo que contiene el tipo del documento es 'type'. Que es exactamente lo que solemos hacer.
Ahora podemos identificar otro patrón aquí. Todos los identificadores DOC empiezan por minúsculas hasta el guión bajo. Su longitud oscila entre 5 y 8 caracteres. Después tenemos números. Podemos traducir esta observación en la siguiente expresión regular: ^[a-z]{5,8}
Esta expresión coincidirá con el principio de la cadena(gracias a ^) todos los caracteres entre 'a' y 'z'(gracias a [a-z]) con una longitud que va de 5 a 8(gracias a {5,8}).
Por lo tanto, puede utilizar la opción DOC ID with regex configurando la opción como ^[a-z]{5,8}. Las remezclas son a veces complicadas, pero le permitirán realizar filtrados más avanzados.
Ordenar
Otra de las novedades de esta versión es la ordenación. Y vas a decir que ordenar ya estaba disponible en la anterior. Y tendrías razón. Cada documento que coincide con la búsqueda tiene una puntuación de relevancia y los resultados siempre se ordenan por puntuación descendente. Sin embargo, ahora puede especificar su propio orden de clasificación. Hemos añadido un campo de ordenación para la consulta FTS que funciona de la siguiente manera:
"sort" : [ "country", "state", "city", "-score" ]
Aquí los resultados se ordenarán primero por país, luego por estado y ciudad si el país, el estado y la ciudad son similares. Luego, si todos son iguales, se ordenan por puntuación de forma descendente. Anteponga el carácter '-' a cualquier campo de ordenación para que la ordenación sea descendente. También debe asegurarse de que todos los campos de la matriz de ordenación se almacenan en el índice. Así es como se ve en una consulta FTS completa:
{ "explain": false, "fields": [ "title" ], "highlight": {}, "sort": ["country", "state", "city", "-score", "-_id"], "query":{ "consulta": "hermosa piscina" } }
Si está utilizando Java, digamos que el archivo travel-sample app por ejemplo, es fácil añadir un Sort personalizado. Simplemente abra el servicio Hotel y vaya al método findHotels. Debería verse así:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
ConjunctionQuery fts = SearchQuery.conjuncts(SearchQuery.term("hotel").field("type")); if (location != null && !location.isEmpty() && !"*".equals(location)) { fts.and(SearchQuery.disjuncts( SearchQuery.matchPhrase(location).field("country"), SearchQuery.matchPhrase(location).field("city"), SearchQuery.matchPhrase(location).field("state"), SearchQuery.matchPhrase(location).field("address") )); } if (description != null && !description.isEmpty() && !"*".equals(description)) { fts.and( SearchQuery.disjuncts( SearchQuery.matchPhrase(description).field("description"), SearchQuery.matchPhrase(description).field("name") )); } SearchQuery query = new SearchQuery("hotels", fts) .limit(100); logQuery(query.export().toString()); SearchQueryResult result = bucket.query(query); |
La consulta a ejecutar es básicamente esta línea de código: SearchQuery query = new SearchQuery("hoteles", fts).limit(100);
Y todo lo que tienes que hacer es añadir una llamada al método de ordenación: SearchQuery query = new SearchQuery("hoteles", fts).limit(100).sort("país", "estado", "ciudad", "-puntuación")
También hay disponibles opciones más avanzadas.
Backend
Algo que ha cambiado pero que no será visible para el usuario final es que hemos cambiado el backend de los índices FTS. Pasamos de usar ForestDB a usar Musgo. moss es una librería de almacenamiento de claves-valores simple, rápida, ordenada y persistente para golang. sus siglas significan "segmentos ordenados orientados a memoria". Aquí está la lista de características tomadas del README:
- API de recopilación de valores clave ordenados
- 100% ir a la aplicación
- iteradores de rango de teclas
- las instantáneas permiten lecturas aisladas
- mutaciones atómicas a través de una API por lotes
- las operaciones de fusión permiten optimizar la lectura, el cálculo y la escritura en los casos de uso con mucha escritura (por ejemplo, la actualización de contadores)
- los lectores y escritores concurrentes no se bloquean mutuamente
- opcionales, API avanzadas para evitar la copia de memoria adicional
- implementación opcional de almacenamiento de nivel inferior, denominada "mossStore", que utiliza un diseño de sólo anexión para las escrituras y mmap() para las lecturas, con una política de compactación configurable; véase: OpenStoreCollection()
- mossStore permite navegar hacia atrás a través de puntos de confirmación anteriores en modo de sólo lectura, y permite revertir a puntos de confirmación anteriores.
- ganchos de persistencia opcionales para permitir el almacenamiento en caché con escritura posterior a una implementación de almacenamiento de nivel inferior que los usuarios avanzados puedan desear proporcionar (por ejemplo, puede conectar moss a leveldb, sqlite, etc.)
- las retrollamadas de eventos permiten supervisar las tareas asíncronas
- pruebas unitarias
- pruebas fuzz mediante go-fuzz y smat (github.com/mschoch/smat); véase LÉAME-smat.md
No voy a entrar en detalles ya que esto es bastante bajo nivel. Sin embargo, nos gustaría saber si buscas más información sobre arquitectura de bajo nivel como esta. ¿Te gustaría ver una presentación más detallada de moss o de cualquier otro componente de Couchbase Server? Si es así, por favor háznoslo saber en twitter o en los comentarios de abajo.