Sonic es un backend de búsqueda escrito en Rust que consume unas decenas de MB de RAM. A diferencia de Elasticsearch o Solr, no guarda los documentos: solo mantiene un índice invertido que asocia palabras con identificadores de objetos. Tu aplicación le pregunta por unos términos, Sonic devuelve los IDs que coinciden y tú recuperas los datos completos de tu base de datos. En este tutorial instalarás Sonic en Ubuntu 24.04 como servicio systemd, indexarás y buscarás textos con su protocolo Sonic Channel y lo integrarás en un script de Python.

Requisitos previos

Para seguir esta guía necesitas:

  • Un servidor con Ubuntu 24.04 LTS de 64 bits (x86_64), por ejemplo un VPS de CubePath.
  • Un usuario no root con privilegios sudo.
  • 512 MB de RAM libres son suficientes para empezar.
  • nc (netcat), que viene instalado por defecto en Ubuntu 24.04.

Sonic escuchará solo en 127.0.0.1:1491, por lo que no hace falta abrir ningún puerto en el cortafuegos.

Cómo organiza Sonic los datos

Antes de indexar conviene entender su jerarquía de tres niveles:

NivelQué representaEjemplo
Colección (collection)El tipo de contenido que buscasproductos, articulos
BucketUna partición dentro de la colección, por ejemplo por cliente. Si no necesitas particionar, usa un nombre fijodefault, cliente-42
Objeto (object)El identificador del registro en tu base de datosprod-001

Sonic se usa a través de tres modos de conexión: ingest para escribir en el índice, search para consultar y control para tareas de administración.

Paso 1: Descargar el binario de Sonic

El proyecto publica binarios para Linux en GitHub. Descarga la última versión (1.10.0 al escribir esta guía; consulta la página de versiones por si hay una más reciente):

SONIC_VERSION=1.10.0
cd /tmp
wget "https://github.com/valeriansaliou/sonic/releases/download/v${SONIC_VERSION}/v${SONIC_VERSION}-x86_64-gnu.tar.gz"
tar xzf "v${SONIC_VERSION}-x86_64-gnu.tar.gz"

El archivo contiene el binario y un archivo de configuración de ejemplo:

ls sonic/
config.cfg  sonic

Instala el binario en /usr/local/bin:

sudo install -m 0755 sonic/sonic /usr/local/bin/sonic

Paso 2: Crear el usuario y los directorios

Sonic no necesita privilegios, así que lo ejecutarás con un usuario de sistema propio que solo puede escribir en su directorio de datos:

sudo useradd --system --no-create-home --shell /usr/sbin/nologin sonic
sudo install -d -o sonic -g sonic -m 0750 /var/lib/sonic
sudo install -d -m 0755 /etc/sonic

Parte del archivo de configuración oficial que venía en el paquete:

sudo install -o root -g sonic -m 0640 sonic/config.cfg /etc/sonic/config.cfg

Paso 3: Configurar Sonic

Genera una contraseña aleatoria para el canal. Cualquier cliente la necesitará para conectarse:

openssl rand -hex 24

Copia el valor y abre el archivo de configuración:

sudo nano /etc/sonic/config.cfg

Modifica solo las siguientes claves y deja el resto con sus valores por defecto. Sustituye your_sonic_password por la contraseña que acabas de generar:

[server]
log_level = "info"

[channel]
inet = "127.0.0.1:1491"
tcp_timeout = 300
auth_password = "your_sonic_password"

Más abajo, en las secciones [store.kv] y [store.fst], cambia las rutas relativas por rutas absolutas dentro de /var/lib/sonic:

[store.kv]
path = "/var/lib/sonic/store/kv/"
[store.fst]
path = "/var/lib/sonic/store/fst/"

El almacén kv guarda el índice invertido (en RocksDB) y el fst guarda los grafos de palabras que se usan para el autocompletado. El valor graph.consolidate_after = 180 de la sección [store.fst] indica cada cuántos segundos se incorporan las palabras nuevas al grafo de sugerencias.

Paso 4: Crear el servicio systemd

Crea la unidad del servicio:

sudo nano /etc/systemd/system/sonic.service

Añade este contenido:

[Unit]
Description=Sonic search backend
After=network.target

[Service]
Type=simple
User=sonic
Group=sonic
ExecStart=/usr/local/bin/sonic -c /etc/sonic/config.cfg
Restart=on-failure
RestartSec=5
LimitNOFILE=65536
NoNewPrivileges=true
ProtectSystem=strict
ReadWritePaths=/var/lib/sonic
ProtectHome=true
PrivateTmp=true

[Install]
WantedBy=multi-user.target

ProtectSystem=strict deja todo el sistema de archivos en solo lectura para el proceso excepto /var/lib/sonic. Recarga systemd e inicia el servicio:

sudo systemctl daemon-reload
sudo systemctl enable --now sonic

Comprueba que está activo y escuchando:

sudo systemctl status sonic
sudo ss -tlnp | grep 1491
LISTEN 0      1024       127.0.0.1:1491       0.0.0.0:*    users:(("sonic",pid=4121,fd=12))

Paso 5: Indexar textos con el modo ingest

Sonic Channel es un protocolo de texto sobre TCP, parecido al de Redis, así que puedes probarlo con nc. Conéctate:

nc 127.0.0.1 1491
CONNECTED <sonic-server v1.10.0>

A partir de aquí escribes comandos y Sonic responde línea a línea. Entra en modo ingest con tu contraseña:

START ingest your_sonic_password
STARTED ingest protocol(1) buffer(20000)

Indexa tres productos con PUSH <colección> <bucket> <objeto> "<texto>". El texto va siempre entre comillas. LANG(spa) indica que el texto está en español (código ISO 639-3) para que Sonic elimine las palabras vacías correctas; si lo omites, intenta detectar el idioma por sí mismo:

PUSH productos default prod-001 "Camiseta básica de algodón en varios colores" LANG(spa)
PUSH productos default prod-002 "Zapatillas de running ligeras con amortiguación" LANG(spa)
PUSH productos default prod-003 "Zapatillas de montaña para senderismo" LANG(spa)

Cada PUSH correcto responde OK. Comprueba cuántos objetos hay en el bucket con COUNTB y sal:

COUNTB productos default
QUIT
RESULT 3
ENDED quit

Sonic no tiene un comando para actualizar un objeto. Si el texto de un producto cambia, bórralo con FLUSHO productos default prod-001 y vuelve a indexarlo con PUSH. Para vaciar un bucket entero existe FLUSHB y para una colección completa, FLUSHC.

Abre una nueva conexión y entra en modo search:

nc 127.0.0.1 1491
START search your_sonic_password
QUERY productos default "zapatillas" LIMIT(10)

Las consultas son asíncronas: Sonic responde primero con PENDING y un marcador, y después envía el resultado con el mismo marcador:

STARTED search protocol(1) buffer(20000)
PENDING Bt2m2gYa
EVENT QUERY Bt2m2gYa prod-003 prod-002

El resultado son los identificadores de los objetos, no los textos. SUGGEST completa una palabra a partir de su comienzo, que es lo que necesitas para un buscador con sugerencias mientras el usuario escribe:

SUGGEST productos default "zapa"
QUIT
PENDING z98uDE0f
EVENT SUGGEST z98uDE0f zapatillas
ENDED quit

Paso 7: Integrar Sonic en una aplicación Python

En una aplicación real no usarás nc, sino una librería cliente. Crea un entorno virtual para no mezclar paquetes con los del sistema:

sudo apt install python3-venv
python3 -m venv ~/sonic-demo
~/sonic-demo/bin/pip install sonic-client

Crea el script de ejemplo:

nano ~/sonic-demo/demo.py

El script indexa unos productos (en tu aplicación vendrían de la base de datos) y después busca y pide sugerencias. Guarda la contraseña en una variable de entorno en lugar de escribirla en el código:

import os

from sonic import IngestClient, SearchClient

HOST, PORT = "127.0.0.1", 1491
PASSWORD = os.environ["SONIC_PASSWORD"]

productos = {
    "prod-004": "Pantalón vaquero slim de corte moderno",
    "prod-005": "Chaqueta impermeable para montaña",
}

with IngestClient(HOST, PORT, PASSWORD) as ingest:
    for object_id, texto in productos.items():
        ingest.push("productos", "default", object_id, texto, lang="spa")

with SearchClient(HOST, PORT, PASSWORD) as search:
    ids = search.query("productos", "default", "montaña", limit=10)
    print("IDs encontrados:", ids)
    print("Sugerencias:", search.suggest("productos", "default", "zapa", limit=5))

Ejecútalo pasando la contraseña como variable de entorno:

SONIC_PASSWORD='your_sonic_password' ~/sonic-demo/bin/python ~/sonic-demo/demo.py
IDs encontrados: ['prod-005', 'prod-003']
Sugerencias: ['zapatillas']

Con esos IDs tu aplicación lanza una consulta del tipo SELECT ... WHERE id IN (...) contra su base de datos y muestra los resultados. Cuando un registro cambie o se borre en la base de datos, repite el FLUSHO y el PUSH correspondientes para que el índice siga sincronizado.

Solución de problemas

El servicio no arranca. Revisa el log del servicio:

sudo journalctl -u sonic -n 50 --no-pager

Un error de permisos sobre /var/lib/sonic suele indicar que el directorio no pertenece al usuario sonic; corrígelo con sudo chown -R sonic:sonic /var/lib/sonic. Un error de sintaxis apunta a una comilla o sección mal escrita en /etc/sonic/config.cfg.

ENDED authentication_failed al hacer START. La contraseña no coincide con auth_password. Recuerda reiniciar el servicio (sudo systemctl restart sonic) después de cambiar la configuración.

ERR invalid_format al indexar. El texto de PUSH debe ir entre comillas dobles y las comillas internas deben escaparse como \".

Una búsqueda no encuentra una palabra que sí está indexada. Sonic descarta las palabras vacías del idioma detectado. Si indexas textos cortos sin LANG(...), la detección puede fallar; indica el idioma de forma explícita tanto al indexar como al consultar.

Conclusión

Tienes Sonic funcionando como servicio en Ubuntu 24.04, con su índice en /var/lib/sonic, y sabes indexar, buscar y obtener sugerencias tanto con el protocolo Sonic Channel como desde Python. Como siguientes pasos, puedes programar una reindexación completa periódica desde tu base de datos para corregir desajustes, usar el comando TRIGGER backup del modo control para hacer copias del índice, o probar otras librerías cliente como sonic-channel para Node.js.