SKOS Nuovo Soggettario, api e autocomplete

Come creare una api per un form con autocompletamento usando i termini del Nuovo Soggettario, con i Sorted Sets di Redis e Nginx+Lua.

ns skos

Il Nuovo Soggettario, disponibile in formato SKOS (CC BY), può essere facilmente usato per creare delle api da usare per servizi di normalizzazione, inserimento dati, catalogazione. E' un set di dati abbastanza piccolo, tale da non rendere necessario l'uso di strumenti sofisticati come SOLR o ElasticSearch.

Il tipo di dato Sorted Sets di Redis e il comando ZRANGEBYLEX sono una soluzione molto efficace e semplice per realizzare sistemi di autocompletamento.

creazione dell'indice

nuovosoggettario-skos-redis contiene uno script dimostrativo in python (moduli richiesti lxml e redis):

$ git clone https://github.com/atomotic/nuovosoggettario-skos-redis.git
$ cd nuovosoggettario-skos-redis
$ pip install -r requirements.txt

Download del soggettario:

$ mkdir xml
$ wget http://thes.bncf.firenze.sbn.it/dati/NS-SKOS.zip
$ unzip NS-SKOS.zip -d xml
$ rm NS-SKOS.zip

Indicizzazione (usate gnu parallel o xargs per caricarli in parallelo):

$ redis-server &
$ parallel -j 8 /usr/bin/env python index.py {} ::: xml/*.xml

Nell'esempio vengono indicizzate la prefLabel e tutte le altLabel (si lo so, index.py imbroglia parsando l'xml, ma il parsing rdf con rdflib è estremamente più lento).

Ricerca di esempio:

$ redis-cli --raw
127.0.0.1:6379> ZRANGEBYLEX autocomplete [archiv "[archiv\xff" LIMIT 0 5
archivi capitolari:{"label":"Archivi capitolari", "id":"http://purl.org/bncf/tid/17165"}
archivi comunali:{"label":"Archivi comunali", "id":"http://purl.org/bncf/tid/32025"}
archivi correnti:{"label":"Archivi correnti", "id":"http://purl.org/bncf/tid/52282"}
archivi di autorità di nomi e titoli:{"label":"Archivi di autorità di nomi e titoli",     "id":"http://purl.org/bncf/tid/2260"}
archivi di autorità:{"label":"Archivi di autorità", "id":"http://purl.org/bncf/tid/2261"}   

Memoria in uso:

$ redis-cli info | grep used_memory_human
used_memory_human:9.57M

api di ricerca

La api web può essere realizzata in qualsiasi linguaggio. Seguendo questo post Redis on steroids: Autocomplete using Redis, Nginx and Lua ho voluto provare con uno script Lua in Nginx.

Su Debian (testing, sid) basta installare nginx e nginx-extras, diversamente bisogna compilare a mano Openresty.

lua-resty-redis non è ancora aggiornato per usare il comando ZRANGEBYLEX, va aggiunto:

$ mkdir /srv/nginx-lua; cd /srv/nginx-lua
$ wget https://raw.githubusercontent.com/openresty/lua-resty-redis/master/lib/resty/redis.lua
$ sed -i 's/\"zscan\"/\"zscan\",\"zrangebylex\"/g' redis.lua

script di ricerca: /srv/nginx-lua/autocomplete.lua

local redis = require "redis"
local red = redis:new()
red:set_timeout(1000)
ngx.header.content_type = 'text/plain';
local ok, err = red:connect("127.0.0.1", 6379)
if not ok then
        ngx.status = ngx.HTTP_SERVICE_UNAVAILABLE
        ngx.say("Redis down")
        return
end
local q=ngx.req.get_uri_args().q
if not q then
        ngx.status = ngx.HTTP_BAD_REQUEST
        ngx.say("arguments missing")
        return
end
local res, err = red:zrangebylex("autocomplete", "["..q, "["..q.."\xff","LIMIT", "0", "100")

ngx.say("[")
table.foreach(res, function(k,v) ngx.say(string.match(v, "{.*}") .. "," ) end)
ngx.say("{\"label\":\"\", \"id\":\"\"}]")

configurazione del virtualhost in nginx, lo script è servito da /ns-bncf/autocomplete:

lua_package_path "/srv/nginx-lua/?.lua;;";

server {
    listen 80 default_server;
    root ....;
    index index.html index.htm;
    server_name ....;

    location / {
            try_files $uri $uri/ =404;
    }

    location = /ns-bncf/autocomplete {
            content_by_lua_file /srv/nginx-lua/autocomplete.lua;
    }
}

test dell'api, viene restituito un array di oggetti json:

$ curl http://atomotic.com/ns-bncf/autocomplete?q=archiv

a questo punto typeahead (o in alternativa jquery-autocomplete) possono essere usati per costruire una select con autocompletamento.

DEMO: http://atomotic.com/ns-bncf

Possibili utilizzi

  • un plugin per wordpress che usi i termini del soggettario come categorie
  • autocomplete di EPrints
  • un reconciliation service per OpenRefine
  • ....