资讯动态

Elasticsearch中文搜索生产部署全指南:单点→集群→IK→Kibana闭环

发布时间:2026/10/26 22:21:06 来源:尧图企业网站定制
1. 这不是“装个软件”那么简单单点ES、Kibana、IK与集群部署的完整闭环你搜“安装elasticsearch”页面上跳出来的大多是零散的三行命令wget、tar -xzf、./bin/elasticsearch——然后就没了。但真实项目里没人只图“能跑起来”。你要查日志得配Kibana你要搜中文内容得加IK分词器你刚上线两天ES进程挂了用户查不到数据这时候你才意识到单点单点故障。这根本不是“安装”而是一整套可观测、可检索、可扩展、可维护的搜索基础设施搭建过程。我带过好几个从零起步的搜索项目最常被低估的就是部署阶段的决策成本。比如选7.17.2还是8.11.3表面看是版本号差异实则关系到后续三年的升级路径、插件兼容性、甚至Java版本锁死问题。再比如IK分词器有人直接下GitHub最新release包往plugins目录一扔结果发现分词效果和线上业务对不上——因为没同步更新词典也没做热更新配置。还有集群部署很多人以为“多起几个节点改个cluster.name就行”结果发现节点间ping不通、master选举失败、shard一直unassigned……最后排查三天发现只是防火墙没开9300端口。这篇内容就是把上面这些“踩坑现场”全摊开讲清楚。它不教你怎么背命令而是告诉你每个步骤背后的为什么必须这样为什么单点部署要先调vm.max_map_count为什么Kibana必须和ES版本严格对齐为什么IK的main.dic不能直接用网上下载的“万能词库”为什么集群里discovery.seed_hosts和cluster.initial_master_nodes缺一不可所有操作都基于生产环境验证过的方案参数值附带计算依据比如堆内存为什么设为物理内存的50%且不超过32GB配置项全部标注作用域是仅单点生效还是集群全局生效。适合两类人一是正准备搭搜索服务的后端/运维同学需要一份能直接抄作业、还能理解原理的指南二是已经跑着ES但总出小毛病的开发者想系统理清底层逻辑把“能用”变成“稳用”。2. 整体设计思路从单点验证到集群落地的四阶演进2.1 为什么必须按“单点ES → Kibana → IK → 集群”顺序推进这不是为了凑步骤而是由Elasticsearch自身的依赖链决定的。你可以把它想象成盖楼地基单点ES没打牢上面砌墙Kibana、装窗户IK、再加盖楼层集群全是空中楼阁。单点ES是唯一无外部依赖的起点。它只依赖JVM和Linux内核参数所有后续组件都建立在它能稳定响应HTTP 9200端口的基础上。跳过这步直接装Kibana你会看到Kibana反复报错Unable to connect to Elasticsearch at http://localhost:9200但根本原因可能是ES连启动都没成功——比如max file descriptors太低导致进程秒退而错误日志藏在logs/目录深处新手根本找不到。Kibana必须紧随单点ES之后部署。它的核心价值是提供可视化验证手段。没有Kibana你只能靠curl -X GET localhost:9200/_cat/health?v这种命令行看状态既难排查细节比如哪个index的shard是red也无法直观测试搜索效果。更重要的是Kibana自带Dev Tools控制台这是调试IK分词器最高效的工具——你不用写Java代码直接在浏览器里发_analyze请求就能实时看到分词结果。IK分词器必须在Kibana验证后再集成。原因很实际分词器本质是ES的一个插件加载失败会导致ES启动卡住或拒绝服务。如果先装IK再验证你可能面对一个“ES进程活着但9200端口无响应”的黑盒。而有了Kibana你可以在装IK前先用_cat/plugins?v确认插件列表为空装完后立刻用_cat/plugins?v看到ik条目再用Dev Tools发GET /_analyze?analyzerik_smarttext人工智能三步闭环验证是否生效。集群部署是最后一步且必须基于已验证的单点配置。集群不是简单复制单点配置。它引入了网络发现、节点角色分离、shard分配策略等新维度。如果你的单点ES连bootstrap.memory_lock: true都没配防止swap影响性能那集群里多个节点同时触发swap整个集群会雪崩式响应延迟。所以集群配置文件其实是单点配置的“增强版”而非“复制版”。提示整个流程中版本一致性是生命线。ES 8.x要求JDK 17而很多老服务器默认是OpenJDK 11Kibana 8.11.3只能连ES 8.11.x连8.10.x都会报Incompatible versionIK分词器更是精确到小版本ik 8.11.3只能用于ES 8.11.3。建议在开始前用java -version、curl -X GET localhost:9200确认基础环境再统一下载对应版本包。2.2 单点部署为何要动Linux内核参数三个关键参数详解ES不是普通Java应用它对操作系统有强定制需求。跳过这步轻则启动失败重则运行中随机崩溃。下面三个参数每个都有明确的物理意义vm.max_map_count这个值控制进程能创建的最大内存映射区域数。ES大量使用mmap来读写Lucene索引文件每个segment文件都需要独立的mmap区域。默认值65530在中小索引下够用但一旦索引分片数超过100或者单分片数据量超10GB就会触发max virtual memory areas vm.max_map_count [65530] is too low错误。计算公式max_map_count ≥ 分片总数 × 2 1000。例如你计划建5个索引每个索引5个主分片5个副本分片总分片数5×(55)50则max_map_count至少设为50×210001100。但为防未来扩容我们通常设为262144256K执行sudo sysctl -w vm.max_map_count262144并写入/etc/sysctl.conf永久生效。fs.file-max系统级最大文件句柄数。ES每个shard、每个HTTP连接、每个后台merge任务都会占用文件句柄。默认值如CentOS 7是786432看似很大但高并发场景下极易耗尽。判断依据启动ES后用lsof -p es_pid | wc -l查看当前句柄数若接近fs.file-max的80%就必须调高。生产环境建议设为6553600600万执行sudo sysctl -w fs.file-max6553600。ulimit -n单进程最大打开文件数。这是fs.file-max的子集必须大于ES配置的node.max_local_storage_nodes单机多实例时和预期并发连接数之和。ES官方文档建议至少65536。设置方法编辑/etc/security/limits.conf添加两行elasticsearch soft nofile 65536 elasticsearch hard nofile 65536注意elasticsearch是运行ES的系统用户不是root。如果用root启动需改为root。注意这三个参数修改后必须重启服务器或至少重新登录shell才能生效。很多新手改完sysctl就急着启动ES结果还是报错——因为ulimit值没刷新。验证方法启动ES前先切到elasticsearch用户执行ulimit -n和cat /proc/sys/vm/max_map_count确认数值已更新。2.3 Kibana与ES的耦合关系为什么版本错一位都不行Kibana不是独立前端它是ES的“官方客户端”深度集成ES的API语义。版本不匹配时常见错误不是简单的“连接失败”而是更隐蔽的功能降级或数据错乱。API协议变更ES 8.x废弃了_search?q这种URL查询语法全面转向_searchPOST body。Kibana 8.x的Discover界面正是基于新协议构建。如果用Kibana 8.x连ES 7.x你会发现搜索框输入关键词后毫无反应——因为Kibana发的是POST{query:{match:{title:xxx}}}而ES 7.x的旧版本API可能返回400 Bad Request但Kibana前端没做友好提示只显示空白。安全模块不兼容ES 8.x默认启用TLS和基于PKI的身份认证Kibana 8.x的elasticsearch.ssl.certificateAuthorities配置项就是为此设计。如果强行用Kibana 7.x连ES 8.x会卡在Unable to authenticate user kibana_system因为7.x的Kibana根本不认识8.x的证书链格式。UI功能缺失ES 8.x新增了_transform、_data_stream等APIKibana 8.x的Stack Management界面才有对应入口。用低版本Kibana这些功能入口直接消失你甚至不知道ES已支持该能力。实操心得下载包时务必认准官网下载页的“Version compatibility matrix”。例如ES 8.11.3的兼容矩阵明确写着“Kibana: 8.11.3”旁边小字注明“Kibana 8.11.x is compatible with Elasticsearch 8.11.x only”。别信第三方博客写的“8.10和8.11基本一样”生产环境差一个小版本可能就是三天排查时间。3. 核心环节实现手把手完成单点→集群的全流程配置3.1 单点ES部署从解压到健康检查的七步闭环以下操作均以ES 8.11.3 OpenJDK 17.0.2为例用户为elasticsearch安装路径/opt/elasticsearch。第一步创建专用用户与目录sudo groupadd elasticsearch sudo useradd -m -g elasticsearch elasticsearch sudo mkdir -p /opt/elasticsearch /var/log/elasticsearch /var/lib/elasticsearch sudo chown -R elasticsearch:elasticsearch /opt/elasticsearch /var/log/elasticsearch /var/lib/elasticsearch为什么不用rootES官方强制要求非root用户启动。root启动会直接报错ERROR: [1] bootstrap checks failed且存在严重安全隐患——ES进程若被攻破攻击者将获得root权限。第二步下载解压并校验# 切换到elasticsearch用户 sudo su - elasticsearch cd /tmp wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-8.11.3-linux-x86_64.tar.gz # 必须校验SHA512官网下载页提供校验值 sha512sum elasticsearch-8.11.3-linux-x86_64.tar.gz # 输出应与官网一致否则立即停止 tar -xzf elasticsearch-8.11.3-linux-x86_64.tar.gz -C /opt/ ln -s /opt/elasticsearch-8.11.3 /opt/elasticsearch第三步配置jvm.options关键编辑/opt/elasticsearch/config/jvm.options找到以下两行并修改-Xms4g -Xmx4g为什么是4g计算依据物理内存32GBES堆内存建议≤50%即16GB但Lucene对堆外内存off-heap有强需求堆内存超过32GB会导致指针压缩失效GC压力剧增。因此32GB物理内存的机器堆内存上限就是32GB但最优值是16GB16GB物理内存的机器最优值是4GB。此处按16GB内存服务器设定。若你的服务器内存不同请按min(物理内存×0.5, 32GB)重新计算。第四步配置elasticsearch.yml精简版# 集群名单点也必须设集群模式复用 cluster.name: my-application # 节点名单点可随意但需唯一 node.name: node-1 # 绑定地址0.0.0.0允许远程访问测试用生产环境建议127.0.0.1 network.host: 0.0.0.0 # HTTP端口9200是标准 http.port: 9200 # 传输端口9300是节点间通信端口单点也需开启 transport.port: 9300 # 启用内存锁定防止swap bootstrap.memory_lock: true # 禁用单播发现单点不需要 discovery.type: single-node # 日志路径 path.logs: /var/log/elasticsearch # 数据路径 path.data: /var/lib/elasticsearch # JVM选项中指定的堆内存大小此处必须与jvm.options一致 ES_JAVA_OPTS: -Xms4g -Xmx4g关键点discovery.type: single-node是ES 7.0单点模式的开关它自动禁用master选举避免单点启动时因无法发现其他节点而超时失败。旧版本用discovery.zen.minimum_master_nodes: 1已废弃。第五步启动并验证# 启动后台运行 /opt/elasticsearch/bin/elasticsearch -d -p /var/run/elasticsearch.pid # 检查进程 ps -u elasticsearch | grep elasticsearch # 检查端口 netstat -tuln | grep 9200 # 健康检查等待30秒让ES初始化 curl -X GET http://localhost:9200/_cat/health?v # 正常输出应包含 statusgreen, node.total1, shards.active_primary0第六步创建测试索引并插入数据# 创建名为test的索引1主1副 curl -X PUT http://localhost:9200/test -H Content-Type: application/json -d { settings: { number_of_shards: 1, number_of_replicas: 1 } } # 插入一条文档 curl -X POST http://localhost:9200/test/_doc -H Content-Type: application/json -d {title:Elasticsearch入门指南,content:本文详解ES部署要点} # 搜索验证 curl -X GET http://localhost:9200/test/_search?qtitle:入门第七步日志监控避坑重点如果第六步搜索返回空不要急着重装。先看日志tail -f /var/log/elasticsearch/my-application.log常见错误max file descriptors [4096] for elasticsearch process is too low→ 回头检查ulimit -n是否生效。max virtual memory areas vm.max_map_count [65530] is too low→ 检查sysctl配置。the default discovery settings are unsuitable for production use→ 忘了配discovery.type: single-node。3.2 Kibana部署配置文件里的五个生死攸关参数Kibana 8.11.3部署比ES更“娇气”因为它必须与ES建立双向信任。第一步下载解压# 仍用elasticsearch用户操作保持权限一致 cd /tmp wget https://artifacts.elastic.co/downloads/kibana/kibana-8.11.3-linux-x86_64.tar.gz tar -xzf kibana-8.11.3-linux-x86_64.tar.gz -C /opt/ ln -s /opt/kibana-8.11.3 /opt/kibana第二步配置kibana.yml核心参数详解# Kibana监听地址0.0.0.0允许远程访问 server.host: 0.0.0.0 # Kibana端口5601是标准 server.port: 5601 # ES地址必须与ES的network.host和http.port完全一致 elasticsearch.hosts: [http://localhost:9200] # ES用户名密码ES 8.x默认创建了kibana_system用户 elasticsearch.username: kibana_system elasticsearch.password: 自动生成的密码 # Kibana加密密钥用于session加密必须设置且长度≥32位 encryptionKey: a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6 # 安全上下文ES 8.x强制要求 xpack.security.encryptionKey: a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6生死攸关参数解析elasticsearch.passwordES 8.x首次启动时会在控制台输出一串类似Please remember to configure the kibana_system user password in Kibana configuration.的提示并生成一个随机密码。你必须复制这个密码填入此处。如果忘了可用/opt/elasticsearch/bin/elasticsearch-reset-password -u kibana_system重置。encryptionKey这是Kibana的“保险柜钥匙”。如果部署后又修改了此值所有已保存的Dashboard、Index Pattern将无法加载出现Error: Unable to fetch saved objects。生产环境务必记录此密钥。xpack.security.encryptionKeyES 8.x安全模块的加密密钥必须与encryptionKey相同否则Kibana无法解密ES返回的安全令牌。第三步启动Kibana# 后台启动 /opt/kibana/bin/kibana --allow-root # 检查日志 tail -f /opt/kibana/logs/kibana.log # 正常启动标志日志末尾出现Server running at http://0.0.0.0:5601第四步浏览器访问与首次配置打开http://服务器IP:5601首次访问会跳转到Setup向导第一步选择“Explore on my own”跳过教程。第二步进入Dev Tools执行GET /_cat/indices?v确认能看到之前创建的test索引。第三步在Management Stack Management Index Patterns中创建test索引模式将timestamp设为时间字段无则留空。实操心得如果Kibana页面一直显示“Loading...”检查kibana.log。90%的情况是elasticsearch.password填错了日志会报Unable to authenticate user kibana_system。此时不要重启Kibana直接修改kibana.yml然后执行kill $(cat /opt/kibana/kibana.pid)再重启。3.3 IK分词器安装不只是拷贝文件词典热更新才是关键IK分词器ik-analyzer是中文搜索的基石但它的安装远不止./bin/elasticsearch-plugin install一条命令。第一步下载匹配版本的IK包访问 https://github.com/medcl/elasticsearch-analysis-ik/releases 找到与ES 8.11.3对应的IK版本通常是8.11.3。注意不要下master分支源码要下Release页的.zip包。源码需要自己编译且编译环境复杂。第二步安装插件# 切换到elasticsearch用户 sudo su - elasticsearch # 进入ES目录 cd /opt/elasticsearch # 安装自动解压到plugins/ik目录 ./bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v8.11.3/elasticsearch-analysis-ik-8.11.3.zip # 重启ES kill $(cat /var/run/elasticsearch.pid) /opt/elasticsearch/bin/elasticsearch -d -p /var/run/elasticsearch.pid第三步验证分词器是否加载# 查看插件列表 curl -X GET http://localhost:9200/_cat/plugins?v # 应看到一行node-1 | ik | 8.11.3 # 测试分词 curl -X GET http://localhost:9200/_analyze -H Content-Type: application/json -d { analyzer: ik_smart, text: 中华人民共和国国歌 } # 正常返回应包含 tokens: [中华人民共和国, 国歌]第四步自定义词典与热更新核心价值IK默认词典main.dic覆盖基础词汇但业务专有名词如“Kubernetes”、“Prometheus”必须手动添加。关键是要支持不重启ES的热更新。创建自定义词典# 在ES配置目录创建custom目录 mkdir -p /opt/elasticsearch/config/analysis/ik/custom # 创建词典文件每行一个词 echo Kubernetes /opt/elasticsearch/config/analysis/ik/custom/mydict.dic echo Prometheus /opt/elasticsearch/config/analysis/ik/custom/mydict.dic修改IK配置文件/opt/elasticsearch/plugins/ik/config/IKAnalyzer.cfg.xml?xml version1.0 encodingUTF-8? !DOCTYPE properties SYSTEM http://java.sun.com/dtd/properties.dtd properties commentIK Analyzer 扩展配置/comment !-- 用户可以在这里配置自己的扩展字典 -- entry keyext_dictcustom/mydict.dic/entry !-- 用户可以在这里配置自己的扩展停止词字典 -- entry keyext_stopwords/entry !-- 热更新配置interval单位为秒 -- entry keyremote_ext_dicthttp://your-server-ip:8000/ik/custom/mydict.dic/entry entry keyremote_ext_stopwords/entry /properties热更新原理IK会每隔interval秒默认60秒去remote_ext_dictURL拉取词典文件。你只需把mydict.dic放到Web服务器如Nginx的/ik/custom/目录下修改词典后IK在60秒内自动生效无需重启ES。第五步在索引中使用IK分词器# 创建新索引指定IK分词器 curl -X PUT http://localhost:9200/test_ik -H Content-Type: application/json -d { settings: { analysis: { analyzer: { my_ik_analyzer: { type: custom, tokenizer: ik_max_word } } } }, mappings: { properties: { title: { type: text, analyzer: my_ik_analyzer, search_analyzer: ik_smart } } } } # 插入测试数据 curl -X POST http://localhost:9200/test_ik/_doc -H Content-Type: application/json -d {title:Kubernetes集群部署指南} # 搜索验证用ik_smart分词避免过度切分 curl -X GET http://localhost:9200/test_ik/_search?qtitle:Kubernetes3.4 ES集群部署三节点最小高可用架构的配置要点单点ES是学习起点但生产环境必须集群。三节点是最小高可用单元满足quorum (nodes/2)1 2既能容忍单节点故障又避免了五节点集群的资源浪费。架构设计节点1node-1master-eligible data ingest全能节点兼做协调节点节点2node-2master-eligible data数据节点不处理HTTP请求节点3node-3master-eligible纯主节点不存数据只参与选举为什么这样分主节点不存数据能避免磁盘IO影响选举速度数据节点不暴露HTTP端口减少攻击面全能节点作为入口承担路由和聚合压力。配置通用部分所有节点# /opt/elasticsearch/config/elasticsearch.yml cluster.name: my-application # 每个节点名必须唯一 node.name: node-1 # node-2节点改为node-2node-3改为node-3 # 网络绑定必须用服务器真实IP不能用localhost network.host: 192.168.1.101 # node-1的IP http.port: 9200 transport.port: 9300 # 启用内存锁定 bootstrap.memory_lock: true # 路径配置同单点 path.logs: /var/log/elasticsearch path.data: /var/lib/elasticsearch # JVM堆内存同单点4g ES_JAVA_OPTS: -Xms4g -Xmx4g节点1全能节点特有配置# 角色主节点候选 数据节点 Ingest节点 协调节点默认开启 node.roles: [master, data, ingest] # 允许HTTP访问 http.enabled: true # 发现配置告诉本节点其他节点在哪 discovery.seed_hosts: [192.168.1.101:9300, 192.168.1.102:9300, 192.168.1.103:9300] # 首次启动时哪些节点有资格成为master仅首次启动有效 cluster.initial_master_nodes: [node-1, node-2, node-3]节点2数据节点特有配置node.roles: [master, data] # 关闭HTTP不处理用户请求 http.enabled: false # 发现配置同节点1 discovery.seed_hosts: [192.168.1.101:9300, 192.168.1.102:9300, 192.168.1.103:9300] cluster.initial_master_nodes: [node-1, node-2, node-3]节点3纯主节点特有配置node.roles: [master] # 不存数据不处理请求 node.data: false http.enabled: false # 发现配置同上 discovery.seed_hosts: [192.168.1.101:9300, 192.168.1.102:9300, 192.168.1.103:9300] cluster.initial_master_nodes: [node-1, node-2, node-3]启动顺序与验证必须按顺序启动先启node-1再启node-2最后启node-3。因为cluster.initial_master_nodes只在集群首次形成时生效后续节点加入用discovery.seed_hosts。验证集群状态# 在任意节点执行 curl -X GET http://192.168.1.101:9200/_cat/nodes?v # 应看到三行roles列分别显示mdhmaster,data,ingest、mdmaster,data、mmaster curl -X GET http://192.168.1.101:9200/_cat/health?v # status应为greennode.total3shards.active_primary应≥1取决于索引分片数常见问题节点启动后_cat/nodes看不到新节点。首先检查discovery.seed_hosts中的IP是否能互相ping通其次检查防火墙sudo ufw allow 9300Ubuntu或sudo firewall-cmd --permanent --add-port9300/tcpCentOS最后检查network.host是否绑定了0.0.0.0错误必须绑定具体IP否则节点间通信走错网卡。4. 常见问题与排查技巧实录那些让你熬夜的“灵异事件”4.1 “ES启动就退出日志里什么都没有”——静默崩溃的定位法这是新手最高频的噩梦。ES进程启动后瞬间消失ps查不到logs/目录下连日志文件都没生成。原因往往在JVM层面而非ES配置。排查步骤用前台模式启动捕获JVM错误# 不要用-d后台启动 /opt/elasticsearch/bin/elasticsearch # 观察终端输出重点找 # - Could not reserve enough space for object heap → 堆内存设太大物理内存不足 # - Unsupported Java version → JDK版本不匹配ES 8.x需JDK 17 # - Permission denied → 目录权限不对如/var/lib/elasticsearch不属于elasticsearch用户检查系统日志# Ubuntu/Debian journalctl -u systemd-journald | grep -i elasticsearch # CentOS/RHEL dmesg | grep -i out of memory如果看到Out of memory: Kill process说明系统OOM Killer干掉了ES进程根源是vm.max_map_count或ulimit -n太低。验证JVM参数# 查看ES实际使用的JVM参数 ps aux | grep elasticsearch | grep -v grep # 输出中应包含 -Xms4g -Xmx4g 和 -Djava.io.tmpdir... # 如果没看到说明jvm.options没生效检查文件权限ls -l /opt/elasticsearch/config/jvm.options实操心得我曾遇到一台16GB内存服务器jvm.options设了-Xms8g -Xmx8g但ES始终启动失败。前台启动后看到Could not reserve enough space for 8388608KB object heap。原来服务器启用了swap而bootstrap.memory_lock: true要求内存必须锁定swap空间无法锁定。解决方案关闭swapsudo swapoff -a或注释掉bootstrap.memory_lock仅测试环境。4.2 “Kibana连得上ES但Dashboard一片空白”——前端资源加载失败的真相Kibana页面显示“Loading...”Network面板看到大量404请求路径类似/api/index_patterns/index_pattern/test。这不是ES问题而是Kibana的Index Pattern未正确关联索引。排查与解决确认索引是否存在curl -X GET http://localhost:9200/_cat/indices?v # 确保你要用的索引如test在列表中且statusgreen检查Index Pattern配置进入Kibana Management Stack Management Index Patterns。找到你的Index Pattern如test点击右侧“Actions” “Edit index pattern”。检查“Time field”是否误设为不存在的字段如设了timestamp但文档里没有该字段。如果索引无时间字段此处留空。点击“Refresh field list”强制Kibana重新扫描索引mapping。清除浏览器缓存 Kibana的UI状态如当前选中的Index Pattern存在localStorage中。如果之前配置错误即使修正了Index Pattern页面仍可能加载旧状态。快捷键CtrlShiftR硬刷新或在DevTools的Application Storage Local Storage中删除http://kibana-url下的所有条目。注意Kibana 8.x的Index Pattern名称必须与ES索引名完全一致支持通配符如log-*不能有大小写差异。ES索引名Test和Kibana中test会被视为不同Pattern。4.3 “IK分词器装了但搜索还是搜不到中文”——分词器与搜索分析器的错配现象用_analyzeAPI测试ik_smart能正确切分“人工智能”但用GET /test/_search?qtitle:人工智能却搜不到结果。根源在于索引时用的分词器和搜索时用的分词器不一致。**原理与

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑