martes, 1 de abril de 2014

Búsquedas en Elasticsearch

En este post voy a hacer una recopilación de algunas querys más o menos complejas sobre un índice de Elasticsearch.
En primer lugar, el mapping usado (ficticio) será el siguiente, con un tipo película donde tenemos varios campos de distintos tipos: cadenas de caracteres, números, un array de enteros y otro de objetos. La generación del mapping, modificada, se realizó a partir del índice de un modelo en Rails, como explico en el post sobre integrar Elasticsearch en Ruby.

{
  "pelicula":{
    "index_analyzer":"default_index",
    "dynamic_templates":[
      {
        "string_template":{
          "mapping":{
            "type":"multi_field",
            "fields":{
              "analyzed":{
                "index":"analyzed",
                "type":"string"
              },
              "{name}":{
                "index":"not_analyzed",
                "type":"string"
              }
            }
          },
          "match":"*",
          "match_mapping_type":"string"
        }
      }
    ],
    "properties":{
      "presupuesto":{
        "type":"float"
      },
      "imdb":{
        "type":"string",
        "fields":{
          "imdb_sort":{
            "type":"string",
            "index":"not_analyzed"
          }
        }
      },
      "categoria":{
        "type":"string",
        "analyzer":"keyword"
      },
      "duracion":{
        "type":"long"
      },
      "bn":{
        "type":"boolean"
      },
      "actores":{
        "type":"long",
        "index_name":"actor"
      },
      "titulo":{
        "type":"string",
        "fields":{
          "titulo_sort":{
            "type":"string",
            "index":"not_analyzed"
          }
        }
      },
      "premios":{
        "type":"nested",
        "properties":{
          "fecha":{
            "type":"date",
            "format":"dateOptionalTime"
          },
          "actor":{
            "type":"long"
          },
          "nombre":{
            "type":"string",
            "analyzer":"keyword"
          }
        }
      }
    }
  }
}

Un par de comentarios sobre el mapping.
En los campos tipo String sobre los que vamos a tener que realizar operaciones tanto de filtrado como de ordenación, tendremos que convertir el campo en un multifield, de modo que se duplique. Así, la ordenación se realizará sobre el campo not analyzed, y el filtrado sobre el analyzed.
También otra característica de los campos String es que elasticsearch realizará un análisis stemming dependiendo del idioma. En algunos campos querremos evitarlo, como en identificadores tipo cadena. Para ello usaremos el analyzer tipo keyword.

lunes, 31 de marzo de 2014

Comunicación Rails - Node JS con Sidekiq

En Rails, para ejecutar tareas en segundo plano, disponemos de varias gemas. Las más usadas son Resque y Sidekiq. Ambas son bastante similares, incluso he realizado pruebas donde encolaba trabajos usando Resque y los ejecutaba mediante Sidekiq, y no tenía ningún problema. La mayor diferencia es la concurrencia. Mientras que Resque levanta un proceso,
Sidekiq puede ejecutar hasta 50 hilos distintos.

Llevando este concepto a una aplicación sobre Node JS, he hecho prebas para comprobar qué difícil sería enviar trabajos desde esta aplicación web a un backend Rails. Node necesitaría conectarse a Redis e instanciar un cliente que encolara los trabajos. Para ambas cosas hay librerías disponibles.

viernes, 21 de marzo de 2014

AngularJS, ui-autocomplete con Node JS

En este post mostraré el uso de la directiva ui-autocomplete con AngularJS, obteniendo los datos de modo remoto contra Node js. En el ejemplo de la documentación de esta directiva, vemos que con dats estáticos es bastante sencillo. En mi caso quería realizar el filtrado directamente en Node, ya que es más eficiente en el caso de que tengamos una gran cantidad de registros.

Mostraré primero la parte relevante de Node js y luego la de AngularJS:

Node js

Por un lado tendremos el modelo, usando mongoose para el mapeo con MongoDB. Nada del otro mundo.

En el controlador definiremos una acción, que será el servicio REST encargado de buscar los datos que concuerden con el filtro y devolverlos en formato JSON.
exports.txt_search = function (req, res, next) {
  var util = require('util');

  var searchTerm = req.query.term;
  Objeto.find({name: new RegExp('^' + searchTerm, "i")}, function (err, list_objs) {
    if (list_objs && list_objs.length) {
      res.send(list_objs);
    } else {
      res.send([]);
    }
  });

};

Definimos la ruta necesaria para que las llamadas ejecuten esta función:
app.get('/api/objects', league.txt_search);




jueves, 20 de marzo de 2014

#canonAEDE

DECLARACIÓN CONJUNTA DE LA RED Y LOS AUTORES CULTURALES SOBRE EL PROYECTO DE REFORMA DE LA LEY DE PROPIEDAD INTELECTUAL


El pasado 14 de febrero de 2014 el Consejo de Ministros aprobó el proyecto de reforma de la Ley de Propiedad Intelectual (texto publicado en el B.O.C.G. el 21 de febrero).

Este proyecto de Ley, arcaico en su concepción, recorta numerosos derechos en España, afecta muy negativamente a amplios sectores de la sociedad, pone en peligro la cultura libre y cuestiona el funcionamiento de internet, limitando la cita y el enlace a una actividad meramente mercantil.

MEAN Stack (MongoDB, Express, AngularJS, Node) y Yeoman

Hace un tiempo escribí un post sobre la integración de AngularJS en Rails. Una manera sencilla de aprovechar una aplicación para meter un Framework MVC JavaScript. Aún que la integración fue más o menos sencilla, le veo algunos problemas debido a la naturaleza de Rails.

Rails pierde su función original de framework MVC, ya que se limita a servir datos en formato JSON y del resto se debe encargar JS. Además de esto, está orientado a servir distintas páginas, una por cada recurso y action. Esto choca con la idea de AngularJS de poder realizar aplicaciones en una sóla página, modificando sólo el contenido necesario.
Para solucionar esto, es necesario modificar el backend, que es el que se encargará de la gestión de los datos y servirlos en formato JSON. Dentro de las distintas opciones, actualmente la tendencia es el MEAN stack (MongoDB, Express, AngularJS, Node)



martes, 18 de marzo de 2014

GIT: workflow, merge/rebase de ramas remotas.

Hay una gran variedad de workflows distintos para el trabajo con GIT. Dependiendo del tipo de equipo conviene adaptarse a uno u a otro. El más usado posiblemente sea git-flow, donde tenemos una rama master donde se integran los cambios, para pasar una vez validados a la rama stable.

La bonita utopía 

En este workflow, cada desarrollador tiene su copia local de master, desde donde creará ramas locales para implementar las funcionalidades del proyecto

git checkout -b mitarea

Cada vez que finalice la funcionalidad se integrará con la rama master y los cambios que haya podido sufrir durante el desarrollo. Lo ideal sería algo así:
git checkout master
git pull origin master
git checkout mitarea
git rebase master
git rebase master -i
git checkout master
git merge mitarea
git push origin master

Con esto nos aseguramos de que nuestro master este actualizado; hacemos rebase contra nuestra rama local, de modo que añadiremos los commit que hemos realizado. Luego haremos el rebase interactivo (opcional) para que todos nuestros commit se integren en uno, y la rama estará lista para que sea subida a master.

jueves, 6 de marzo de 2014

Despliegue de aplicaciones Rails con Capistrano v3

Como decía en el anterior post sobre la configuración de una aplicación rails con Nginx y Unicorn, ahora comentaré cómo he realizado el despliegue usando Capistrano 3. Realmente es una herramiente muy sencilla, que permite incluir muchas opciones de configuración, aunque lo básico ya viene prácticamente hecho de serie.

Para empezar, incluimos en el Gemfile las gemas que vamos a usar:


# Deploy with Capistrano
gem 'capistrano'
gem 'capistrano-rails'
gem 'capistrano-rvm'
# integrate bundler with capistrano
gem 'capistrano-bundler'

Ejecutamos bundle install y una vez que hemos instalado las gemas, creamos la estructura de ficheros que necesita Capistrano. Para ello simplemente habrá que ejecutar: cap install.
A partir de aquí, simplemente tendremos que configurar los ficheros generados de acuerdo a las necesidades de nuestro servidor.