Sonic 常用 CLI 命令与工具详解

Sonic Channel 文本协议全命令实测详解:PING/AUTH/PUSH/POP/FLUSH/COUNT/QUERY/SUGG/LIST 语法、真实回显、错误码表与 Python 最小客户端实现。

SonicSonic2026/10/17

Sonic 常用 CLI 命令与工具详解

‍‍​​‌​> 目标:逐一实测 Sonic Channel 文本协议的全部常用命令(PING/AUTH/PUSH/POP/FLUSH/COUNT/QUERY/SUGG/LIST/TRIGGER/INFO 等),给出协议语法表、错误码表与一个可直接复用的 Python 最小客户端;全部回显取自 Ubuntu 22.04 + sonic-server v1.10.2 真实会话。

一、环境信息

  • 操作系统:Ubuntu 22.04(x86_64)
  • 软件版本:sonic-server v1.10.2
  • 服务端点:127.0.0.1:1491(Sonic Channel,TCP 文本协议;配置 inet = "0.0.0.0:1491")
  • 认证口令:q1w2e3r4(channel.auth_password 配置值)
  • 配置文件:/opt/data/sonic/config.cfg(参数说明见《Sonic 配置参数详解》)
  • 数据目录:/opt/data/sonic/store/
  • 测试数据:messages 集合(default 桶,对象 conversation:1 至 conversation:7,4 英 3 中文本)
  • 客户端工具:nc(netcat-openbsd)与 Python 3.10 内置 socket 库

二、前置条件

  1. Sonic 进程在运行且端口可达,用 nc 验证(实测回显):
printf 'QUIT\n' | nc -w 2 127.0.0.1 1491
CONNECTED <sonic-server v1.10.2>
ENDED quit
  1. 已知认证口令(配置 channel.auth_password,未设置则任意口令可过);
  2. 准备一个交互工具:临时手测用 nc(nc 127.0.0.1 1491 进入交互,逐行输入命令);批量验证/接入业务用本文第七节的 Python 最小客户端,或选用官方生态客户端库(Go: github.com/valeriansaliou/go-sonic;Python: github.com/x0k/sonic-client 等社区库;Rust/PHP/JS 均有社区实现)。

三、协议总览与认证

3.1 连接生命周期与问候语

每次 TCP 连接建立后,服务端先推一行问候语(实测):

CONNECTED <sonic-server v1.10.2>

随后连接处于「未认证」状态,必须先 START;未认证发送其他命令会直接终止连接(实测):

>>> PING
<<< ENDED not_recognized

正常收尾用 QUIT(实测):

>>> QUIT
<<< ENDED quit

3.2 START 与三种模式

START <模式> <口令> 完成认证并锁定通道模式,实测:

>>> START search q1w2e3r4
<<< STARTED search protocol(1) buffer(20000)

回显三段含义:模式名、协议版本 protocol(1)、单命令缓冲上限 buffer(20000)(字节)。三种模式与可用命令:

模式用途命令集
ingest写入/删除/计数/清空PING、PUSH、POP、COUNT、COUNTC、COUNTB、COUNTO、FLUSHC、FLUSHB、FLUSHO、HELP、QUIT
search查询/补全/列词PING、QUERY、SUGGEST、LIST、HELP、QUIT
control触发后台任务/状态PING、TRIGGER、INFO、HELP、QUIT

模式约束实测:search 模式发 ingest 命令被拒:

>>> PUSH messages default conversation:1 "should fail here"
<<< ERR unknown_command

非法模式名直接终止连接(实测):

>>> START badmode q1w2e3r4
<<< ENDED invalid_mode

口令错误同样终止(实测):

>>> START search wrong-pass
<<< ENDED authentication_failed

3.3 同步响应与异步响应

  • 同步命令(PUSH/POP/FLUSH/COUNT/TRIGGER/INFO/START/QUIT/PING)直接回一行结果;
  • 异步命令(QUERY/SUGGEST/LIST)两段式:先回 PENDING <任务ID>,处理完成后推送 EVENT <命令> <任务ID> [结果...],客户端凭 ID 匹配。实测一组完整交互:
>>> QUERY messages default "sonic"
<<< PENDING RHkjf3oe
<<< EVENT QUERY RHkjf3oe conversation:6 conversation:4 conversation:2 conversation:1

3.4 协议语法要素

语法要素说明示例
参数顺序固定位置参数PUSH <collection> <bucket> <object> "<text>"
引号文本参数必须双引号包裹"Hello world"
修饰符KEY(value) 形式,置于命令尾部LIMIT(10)、OFFSET(2)、LANG(cmn)
换行每条命令以 \n 结尾—
大小写命令与参数名大写,值原样保留QUERY/LIMIT

文本不加引号会报错(实测):

>>> PUSH messages default conversation:1 Hello world unquoted
<<< ERR invalid_parameter("text", "unterminated quoted string")

四、数据写入与删除命令详解(ingest 模式)

4.1 PUSH:写入索引

语法:PUSH <collection> <bucket> <object> "<text>" [LANG(<locale>)]

实测写入英文与中文测试语料(回显逐行照抄):

>>> PUSH messages default conversation:1 "Hello world, this is Sonic search backend"
<<< OK
>>> PUSH messages default conversation:2 "Sonic is a fast, lightweight and schema-less search backend"
<<< OK
>>> PUSH messages default conversation:3 "Rust is a fast systems programming language"
<<< OK
>>> PUSH messages default conversation:4 "快速上手 Sonic 搜索引擎,轻量又高效"
<<< OK
>>> PUSH messages default conversation:6 "Sonic 支持中文搜索吗?实测一下就知道"
<<< OK

要点:

  • object 是外部数据库主键(如 conversation:1),查询返回它,正文仍存业务库;
  • 文本上限为 START 回显的 buffer(20000) 字节(实测 25000 字节文本发送后服务端直接断开连接);
  • 更新对象 = 先 POP 旧文本再 PUSH 新文本;
  • 中文建议显式 LANG(cmn) 强制词级分词(实测对比见《Sonic 介绍与选型指南》4.2 节)。

4.2 POP:按文本删除

语法:POP <collection> <bucket> <object> "<text>"——必须提供与写入时相同的文本,服务端按词条反删。实测(回显为被删除的词条数):

>>> POP messages default conversation:1 "Hello world, this is Sonic search backend"
<<< RESULT 3

删除不存在的文本返回 0,不报错(实测):

>>> POP messages default conversation:1 "some other text that was never pushed"
<<< RESULT 0

删除效果复核(conversation:1 原有 3 词条,删后为 0):

>>> COUNTO messages default conversation:1
<<< RESULT 0

⚠️ 注意:POP 只删除「文本分词后命中的词条映射」。若原文因停用词过滤从未入索引的词,POP 无需也无法删除它们;文本前后空白差异可能造成删不干净,务必用原文。

4.3 FLUSHO / FLUSHB / FLUSHC:三级清空

命令语法作用范围
FLUSHOFLUSHO <collection> <bucket> <object>清除单个对象
FLUSHBFLUSHB <collection> <bucket>清除整个桶
FLUSHCFLUSHC <collection>清除整个集合

实测记录(FLUSHO 返回被清除的词条数):

>>> FLUSHO ftest2 def o1
<<< RESULT 3

(该对象文本 red green blue,3 个词条,数字精确对应。)

FLUSHB/FLUSHC 实测:

>>> FLUSHB ftest def
<<< RESULT 1
>>> FLUSHC ftest2
<<< RESULT 1
>>> COUNTC ftest2
<<< RESULT 0

💡 说明:官方协议文档将 FLUSHB/FLUSHC 返回值描述为清除计数,但实测中(无论桶内 4 个对象还是 2 个对象)均返回 1;建议把该返回值当作「操作已受理」的指示符,实际效果用 COUNT 系列命令复核(上例 COUNTC 归 0 即确认清空成功)。

4.4 COUNT / COUNTC / COUNTB / COUNTO:计数

命令语法返回含义(实测+源码确认)
COUNTCCOUNTC <collection>集合内桶数
COUNTBCOUNTB <collection> <bucket>桶内对象数
COUNTOCOUNTO <collection> <bucket> <object>对象词条数

实测(7 个对象、1 个桶、conversation:1 有 3 词条时):

>>> COUNTC messages
<<< RESULT 1
>>> COUNTB messages default
<<< RESULT 7
>>> COUNTO messages default conversation:1
<<< RESULT 3

老命令 COUNT(不带段名)在 1.10.2 已被官方弃用,且三种参数形态行为不一致(实测 COUNT messages 返回 0 而 COUNTB messages default 返回 7),新代码一律使用 COUNTC/COUNTB/COUNTO 三段式。

五、数据查询命令详解(search 模式)

5.1 QUERY:全文检索

语法:QUERY <collection> <bucket> "<terms>" [LIMIT(<number>)] [OFFSET(<number>)] [LANG(<locale>)]

英文多词检索(相关度降序,实测):

>>> QUERY messages default "sonic"
<<< PENDING RHkjf3oe
<<< EVENT QUERY RHkjf3oe conversation:6 conversation:4 conversation:2 conversation:1
>>> QUERY messages default "search backend"
<<< PENDING KHwJjB2h
<<< EVENT QUERY KHwJjB2h conversation:2 conversation:1

分页修饰符实测(LIMIT(2) 取前 2,OFFSET(2) 跳过前 2):

>>> QUERY messages default "sonic" LIMIT(2)
<<< EVENT QUERY 4GmsXQ3s conversation:6 conversation:4
>>> QUERY messages default "sonic" LIMIT(2) OFFSET(2)
<<< EVENT QUERY LNNwCfzR conversation:2 conversation:1

LIMIT 越界被拒(受 query_limit_maximum = 100 约束,实测):

>>> QUERY messages default "sonic" LIMIT(1000)
<<< ERR policy_reject(LIMIT out of minimum/maximum bounds)

无命中词返回空 EVENT(实测):

>>> QUERY nosuch nobucket "test"
<<< PENDING hDweLkYB
<<< EVENT QUERY hDweLkYB

中文检索实测要点:查询词分词路径与索引一致才能精确命中。实测 QUERY messages default "搜索引擎" 直接返回了以「搜索引擎」为词索引的对象:

>>> QUERY messages default "搜索引擎"
<<< PENDING lBPsXyUe
<<< EVENT QUERY lBPsXyUe conversation:4 conversation:6

而「今天天气」这类在索引中被逐字切开的查询词,精确命中为空、靠 FST 相似词兜底返回了包含 今天天气 词条的对象(实测):

>>> QUERY messages default "今天天气"
<<< PENDING 4bD69jt3
<<< EVENT QUERY 4bD69jt3 conversation:4

⚠️ 注意:这就是中文场景必须「写入与查询同用 LANG(cmn)」的原因——索引粒度(词/字)与查询粒度错位时,精确命中降级为模糊兜底,排序质量随之下降。

5.2 SUGGEST:搜索补全

语法:SUGGEST <collection> <bucket> "<word>" [LIMIT(<number>)]

基于 FST 词图的前缀补全(实测):

>>> SUGGEST messages default "son"
<<< PENDING RBt9H0YP
<<< EVENT SUGGEST RBt9H0YP sonic
>>> SUGGEST messages default "sea"
<<< PENDING j2CW2mCR
<<< EVENT SUGGEST j2CW2mCR search

无匹配前缀返回空 EVENT(实测):

>>> SUGGEST messages default "zzz"
<<< PENDING TZYugGVH
<<< EVENT SUGGEST TZYugGVH

⚠️ 注意:SUGGEST/LIST 依赖 FST 词图合并(默认 180 秒周期或手动 TRIGGER consolidate),刚 PUSH 的词可能暂不可补全(实测复现与解法见 6.1)。

5.3 LIST:列出索引词表

语法:LIST <collection> <bucket> [LIMIT(<number>)] [OFFSET(<number>)]

实测列出 messages 桶全部词条(LIMIT(500) 满页):

>>> LIST messages default LIMIT(500)
<<< PENDING ybeCU5Y0
<<< EVENT LIST ybeCU5Y0   sonic 不 不错 中文搜索 今 今天天气 北京 天 实测 快 快速 手 搜索引擎 支持 轻量 知道 高效 backend contact example.org fast language lightweight programming rust schema search support systems

(可读性起见按输出原样截取;可见中文逐字词条与英文词级词条并存、停用词已滤除、conversation:7 的 contact/example.org/support 三个词条在 POP 前存在。)

LIMIT 越界同样被拒(实测):

>>> LIST messages default LIMIT(5000)
<<< ERR policy_reject(LIMIT out of minimum/maximum bounds)

六、管理命令详解(control 模式)

6.1 TRIGGER:触发后台任务

语法:TRIGGER <action>,实测可用 action 为 consolidate(合并 FST 词图)。实测效果——合并前 LIST/SUGGEST 为空:

>>> LIST messages default
<<< PENDING Jy058Ddq
<<< EVENT LIST Jy058Ddq
>>> SUGGEST messages default "sea"
<<< PENDING Efx83Ib2
<<< EVENT SUGGEST Efx83Ib2

触发合并后立即可用(实测):

>>> TRIGGER consolidate
<<< OK
>>> LIST messages default LIMIT(50)
<<< PENDING p0cSlmwt
<<< EVENT LIST p0cSlmwt   backend contact example.org fast language lightweight programming rust schema search sonic support systems 一下 不错 中文搜索 今天天气 出门 实测 快速 手 搜索引擎 支持 散步 知道 轻量 高效

批量写入后的固定动作建议:PUSH 批次结束 → control 模式 TRIGGER consolidate → 再开放查询流量,保证补全与纠错立即可用。

6.2 INFO:运行统计

语法:INFO,实测:

>>> INFO
<<< RESULT uptime(179) clients_connected(1) commands_total(35) command_latency_best(2) command_latency_worst(63) kv_open_count(1) fst_open_count(1) fst_consolidate_count(1)

字段含义:uptime 进程运行秒数;clients_connected 当前连接数(监控连接泄漏);commands_total 累计命令数;command_latency_best/worst 命令延迟极值(微秒);kv_open_count/fst_open_count 打开的 KV/FST 库句柄数(多集合部署排查句柄占用);fst_consolidate_count 累计合并次数。

6.3 HELP:命令自述

各模式均可 HELP 与 HELP commands(实测 search 模式):

>>> HELP
<<< RESULT PING QUIT
>>> HELP commands
<<< RESULT QUERY SUGGEST LIST PING HELP QUIT

(ingest 模式 HELP commands 实测回显 RESULT PUSH POP COUNT COUNTC COUNTB COUNTO FLUSHC FLUSHB FLUSHO PING HELP QUIT;control 模式回显 RESULT TRIGGER INFO PING HELP QUIT——HELP commands 就是该模式可用命令集的权威清单。)

七、Python 最小客户端实现

仅用标准库 socket 即可实现协议客户端,以下代码可直接保存为 sonic_client.py 使用(本专栏全部实测回显即出自它):

#!/usr/bin/env python3
"""Minimal Sonic Channel text-protocol client (raw TCP, no deps)."""
import re
import socket
import time


class SonicClient:
    def __init__(self, host="127.0.0.1", port=1491, timeout=15):
        self.sock = socket.create_connection((host, port), timeout=timeout)
        self.buf = b""
        self.greeting = self._read_line()          # CONNECTED <sonic-server v1.10.2>

    def _read_line(self):
        while b"\n" not in self.buf:
            chunk = self.sock.recv(4096)
            if not chunk:
                raise ConnectionError("connection closed by server")
            self.buf += chunk
        line, self.buf = self.buf.split(b"\n", 1)
        return line.decode("utf-8", "replace").rstrip("\r")

    def cmd(self, command, timeout=15):
        """Send one command; return list of response lines (verbatim)."""
        self.sock.sendall((command + "\n").encode("utf-8"))
        lines, deadline = [], time.time() + timeout
        pending_id = None
        while True:
            line = self._read_line()
            lines.append(line)
            m = re.match(r"^PENDING\s+(\S+)", line)
            if m:
                pending_id = m.group(1)            # async command: wait for EVENT
            if line.startswith("EVENT ") or pending_id is None:
                if re.match(r"^(PONG|OK|ERR|ENDED|STARTED|EVENT)\b", line):
                    break
            if time.time() > deadline:
                break
        return lines

    def close(self):
        try:
            self.cmd("QUIT", timeout=5)
        except Exception:
            pass
        self.sock.close()

使用示例(写入 → 检索完整闭环,实测输出附后):

from sonic_client import SonicClient

# 写入侧
c = SonicClient()
print(c.greeting)
for line in c.cmd("START ingest q1w2e3r4"):
    print(line)
for line in c.cmd('PUSH messages default conversation:1 "Hello world, this is Sonic search backend"'):
    print(line)
c.close()

# 查询侧
s = SonicClient()
s.cmd("START search q1w2e3r4")
for line in s.cmd('QUERY messages default "sonic"'):
    print(line)
s.close()

实测输出:

CONNECTED <sonic-server v1.10.2>
STARTED ingest protocol(1) buffer(20000)
OK
PENDING RHkjf3oe
EVENT QUERY RHkjf3oe conversation:6 conversation:4 conversation:2 conversation:1

实现要点:QUERY/SUGGEST/LIST 必须等待 EVENT <命令> <同ID> 行才算完成(本实现的 pending_id 匹配逻辑);生产化还需补上重连、口令配置化与并发事件分发。

八、命令速查与错误码

8.1 命令速查表

命令模式语法同步/异步实测成功回显
PING全部PING同步PONG
START未认证START <mode> <password>同步STARTED <mode> protocol(1) buffer(20000)
QUIT全部QUIT同步ENDED quit
PUSHingestPUSH <c> <b> <o> "<text>" [LANG(l)]同步OK
POPingestPOP <c> <b> <o> "<text>"同步RESULT <删除词条数>
COUNTCingestCOUNTC <c>同步RESULT <桶数>
COUNTBingestCOUNTB <c> <b>同步RESULT <对象数>
COUNTOingestCOUNTO <c> <b> <o>同步RESULT <词条数>
FLUSHCingestFLUSHC <c>同步RESULT 1(见 4.3 说明)
FLUSHBingestFLUSHB <c> <b>同步RESULT 1(见 4.3 说明)
FLUSHOingestFLUSHO <c> <b> <o>同步RESULT <词条数>
QUERYsearchQUERY <c> <b> "<terms>" [LIMIT(n)] [OFFSET(n)] [LANG(l)]异步EVENT QUERY <id> <objects...>
SUGGESTsearchSUGGEST <c> <b> "<word>" [LIMIT(n)]异步EVENT SUGGEST <id> <words...>
LISTsearchLIST <c> <b> [LIMIT(n)] [OFFSET(n)]异步EVENT LIST <id> <words...>
TRIGGERcontrolTRIGGER consolidate同步OK
INFOcontrolINFO同步RESULT uptime(...) ...
HELP全部HELP [commands]同步RESULT <命令列表>

8.2 错误响应表(实测汇总)

回显触发场景(实测)处置
ENDED not_recognized未认证时发送任意命令先 START 再发命令
ENDED authentication_failed口令错误核对 channel.auth_password
ENDED invalid_modeSTART 模式名非法用 ingest/search/control
ERR unknown_command当前模式不支持该命令核对命令与模式归属
ERR invalid_parameter("text", "unterminated quoted string")文本未加双引号文本参数加双引号
ERR policy_reject(LIMIT out of minimum/maximum bounds)LIMIT 超出 search 段上限1 ≤ LIMIT ≤ maximum
连接直接断开单命令超过 buffer(20000) 字节拆分文本分多次 PUSH

通用规则:ERR 开头的行不终止连接,可继续发送后续命令;ENDED 开头的行意味着服务端已关闭本次连接,客户端必须重连并重新 START。

九、常见问题

Q1:PING 返回 ENDED not_recognized? 命令发在 START 之前。Sonic 通道必须先认证选模式,任何未认证命令都会结束连接(实测复现)。

Q2:QUERY 报 ERR unknown_command? 命令发错了模式——QUERY 属 search 模式,在 ingest 连接里不可用。按第八节速查表核对命令归属(实测在 search 连接里发 PUSH 同样报此错)。

Q3:PUSH 返回 OK 但 QUERY 查不到? 先查对象与桶拼写;再确认查询词没有踩停用词(如 hello/world/help 均在英文停用词表,实测不在索引词表中);中文场景检查索引与查询的分词粒度是否一致(LANG(cmn) 用法见 5.1)。

Q4:SUGGEST/LIST 返回空但 PUSH 成功? FST 词图尚未合并。等默认 180 秒周期,或 control 模式 TRIGGER consolidate 后立即生效(实测复现并解决)。

Q5:发送长文本后连接消失? 超过 START 回显的 buffer 上限(20000 字节),服务端直接断开。客户端按 buffer 拆分文本、同一对象分多次 PUSH 即可(实测复现)。

Q6:POP 后 COUNTO 不为 0? POP 按词条删除,传入文本与原文不一致(空白/标点差异)会漏删。用与 PUSH 完全一致的原文;顽固残留用 FLUSHO 直接清对象(实测 FLUSHO 后 COUNTC/COUNTO 立即归 0)。

Q7:如何确认服务端版本与运行状态? 问候语 CONNECTED <sonic-server v1.10.2> 带版本;control 模式 INFO 看连接数、命令延迟与句柄数(均为实测字段,见 6.2)。

十、参考链接