Instalación y Configuración de Apache Solr

Apache Solr es una plataforma de búsqueda empresarial de código abierto, basada en Apache Lucene, que destaca por su escalabilidad, alta disponibilidad y la capacidad de indexar y buscar en millones de documentos con gran velocidad. Solr soporta búsqueda de texto completo, búsqueda facetada, geoespacial, sugerencias y clustering mediante SolrCloud, siendo una opción probada en entornos empresariales exigentes. Esta guía cubre la instalación en Linux, creación de cores y colecciones, diseño del schema y la configuración de SolrCloud.

Requisitos Previos

  • Ubuntu 20.04/22.04 o CentOS 8+/Rocky Linux 8+
  • Java 11 o Java 17
  • 4 GB de RAM mínimo (8 GB recomendado)
  • 20 GB de espacio en disco
  • Puerto 8983 disponible

Instalación de Apache Solr

# Instalar Java si no está disponible
sudo apt update && sudo apt install -y openjdk-17-jdk  # Ubuntu/Debian
sudo dnf install -y java-17-openjdk                     # CentOS/Rocky

java -version

# Descargar la versión estable más reciente de Solr
SOLR_VERSION=9.5.0
wget https://downloads.apache.org/solr/solr/${SOLR_VERSION}/solr-${SOLR_VERSION}.tgz -P /tmp

# Verificar la descarga con SHA512
wget https://downloads.apache.org/solr/solr/${SOLR_VERSION}/solr-${SOLR_VERSION}.tgz.sha512 -P /tmp
sha512sum -c /tmp/solr-${SOLR_VERSION}.tgz.sha512

# Extraer el instalador del paquete
tar xzf /tmp/solr-${SOLR_VERSION}.tgz solr-${SOLR_VERSION}/bin/install_solr_service.sh --strip-components=2 -C /tmp

# Instalar Solr como servicio (crea usuario solr, directorio /opt/solr y servicio systemd)
sudo bash /tmp/install_solr_service.sh /tmp/solr-${SOLR_VERSION}.tgz

# Verificar el estado del servicio
sudo systemctl status solr

# Acceder a la interfaz web de administración
# http://tu-ip:8983/solr

Instalación manual (sin script)

# Si prefieres instalación manual
sudo useradd -r -s /bin/false solr
sudo mkdir -p /opt/solr /var/solr

tar xzf /tmp/solr-${SOLR_VERSION}.tgz -C /opt/
sudo ln -s /opt/solr-${SOLR_VERSION} /opt/solr
sudo chown -R solr:solr /opt/solr /opt/solr-${SOLR_VERSION} /var/solr

# Configurar variables de entorno
sudo tee /etc/default/solr > /dev/null <<EOF
SOLR_HOME=/var/solr
SOLR_HEAP=2g
SOLR_PORT=8983
SOLR_HOST=0.0.0.0
JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64
EOF

Creación de Cores

En Solr, un core es una instancia de índice con su propio schema y configuración:

# Crear un core usando la API (modo standalone)
curl "http://localhost:8983/solr/admin/cores?action=CREATE&name=productos&configSet=_default"

# O usando el script de Solr
sudo -u solr /opt/solr/bin/solr create -c productos -n _default

# Listar cores existentes
curl "http://localhost:8983/solr/admin/cores?action=STATUS"

# Recargar un core después de cambios de configuración
curl "http://localhost:8983/solr/admin/cores?action=RELOAD&core=productos"

# Eliminar un core
curl "http://localhost:8983/solr/admin/cores?action=UNLOAD&core=productos&deleteIndex=true&deleteDataDir=true&deleteInstanceDir=true"

Diseño del Schema

Solr usa managed-schema (schema gestionado via API) o el archivo schema.xml:

# Añadir campos al schema via API (Schema API)

# Añadir un campo de texto
curl -X POST http://localhost:8983/solr/productos/schema \
  -H "Content-Type: application/json" \
  -d '{
    "add-field": {
      "name": "nombre",
      "type": "text_general",
      "stored": true,
      "indexed": true,
      "multiValued": false
    }
  }'

# Añadir múltiples campos en una sola petición
curl -X POST http://localhost:8983/solr/productos/schema \
  -H "Content-Type: application/json" \
  -d '{
    "add-field": [
      {"name": "descripcion", "type": "text_general", "stored": true, "indexed": true},
      {"name": "categoria",   "type": "string",       "stored": true, "indexed": true, "docValues": true},
      {"name": "marca",       "type": "string",       "stored": true, "indexed": true, "docValues": true},
      {"name": "precio",      "type": "pfloat",       "stored": true, "indexed": true, "docValues": true},
      {"name": "stock",       "type": "pint",         "stored": true, "indexed": true},
      {"name": "activo",      "type": "boolean",      "stored": true, "indexed": true},
      {"name": "fecha_alta",  "type": "pdate",        "stored": true, "indexed": true, "docValues": true},
      {"name": "etiquetas",   "type": "string",       "stored": true, "indexed": true, "multiValued": true, "docValues": true}
    ]
  }'

# Ver el schema completo
curl "http://localhost:8983/solr/productos/schema?wt=json" | python3 -m json.tool

Tipos de campo comunes en Solr

TipoUso
text_generalTexto con análisis estándar
text_esTexto con análisis en español (stemming, stopwords)
stringCadena exacta (para facetas y ordenación)
pint / pfloat / plongNúmeros enteros/decimales
pdateFechas
booleanVerdadero/falso
locationCoordenadas geoespaciales (latitud/longitud)

Indexación de Documentos

# Indexar documentos vía JSON
curl -X POST "http://localhost:8983/solr/productos/update?commit=true" \
  -H "Content-Type: application/json" \
  -d '[
    {
      "id": "prod-001",
      "nombre": "Camiseta básica algodón",
      "descripcion": "Camiseta unisex de algodón 100% disponible en varios colores",
      "categoria": "Ropa",
      "marca": "BasicWear",
      "precio": 19.99,
      "stock": 150,
      "activo": true,
      "fecha_alta": "2024-01-15T00:00:00Z",
      "etiquetas": ["ropa", "casual", "algodón"]
    },
    {
      "id": "prod-002",
      "nombre": "Zapatillas deportivas running",
      "descripcion": "Zapatillas ligeras para correr con amortiguación extra",
      "categoria": "Calzado",
      "marca": "SpeedRun",
      "precio": 89.99,
      "stock": 45,
      "activo": true,
      "fecha_alta": "2024-02-01T00:00:00Z",
      "etiquetas": ["deporte", "running", "calzado"]
    }
  ]'

# Actualización atómica de campos (sin reindexar el documento completo)
curl -X POST "http://localhost:8983/solr/productos/update?commit=true" \
  -H "Content-Type: application/json" \
  -d '[{"id": "prod-001", "precio": {"set": 17.99}, "stock": {"inc": 50}}]'

# Eliminar un documento por ID
curl -X POST "http://localhost:8983/solr/productos/update?commit=true" \
  -H "Content-Type: application/json" \
  -d '{"delete": {"id": "prod-001"}}'

# Eliminar con una consulta
curl -X POST "http://localhost:8983/solr/productos/update?commit=true" \
  -H "Content-Type: application/json" \
  -d '{"delete": {"query": "activo:false"}}'

# Commit manual (sin commit=true en la URL)
curl "http://localhost:8983/solr/productos/update?commit=true"

# Optimizar el índice (consolida segmentos, mejora rendimiento)
curl "http://localhost:8983/solr/productos/update?optimize=true"

Consultas y Búsqueda Facetada

# Búsqueda básica
curl "http://localhost:8983/solr/productos/select?q=zapatillas&wt=json&indent=true"

# Búsqueda con parámetros avanzados
curl "http://localhost:8983/solr/productos/select?wt=json&indent=true" \
  --data-urlencode "q=zapatillas deporte" \
  --data-urlencode "qf=nombre^3 descripcion etiquetas^2" \
  --data-urlencode "defType=edismax" \
  --data-urlencode "fq=activo:true" \
  --data-urlencode "fq=precio:[0 TO 100]" \
  --data-urlencode "sort=precio asc" \
  --data-urlencode "rows=20" \
  --data-urlencode "start=0" \
  --data-urlencode "fl=id,nombre,precio,categoria,score"

Búsqueda facetada

# Facetas de campo (para filtros de navegación)
curl "http://localhost:8983/solr/productos/select?wt=json&indent=true" \
  --data-urlencode "q=*:*" \
  --data-urlencode "fq=activo:true" \
  --data-urlencode "facet=true" \
  --data-urlencode "facet.field=categoria" \
  --data-urlencode "facet.field=marca" \
  --data-urlencode "facet.field=etiquetas" \
  --data-urlencode "facet.mincount=1" \
  --data-urlencode "facet.limit=10" \
  --data-urlencode "facet.range=precio" \
  --data-urlencode "facet.range.start=0" \
  --data-urlencode "facet.range.end=500" \
  --data-urlencode "facet.range.gap=50" \
  --data-urlencode "rows=0"

Búsqueda geoespacial

# Buscar productos en un radio de 10 km de unas coordenadas
curl "http://localhost:8983/solr/tiendas/select?wt=json" \
  --data-urlencode "q=*:*" \
  --data-urlencode "fq={!geofilt sfield=ubicacion pt=40.416775,-3.703790 d=10}" \
  --data-urlencode "sort=geodist() asc" \
  --data-urlencode "fl=nombre,ciudad,geodist()"

SolrCloud con ZooKeeper

SolrCloud permite distribuir los índices entre múltiples nodos:

# Iniciar ZooKeeper embebido en Solr (solo para pruebas)
sudo -u solr /opt/solr/bin/solr start -c

# Para producción, usar un ensemble de ZooKeeper externo (3 nodos)
# En cada nodo Solr, indicar la dirección de ZooKeeper
sudo -u solr /opt/solr/bin/solr start -c -z zk1:2181,zk2:2181,zk3:2181

# Crear una colección en SolrCloud con 2 shards y 2 réplicas
curl "http://localhost:8983/solr/admin/collections?action=CREATE&name=productos&numShards=2&replicationFactor=2&collection.configName=_default"

# Ver el estado del clúster
curl "http://localhost:8983/solr/admin/collections?action=CLUSTERSTATUS&wt=json" | python3 -m json.tool

# Subir configuración personalizada a ZooKeeper
sudo -u solr /opt/solr/bin/solr zk upconfig \
  -z localhost:9983 \
  -n mi-config \
  -d /opt/solr/server/solr/configsets/mi-config/

Seguridad y Autenticación

# Habilitar autenticación básica
# Crear archivo de configuración de seguridad en ZooKeeper
curl http://localhost:8983/solr/admin/authentication -H 'Content-type:application/json' \
  -d '{"set-user": {"admin": "contraseña_admin", "usuario": "contraseña_usuario"}}'

# Habilitar el handler de seguridad en solr.xml
# Editar /var/solr/data/solr.xml y añadir autenticación

# Configurar HTTPS
# Generar keystore Java
keytool -genkeypair -alias solr-ssl \
  -keyalg RSA \
  -keysize 2048 \
  -keystore /etc/solr/ssl/solr-ssl.keystore.p12 \
  -storetype PKCS12 \
  -storepass contraseña_keystore \
  -validity 3650 \
  -dname "CN=solr.tudominio.com, OU=IT, O=MiEmpresa, L=Madrid, ST=Madrid, C=ES"

Solución de Problemas

Solr no arranca:

# Revisar logs
sudo tail -100 /var/solr/logs/solr.log | grep -i "error\|exception"

# Verificar que Java está disponible
java -version

# Comprobar permisos
ls -la /var/solr/
sudo chown -R solr:solr /var/solr/

Core en estado de error:

# Ver el estado detallado del core
curl "http://localhost:8983/solr/admin/cores?action=STATUS&core=productos&wt=json" | python3 -m json.tool

# Los errores de core suelen ser por schema inconsistente o archivos de índice corruptos
# Intentar recargar el core
curl "http://localhost:8983/solr/admin/cores?action=RELOAD&core=productos"

Rendimiento lento en consultas:

# Habilitar caché de consultas en solrconfig.xml
# Revisar el plan de ejecución de la consulta con debugQuery
curl "http://localhost:8983/solr/productos/select?q=zapatillas&debugQuery=true&wt=json" | python3 -m json.tool

# Añadir docValues a los campos usados en facetas y ordenación
# Aumentar la caché de filtros (filterCache) en solrconfig.xml

Alta memoria heap:

# Ajustar SOLR_HEAP en /etc/default/solr
SOLR_HEAP=4g  # Usar máximo el 50% de la RAM disponible

sudo systemctl restart solr

Conclusión

Apache Solr es una solución de búsqueda probada en producción durante más de 15 años, con una comunidad activa y un ecosistema maduro de integraciones. Su soporte nativo para SolrCloud, las actualizaciones atómicas de campos y las capacidades geoespaciales lo hacen especialmente adecuado para aplicaciones empresariales que requieren búsqueda avanzada a escala. La curva de aprendizaje es mayor que la de soluciones más modernas como Meilisearch o Typesense, pero las posibilidades de personalización y el rendimiento en grandes volúmenes de datos justifican la inversión.