ManticoreSearch Installation and Configuration

ManticoreSearch is a high-performance full-text search engine with a MySQL-compatible SQL interface and real-time indexing, designed as a modern replacement for Sphinx Search. This guide covers installing ManticoreSearch on Linux, using the SQL interface, creating real-time indexes, integrating data sources, replication, and migrating from Sphinx.

Prerequisites

  • Ubuntu 20.04+ / Debian 11+ or CentOS 8+ / Rocky Linux 8+
  • 1 GB RAM minimum (more RAM = better performance)
  • MySQL client tools for interacting with Manticore
  • Root or sudo access

Installing ManticoreSearch

# Ubuntu/Debian
wget https://repo.manticoresearch.com/manticore-repo.noarch.deb
sudo dpkg -i manticore-repo.noarch.deb
sudo apt-get update
sudo apt-get install -y manticore manticore-extra

# CentOS/Rocky Linux
sudo rpm --import https://repo.manticoresearch.com/GPG-KEY-manticore
wget https://repo.manticoresearch.com/manticore-repo.noarch.rpm
sudo rpm -i manticore-repo.noarch.rpm
sudo dnf install -y manticore manticore-extra

# Verify installation
searchd --version

# Enable and start the service
sudo systemctl enable --now manticore
sudo systemctl status manticore

# Connect with MySQL client (Manticore uses MySQL protocol on port 9306)
mysql -h 127.0.0.1 -P 9306 -u root

Once connected you'll see a MySQL-like prompt. Manticore uses standard SQL syntax for search operations.

Configuration Overview

The main configuration file is /etc/manticoresearch/manticore.conf:

# /etc/manticoresearch/manticore.conf

searchd {
    listen = 127.0.0.1:9306:mysql41    # MySQL protocol
    listen = 127.0.0.1:9308:http      # HTTP/JSON API
    listen = 127.0.0.1:9312           # Binary protocol (Sphinx compat)
    
    log = /var/log/manticore/searchd.log
    query_log = /var/log/manticore/query.log
    query_log_format = sphinxql

    pid_file = /run/manticore/searchd.pid
    data_dir = /var/lib/manticore/data

    # Performance
    max_children = 30
    net_throttle_accept = 0
    binlog_path = /var/lib/manticore/binlog
}

Restart after config changes:

sudo systemctl restart manticore

Creating Real-Time Indexes

Real-time (RT) indexes accept INSERT, UPDATE, and DELETE operations immediately without rebuilding:

-- Connect to ManticoreSearch
mysql -h 127.0.0.1 -P 9306

-- Create a real-time index
CREATE TABLE products (
    id          BIGINT,
    title       TEXT,
    description TEXT,
    category    STRING,
    brand       STRING,
    price       FLOAT,
    in_stock    BOOL,
    tags        STRING ATTRIBUTE MULTI,
    created_at  TIMESTAMP
) engine='columnar';

-- The 'id' column is the primary key (must be a positive integer)
-- TEXT columns are full-text indexed
-- STRING columns are for filtering and sorting (not full-text)
-- ATTRIBUTE MULTI = multi-valued attribute (like an array)

Indexing and Querying with SQL

-- Insert documents
INSERT INTO products (id, title, description, category, brand, price, in_stock, tags)
VALUES
(1, 'Mechanical Keyboard TKL', 'Cherry MX Brown switches tenkeyless layout', 'Electronics', 'Keychron', 89.99, 1, (1,2,3)),
(2, 'Ergonomic Vertical Mouse', 'Reduces wrist strain for long work sessions', 'Electronics', 'Logitech', 45.00, 0, (2,4)),
(3, 'USB-C Hub 7-in-1', 'HDMI, USB-A, SD card, power delivery', 'Electronics', 'Anker', 39.99, 1, (5,6));

-- Full-text search
SELECT id, title, price, WEIGHT() AS relevance
FROM products
WHERE MATCH('mechanical keyboard')
ORDER BY relevance DESC;

-- Full-text with filters
SELECT id, title, brand, price
FROM products
WHERE MATCH('keyboard OR mouse')
  AND price < 100
  AND in_stock = 1
ORDER BY price ASC
LIMIT 10;

-- Full-text search with field-specific matching
SELECT id, title
FROM products
WHERE MATCH('@title mechanical @description switches');

-- Update a document
UPDATE products SET price = 79.99, in_stock = 1 WHERE id = 2;

-- Delete
DELETE FROM products WHERE id = 3;

-- Truncate (remove all documents)
TRUNCATE RTINDEX products;

Plain Indexes from Data Sources

Plain indexes are built from a data source (MySQL, PostgreSQL, etc.) and are read-only after building. Useful for large static datasets:

# Add to /etc/manticoresearch/manticore.conf

source products_src {
    type = mysql
    sql_host = localhost
    sql_user = myuser
    sql_pass = mypassword
    sql_db   = mydb
    sql_port = 3306

    sql_query_pre  = SET NAMES utf8
    sql_query      = SELECT id, title, description, category, price, UNIX_TIMESTAMP(created_at) AS created_ts FROM products WHERE id >= $start AND id <= $end
    sql_query_range = SELECT MIN(id), MAX(id) FROM products
    sql_range_step  = 1000

    # Declare non-full-text attributes
    sql_attr_float  = price
    sql_attr_string = category
    sql_attr_uint   = created_ts
}

index products_plain {
    type    = plain
    source  = products_src
    path    = /var/lib/manticore/data/products_plain
}

Build and rotate the index:

# Build the plain index
sudo -u manticore indexer --config /etc/manticoresearch/manticore.conf products_plain

# Rotate (load new index without downtime)
sudo -u manticore indexer --config /etc/manticoresearch/manticore.conf --rotate products_plain

# Or rebuild all indexes
sudo -u manticore indexer --all --rotate

Full-Text Search Features

-- Boolean operators
SELECT * FROM products WHERE MATCH('keyboard AND switches');
SELECT * FROM products WHERE MATCH('keyboard OR mouse');
SELECT * FROM products WHERE MATCH('keyboard NOT gaming');

-- Phrase search
SELECT * FROM products WHERE MATCH('"mechanical keyboard"');

-- Proximity search (words within N positions)
SELECT * FROM products WHERE MATCH('"keyboard switches"~5');

-- Wildcard search (requires min_prefix_len or min_infix_len in config)
SELECT * FROM products WHERE MATCH('key*');

-- Fuzzy / typo-tolerant search
SELECT * FROM products WHERE MATCH('keyborad~1');  -- 1 edit distance

-- Field weighting
SELECT id, title, WEIGHT() AS w
FROM products
WHERE MATCH('keyboard')
OPTION field_weights=(title=10, description=1)
ORDER BY w DESC;

-- Faceted search with grouping
SELECT category, COUNT(*) AS cnt, AVG(price) AS avg_price
FROM products
WHERE MATCH('keyboard')
GROUP BY category
ORDER BY cnt DESC;

-- SNIPPET - highlight matched terms
SELECT id, SNIPPET(description, 'mechanical keyboard', 'limit=200,around=5') AS excerpt
FROM products
WHERE MATCH('mechanical keyboard');

Configure fuzzy and wildcard support in manticore.conf:

index products {
    # ...
    min_prefix_len = 3    # Enable prefix wildcards (key* matches keyboard)
    min_infix_len  = 3    # Enable infix wildcards (*board* matches keyboard)
    morphology     = stem_en   # English stemming (run = running = ran)
}

Replication and High Availability

ManticoreSearch supports streaming replication for real-time indexes:

-- On the primary node: create a replication cluster
CREATE CLUSTER my_cluster;

-- Add an index to the cluster
ALTER CLUSTER my_cluster ADD products;

-- On each replica node, join the cluster
-- (replace primary_ip with the actual IP)
JOIN CLUSTER my_cluster AT 'primary_ip:9312';

-- Check cluster status
SHOW STATUS LIKE 'cluster%';

Clients should connect to any node in the cluster. For load balancing, use HAProxy:

# HAProxy frontend for ManticoreSearch
listen manticore
    bind 0.0.0.0:9306
    mode tcp
    balance roundrobin
    server node1 192.168.1.10:9306 check
    server node2 192.168.1.11:9306 check
    server node3 192.168.1.12:9306 check

Troubleshooting

Check logs:

sudo tail -f /var/log/manticore/searchd.log
sudo tail -f /var/log/manticore/query.log

ManticoreSearch won't start:

# Test config file syntax
searchd --config /etc/manticoresearch/manticore.conf --stopwait
searchd --config /etc/manticoresearch/manticore.conf --status

Index not found or empty:

-- List all indexes
SHOW TABLES;

-- Check index status
SHOW INDEX products STATUS;
SHOW INDEX products SETTINGS;

Full-text query returns no results:

-- Check that the index has documents
SELECT COUNT(*) FROM products;

-- Debug MATCH query
SELECT id, title, WEIGHT() FROM products WHERE MATCH('keyboard') OPTION ranker=none;
-- WEIGHT() = 1 means no ranking, confirms documents are found

Slow queries:

-- Check query log for slow queries
-- Set in config:
-- query_log_min_msec = 100  (log queries over 100ms)

-- Check index statistics
CALL KEYWORDS('mechanical keyboard', 'products', 1);
-- Shows term frequency and statistics

Migrate from Sphinx:

# ManticoreSearch is API-compatible with Sphinx 2.x
# Most Sphinx configs work with minimal changes:
# 1. Replace 'sphinx' with 'manticore' in service names
# 2. Update the data_dir path
# 3. Change listen syntax if needed
# Existing plain indexes can be used directly by copying files

Conclusion

ManticoreSearch delivers exceptional full-text search performance with a familiar SQL interface, making it accessible to developers who know MySQL. Real-time indexes provide instant write visibility, while plain indexes built from SQL databases handle large static datasets efficiently. The built-in streaming replication enables high availability without external tools, and the Sphinx compatibility layer simplifies migration for existing deployments. For production use, configure replication across at least two nodes and use HAProxy or a similar load balancer for connection distribution.