使用 Sphinx 實現子域名匹配(搜 jb51.net 命中 www.jb51.net、host.jb51.net)時,默認分詞器以點號 . 為分隔符,導致過度分詞(命中 jb51.a.cn)與漏匹配(漏掉 jb51.net.com)。本文通過 charset_table 配置、邊界後綴標記、特殊字符替換三步徹底解決域名搜索精準匹配問題。
jb51.net → 分詞為 jb51、net → 命中 aajb51.net、jb51.a.cn、jb51.net.com(噪音極大)。jb51.net 結尾的域名(含子域名)。在 sphinx.conf index 區塊配置:
charset_table = 0..9, A..Z->a..z, a..z, U+002E, U+002D, U+0040, U+0060
# 含義:
# 0-9 數字
# A-Z 大寫轉小寫 + a-z 小寫
# U+002E = '.' (點號) ← 關鍵:將點號視為字符而非分隔符
# U+002D = '-' (連字符)
# U+0040 = '@'
# U+0060 = '`' (反引號,備用特殊字符)
效果:jb51.net 作為整體詞項進入索引,不再拆分為 jb51 + net。解決 jb51.a.cn 類誤命中。
數據源 SQL 中對域名字段拼接唯一標記(如 __END__):
sql_query = SELECT id, CONCAT(domain, '__END__') AS domain_idx FROM domains;
搜索時同樣帶上後綴:
SELECT * FROM domains_idx WHERE MATCH('jb51.net__END__');
效果:精確匹配以 jb51.net 結尾的域名,排除 jb51.net.com(其索引為 jb51.net.com__END__,不匹配)。
SphinxQL 中 MATCH('@"jb51.net"')(雙引號短語匹配)與點號、單引號存在解析衝突。實測最穩健方案:
. 替換為反引號 `(已在 charset_table 納入)。MATCH('`jb51`net__END__')(或直接用步驟 2 的後綴法,無需短語匹配)。替換規則表:
| 原字符 | 替換為 | Unicode | charset_table 需包含 |
|---|---|---|---|
| . | ` | U+0060 | U+0060 |
| - | - | U+002D | U+002D |
| @ | @ | U+0040 | U+0040 |
source domains_src
{
type = mysql
sql_host = localhost
sql_user = sphinx
sql_pass = secret
sql_db = mydb
sql_query = SELECT id, CONCAT(domain, '__END__') AS domain_idx FROM domains
sql_attr_uint = id
}
index domains_idx
{
source = domains_src
path = /var/lib/sphinx/domains_idx
charset_table = 0..9, A..Z->a..z, a..z, U+002E, U+002D, U+0040, U+0060
min_word_len = 1
enable_star = 1 # 支持通配符 *
}
searchd
{
listen = 9306:mysql41
log = /var/log/sphinx/searchd.log
query_log = /var/log/sphinx/query.log
}
-- 命中 www.jb51.net、jb51.net、host.jb51.net
SELECT * FROM domains_idx WHERE MATCH('jb51.net__END__');
-- 不命中 jb51.net.com、aajb51.net
SELECT * FROM domains_idx WHERE MATCH('jb51.net.com__END__');
indexer --rotate domains_idx。__END__)。charset_table 納入 CJK 範圍或使用 ngram_chars,另行規劃。Sphinx 子域名精準匹配三板斧:
1. charset_table 納入點號 → 禁止過度分詞。
2. 索引/查詢雙端加唯一後綴 → 精確邊界匹配,排除父域名干擾。
3. 特殊字符統一替換為反引號 → 規避解析器衝突。
配置生效後重建索引,即可實現「搜主域名,命中所有子域名,排除無關域名」的業務語義。