Skip to content

Query Guide

Learn how to search effectively with MygramDB.

What is CIDR?

CIDR is a notation for a range of IP addresses. If you cannot connect, first check that the client IP falls inside network.allow_cidrs.

Allow your source IP

Before executing queries, ensure your IP is registered in allow_cidrs in the configuration. Without CIDR registration, all connections are denied. See Network Security.

Connecting with mygram-cli

bash
mygram-cli -h localhost -p 11016

Once connected, you can execute queries interactively.

mygram
127.0.0.1:11016> SEARCH articles hello world
OK RESULTS 3 101 205 387

In a single-database configuration, articles resolves to that database's table. In a multi-database configuration, qualify the table as <database>.<table>:

mygram
127.0.0.1:11016> SEARCH app_db.articles hello world

Boolean Operators

Reading the operators

AND means "contains both", OR means "contains any", and NOT means "exclude anything containing this". For anything complex, parentheses make the intent unambiguous.

AND - All terms must match

mygram
127.0.0.1:11016> SEARCH articles golang AND tutorial

OR - Any term matches

mygram
127.0.0.1:11016> SEARCH articles golang OR python OR rust

NOT - Exclude terms

mygram
127.0.0.1:11016> SEARCH articles tutorial NOT beginner
127.0.0.1:11016> SEARCH articles tutorial AND NOT beginner

AND NOT is equivalent to NOT here. It is accepted for clients that represent each additional condition with an AND prefix.

Combined

mygram
127.0.0.1:11016> SEARCH articles (golang OR python) AND tutorial NOT beginner

Use quotes for exact phrases:

mygram
127.0.0.1:11016> SEARCH articles "machine learning"
127.0.0.1:11016> SEARCH articles 'web framework'

Combine with operators:

mygram
127.0.0.1:11016> SEARCH articles "web framework" AND (golang OR python)

Filtering

Filter by column values:

mygram
127.0.0.1:11016> SEARCH articles tech FILTER status = 1
127.0.0.1:11016> SEARCH articles tech FILTER views > 1000
127.0.0.1:11016> SEARCH articles tech FILTER created_at >= 2024-01-01

Filter columns must be configured

FILTER only works on columns declared under tables[*].filters or tables[*].required_filters in the config file. A column that exists in MySQL but is not declared cannot be used as a search-time filter.

Multiple filters (AND logic):

mygram
127.0.0.1:11016> SEARCH articles tech FILTER status = 1 FILTER category_id = 5

Filter Operators

OperatorAliasDescription
=EQEqual
!= / <>NENot equal
>GTGreater than
>=GTEGreater or equal
<LTLess than
<=LTELess or equal

Sorting

Sort by primary key:

mygram
127.0.0.1:11016> SEARCH articles golang SORT ASC
127.0.0.1:11016> SEARCH articles golang SORT DESC

Sort by column:

mygram
127.0.0.1:11016> SEARCH articles golang SORT created_at DESC
127.0.0.1:11016> SEARCH articles golang SORT BY created_at DESC
127.0.0.1:11016> SEARCH articles golang SORT _score ASC

BY is optional; both column forms are valid. SORT ASC and SORT DESC remain shorthand for primary-key ordering.

Relevance Sort (BM25)

Sort by BM25 relevance score using the reserved _score column (v1.6.0+):

mygram
127.0.0.1:11016> SEARCH articles "machine learning" SORT _score DESC LIMIT 10

BM25 computes IDF and TF at query time, with bm25.k1 (default 1.2) and bm25.b (default 0.75) as tuning parameters. SORT _score requires both bm25.enable: true and verify_text set to "ascii" or "all", so that term frequency can be counted from stored normalized text.

Highlighting

Return text snippets with matched terms wrapped in tags (v1.6.0+):

mygram
127.0.0.1:11016> SEARCH articles "machine learning" HIGHLIGHT LIMIT 10
127.0.0.1:11016> SEARCH articles "golang" HIGHLIGHT TAG <strong> </strong> LIMIT 10
127.0.0.1:11016> SEARCH articles "database" HIGHLIGHT SNIPPET_LEN 200 MAX_FRAGMENTS 5 LIMIT 10
OptionDefaultRangeDescription
TAG <open> <close><em> / </em>Open/close tags
SNIPPET_LEN <n>1001–10,000Max code points per fragment
MAX_FRAGMENTS <n>31–100Max fragments joined with ellipsis

HIGHLIGHT requires verify_text to be "ascii" or "all".

Match terms within a Levenshtein edit distance (v1.6.0+):

mygram
127.0.0.1:11016> SEARCH articles "machne" FUZZY LIMIT 10
127.0.0.1:11016> SEARCH articles "databse" FUZZY 2 LIMIT 10

Distance 1 (default) matches terms within 1 edit (insert/delete/substitute); 2 matches within 2 edits. Candidates are pre-filtered by length to keep this cheap.

FACET Aggregation

Aggregate distinct filter-column values with document counts (v1.6.0+):

mygram
127.0.0.1:11016> FACET articles status
127.0.0.1:11016> FACET articles category "search text" FILTER status = 1 LIMIT 10

Response (sorted by count, DESC):

mygram
OK FACET <column>
<value1> <count1>
<value2> <count2>
...
END

FACET supports the same AND/NOT/FILTER/LIMIT clauses as SEARCH when scoping aggregation to a query.

Since v1.7.0, FACET is also exposed over HTTP at POST /tables/{identity}/facet. The HTTP body uses column, optional q, optional filters, and optional limit.

Synonym Expansion

When a synonym dictionary is configured (synonyms.enable: true, see Configuration), search terms are transparently expanded to OR-groups of their synonyms at query time. No query-side syntax change is needed — a query for car will also match automobile and vehicle when they are grouped in the TSV dictionary.

Synonyms are configured per table under tables[*].synonyms. Fuzzy search takes a separate execution path and is not combined with synonym expansion for the same query.

Pagination

mygram
127.0.0.1:11016> SEARCH articles golang LIMIT 10
127.0.0.1:11016> SEARCH articles golang LIMIT 10 OFFSET 20

Count Query

Get count without IDs:

mygram
127.0.0.1:11016> COUNT articles golang AND tutorial
OK COUNT 42

Complete Examples

Find recent Go tutorials

mygram
127.0.0.1:11016> SEARCH articles golang AND tutorial FILTER status = 1 SORT created_at DESC LIMIT 20
mygram
127.0.0.1:11016> SEARCH posts (mysql OR postgresql) AND performance FILTER views > 1000 SORT _score DESC LIMIT 10

Top relevance with highlighted snippets

mygram
127.0.0.1:11016> SEARCH articles "machine learning" SORT _score DESC HIGHLIGHT LIMIT 10

Count active users in category

mygram
127.0.0.1:11016> COUNT users tech FILTER status = 1 FILTER category_id = 5

HTTP API

SEARCH, COUNT, FACET, and document GET are also exposed over HTTP. v1.7.0 uses the /tables/{identity}/... route shape. HTTP q is literal by default; add "mode": "boolean" only when q is an intentional boolean expression.

bash
curl -X POST http://localhost:8080/tables/articles/search \
  -H "Content-Type: application/json" \
  -d '{"q": "golang tutorial", "limit": 10}'

curl -X POST http://localhost:8080/tables/articles/count \
  -H "Content-Type: application/json" \
  -d '{"q": "golang"}'

curl -X POST http://localhost:8080/tables/articles/facet \
  -H "Content-Type: application/json" \
  -d '{"column": "category", "q": "golang", "limit": 10}'

curl -X POST http://localhost:8080/tables/articles/search \
  -H "Content-Type: application/json" \
  -d '{"q": "golang AND tutorial", "mode": "boolean", "limit": 10}'

With two or more configured databases, use /tables/app_db.articles/.... Admin commands such as SET, SHOW VARIABLES, SYNC, and DUMP remain TCP/CLI-only.

Operator Precedence

Without parentheses, operators are evaluated in this order:

  1. NOT (highest)
  2. AND
  3. OR (lowest)

Example: a OR b AND c is parsed as a OR (b AND c)

Pin the intent with parentheses

Use parentheses to make your intent clear and avoid unexpected results.

Performance Tips

  1. Use LIMIT - Enables faster partial sorting
  2. Add specific filters - Reduces result set early
  3. Use AND over OR - AND queries are typically faster
  4. Index filter columns - Configure frequently filtered columns in config

Next Steps

Detailed Documentation