Elasticsearch 9.x 本地部署实操手册:趣闻生成器搭建
【梗科普】Chuck Norris 是美国知名硬汉动作演员,国外互联网有大量关于他的夸张无厘头幽默趣闻(类似"Chuck Norris 能让圆规画出正方形"),本教程就是用电影剧情为素材,让AI生成这种风格的内容,也可以随时改成任何你想要的生成风格。
一、懂核心逻辑
整个项目本质是用ES自带的能力,一行查询搞定「搜数据→拼提示词→AI生成」全流程,不用写复杂的Python/Java代码,全程在Elasticsearch里完成。
4个核心组件的作用,一句话讲透:
| 组件 | 通俗作用 | 核心价值 |
|---|---|---|
| Elasticsearch 9.3+ | 本地「电影数据库+搜索引擎」,存电影信息,秒级找到你想要的电影剧情 | 不用单独搭数据库,自带全文检索,找数据又快又准 |
| ES | QL | ES自带的「流水线式查询语言」,像搭积木一样串起所有步骤 |
| COMPLETION命令 | ES | QL里专门对接大模型的「AI一键调用开关」 |
| Ollama+本地开源大模型 | 在你电脑上跑的免费AI,不用连外网、不用花钱 | 数据全在本地,安全可控,适配内网/离线环境,彻底替代OpenAI |
二、前置准备
硬件要求
-
系统:Windows/Mac/Linux 全支持
-
内存:最低8G(推荐16G及以上,同时跑ES+大模型更流畅)
-
硬盘:至少20G空闲空间
必须安装的软件
| 软件 | 版本要求 | 安装方式 |
|---|---|---|
| Elasticsearch | 必须9.3.0及以上(COMPLETION命令是9.3新增的功能) | 官网下载对应系统安装包,一键安装 |
| Kibana | 必须和Elasticsearch版本完全一致 | 官网下载对应系统安装包,一键安装 |
| Ollama | 1.30.0及以上(原生支持OpenAI兼容接口,不用写代理代码) | 官网ollama.com一键安装 |
三、第一步:环境搭建(一步一验证,确保全流程不卡壳)
3.1 先搞定本地大模型(最简单,先把AI跑通)
操作步骤
-
安装完Ollama后,打开电脑的终端(Windows用CMD/PowerShell,Mac/Linux用终端)
-
执行命令拉取开源大模型(推荐2个,新手选第一个):
Bash# 推荐:通义千问2 7B,中文效果好,占用内存低,16G内存轻松跑 ollama pull qwen2:7b-instruct # 备选:Llama3 8B,英文效果好,通用型强 ollama pull llama3 -
验证模型是否可用:终端执行
ollama run qwen2:7b-instruct,输入你好,能正常回复说明模型跑通了,输入/exit退出。
原理说明
Ollama帮你搞定了大模型的环境配置、量化优化,一键就能跑开源大模型,而且自带和OpenAI完全兼容的API接口,ES可以直接对接,不用写任何额外的代理代码。
3.2 配置并启动Elasticsearch
操作步骤
-
找到ES的配置文件:
-
Windows:安装目录下的
config/elasticsearch.yml -
Mac/Linux:安装目录下的
config/elasticsearch.yml
-
-
把下面的配置直接复制粘贴到文件里,覆盖原有内容(本地测试专用,生产环境需调整安全配置):
YAML# 核心必开配置:开启ES|QL和推理服务,否则用不了AI功能 xpack.esql.enabled: true xpack.inference.enabled: true # 本地测试关闭安全验证,新手不用管账号密码,生产环境必须开启 xpack.security.enabled: false xpack.security.enrollment.enabled: false xpack.security.http.ssl.enabled: false xpack.security.transport.ssl.enabled: false # 绑定本地地址,端口固定9200 network.host: 0.0.0.0 http.port: 9200 # 允许自动创建索引,导数据不用手动建表 action.auto_create_index: true -
启动ES:
-
Windows:双击安装目录下的
bin/elasticsearch.bat -
Mac/Linux:终端执行
安装目录/bin/elasticsearch
-
-
验证ES是否启动成功:打开浏览器,访问
http://localhost:9200,能看到一串带ES版本号的JSON内容,说明启动成功。
关键原理说明
-
xpack.esql.enabled:开启ES|QL查询语言,不开启就用不了管道式查询 -
xpack.inference.enabled:开启ES的推理服务,不开启就对接不了大模型 -
本地测试关闭安全配置,是为了避免新手被账号密码、SSL证书卡住,生产环境必须开启安全验证。
3.3 配置并启动Kibana(可视化操作,新手友好)
操作步骤
-
找到Kibana的配置文件:
config/kibana.yml -
把下面的配置直接复制粘贴进去,覆盖原有内容:
YAML# 对接本地启动的ES,地址和上面ES的配置完全对应 elasticsearch.hosts: ["http://localhost:9200"] # 绑定本地地址,端口固定5601 server.host: 0.0.0.0 server.port: 5601 -
启动Kibana:
-
Windows:双击安装目录下的
bin/kibana.bat -
Mac/Linux:终端执行
安装目录/bin/kibana
-
-
验证Kibana是否启动成功:打开浏览器,访问
http://localhost:5601,能正常打开Kibana界面,说明对接成功。
核心用途
后面所有的查询、数据导入、调试,都在Kibana的「开发工具(Dev Tools)」里完成,不用记命令行,点点点就能操作。
四、第二步:导入电影测试数据
原教程只提了Kaggle数据集,这里给你2种方案,新手选第一种,不用下载任何文件,直接复制运行。
方案1:零门槛快速导入(推荐新手,10秒搞定)
直接打开Kibana → 左侧菜单找到「开发工具(Dev Tools)」→ 进入控制台,把下面的代码粘贴进去,点击右上角的运行按钮,就能自动创建movies索引,导入4条测试电影数据。
JSON
POST _bulk
{"index": {"_index": "movies"}}
{"title": "第一滴血3", "overview": "战争让兰博身心俱疲,他终于在修道院找到了内心的平静。当好友兼导师特劳特曼上校请求他协助阿富汗的绝密任务时,兰博拒绝了,但当特劳特曼被俘后,他不得不重新考虑。"}
{"index": {"_index": "movies"}}
{"title": "泰坦尼克号", "overview": "富家少女罗丝与穷困画家杰克在豪华游轮泰坦尼克号上相遇相爱,然而游轮撞上冰山沉没,杰克把生存的机会让给了罗丝,自己葬身海底。"}
{"index": {"_index": "movies"}}
{"title": "肖申克的救赎", "overview": "青年银行家安迪被误判谋杀妻子及其情人,被判终身监禁,他在肖申克监狱里用二十年时间,靠一把小锤子挖通隧道,成功越狱,重获自由。"}
{"index": {"_index": "movies"}}
{"title": "复仇者联盟4:终局之战", "overview": "灭霸打了响指消灭了宇宙一半的生命后,复仇者们穿越时空收集无限宝石,逆转了灭霸的恶行,最终钢铁侠牺牲自己,打响响指消灭了灭霸大军。"}
验证是否导入成功
在控制台运行下面的代码,能返回刚才导入的4条数据,说明导入成功:
JSON
GET movies/_search
{
"query": {"match_all": {}}
}
方案2:导入完整电影数据集(适合想批量测试的用户)
-
下载TMDB 5000部电影数据集:点击下载(国内可访问,不用注册)
-
打开Kibana → 「机器学习(Machine Learning)」→ 「数据可视化工具(Data Visualizer)」→ 「上传文件(Upload file)」
-
选择下载好的CSV文件,等待解析完成,点击「导入(Import)」
-
索引名称填
movies,点击「导入」,等待完成即可。
五、第三步:创建ES本地大模型推理端点(核心对接步骤,直接复制运行)
这一步是让ES能找到你本地跑的大模型,相当于给ES存一个「AI调用地址簿」,创建一次,永久使用。
操作步骤
还是在Kibana的开发工具控制台,粘贴下面的代码,点击运行:
JSON
PUT _inference/completion/my-local-ollama
{
"service": "openai",
"service_settings": {
"api_key": "ollama", // 随便填,Ollama不需要API密钥
"model_id": "qwen2:7b-instruct", // 这里必须和你用ollama pull拉的模型名完全一致
"url": "http://localhost:11434/v1" // Ollama的本地API地址
}
}
【踩坑提示】如果你的ES是用Docker安装的,把上面的url改成http://host.docker.internal:11434/v1(Windows/Mac),Linux改成http://172.17.0.1:11434/v1,否则Docker里的ES访问不到宿主机的Ollama。
验证是否创建成功
运行下面的代码,能返回你刚才创建的端点配置,没有报错,说明对接成功:
JSON
GET _inference/completion/my-local-ollama
原理说明
-
_inference是ES的推理端点API,专门用来管理各种AI模型的对接配置 -
这里用
openai服务类型,是因为Ollama的API完全兼容OpenAI的格式,不用额外开发,ES直接就能用 -
后面的ES|QL查询里,直接用这个端点的名字
my-local-ollama,就能调用本地大模型
六、第四步:核心ES|QL查询实操(完整可复制+逐行原理解释)
6.1 完整可直接运行的查询代码
还是在Kibana开发工具控制台,粘贴下面的代码,点击运行,就能直接生成结果!
JSON
POST _query
{
"query": """
// 第1步:指定数据来源,同时拿到检索相关性评分
FROM movies METADATA _score
// 第2步:全文检索,找到标题或剧情匹配你搜索内容的电影
| WHERE MATCH(title, ?query) OR MATCH(overview, ?query)
// 第3步:按匹配度从高到低排序,最准的排最前面
| SORT _score DESC
// 第4步:只取最匹配的1条,给AI最精准的素材
| LIMIT 1
// 第5步:拼接给AI的完整提示词
| EVAL prompt = CONCAT(?instruction, overview)
// 第6步:调用本地大模型,生成趣闻内容
| COMPLETION chuck_norris_fact = prompt WITH { "inference_id": "my-local-ollama" }
// 第7步:只保留需要的字段,让结果干净整洁
| KEEP title, overview, chuck_norris_fact
""",
"params": [
{ "instruction": "根据以下电影描述,生成一条幽默夸张的Chuck Norris趣闻:\n" },
{ "query": "第一滴血3" }
]
}
6.2 逐行拆解:
| 代码行 | 做了什么? | 核心原理 | 你可以改什么? |
|---|---|---|---|
FROM movies METADATA _score |
从movies索引(相当于数据库的表)里取数据,同时把ES的「相关性评分」带出来 |
ES全文检索会给每个匹配的结果打分,分数越高越匹配,ES | QL默认不返回这个分数,必须用METADATA _score显式声明,后面才能用它排序 |
| ` | WHERE MATCH(title, ?query) OR MATCH(overview, ?query)` | 筛选出「标题」或「剧情」里,包含你搜索关键词的电影 | MATCH()是ES的全文检索函数,比普通的LIKE模糊匹配强100倍:它会自动分词,比如你搜"第一滴血",哪怕标题是"第一滴血3"也能匹配到;?query是参数占位符,对应下面params里的内容,不用改查询逻辑,就能换搜索内容 |
| ` | SORT _score DESC` | 把匹配到的结果,按相关性从高到低排序 | 确保最匹配你搜索内容的电影排在最前面,后面取第一条的时候,拿到的就是最准的素材 |
| ` | LIMIT 1` | 只取排序后的第1条结果,也就是最匹配的那部电影 | 大模型的提示词不是越长越好,只给最精准的1条素材,AI生成的内容更贴合,不会混乱,同时减少计算量,速度更快 |
| ` | EVAL prompt = CONCAT(?instruction, overview)` | 创建一个叫prompt的新字段,把「AI生成指令」和「电影剧情」拼接成完整的提示词 |
EVAL是ES |
| ` | COMPLETION chuck_norris_fact = prompt WITH { "inference_id": "my-local-ollama" }` | 核心AI生成步骤:把拼好的提示词发给本地大模型,生成的内容存到chuck_norris_fact字段里 |
COMPLETION是ES 9.3+新增的ES |
| ` | KEEP title, overview, chuck_norris_fact` | 只保留「电影名」「电影剧情」「AI生成内容」3个字段,去掉没用的内容 | ES默认会返回索引里的所有字段,用KEEP只留需要的,结果更干净,也减少数据传输量 |
6.3 参数修改说明(一键换效果)
下面的params是整个查询的「自定义开关」,不用动上面的查询逻辑,只改这里就能换效果:
-
instruction:给AI的生成指令,想换风格直接改这里,比如:-
生成古诗:
"根据以下电影剧情,写一首七言绝句:\n" -
生成抖音文案:
"根据以下电影剧情,写一条30字以内的抖音爆款推广文案:\n" -
生成职场段子:
"根据以下电影剧情,生成一条职场摸鱼段子:\n"
-
-
query:你要搜的电影名,比如改成"泰坦尼克号"、"肖申克的救赎",就能生成对应内容。
七、结果解读+示例展示
正常返回结果示例
JSON
{
"took": 2350, // 整个查询+AI生成的总耗时,单位毫秒
"is_partial": false, // 是否是部分结果,false就是完整结果
"documents_found": 1, // 找到的匹配电影数量
"values_loaded": 2, // 加载的字段数量
"columns": [ // 返回的字段名和类型
{ "name": "title", "type": "text" },
{ "name": "overview", "type": "text" },
{ "name": "chuck_norris_fact", "type": "keyword" }
],
"values": [ // 最终结果
"第一滴血3",
"战争让兰博身心俱疲,他终于在修道院找到了内心的平静。当好友兼导师特劳特曼上校请求他协助阿富汗的绝密任务时,兰博拒绝了,但当特劳特曼被俘后,他不得不重新考虑。",
"Chuck Norris曾去修道院寻找内心平静,五分钟就离开了,因为僧侣们根本承受不住他的觉悟等级。当Chuck听说兰博在阿富汗需要帮助时,他在兰博系完头巾之前,就救出了特劳特曼、打赢了战争,还训练了一只山羊开直升机。"
]
}
八、踩坑排查指南
| 报错/问题现象 | 核心原因 | 一步一步解决方法 |
|---|---|---|
报错:inference endpoint [my-local-ollama] not found |
① 端点名字写错;② 端点没创建成功;③ ES版本低于9.3.0 | 1. 运行GET _inference,确认有这个端点,名字完全一致;2. 运行GET /,确认ES版本≥9.3.0;3. 重新运行创建端点的代码,看有没有报错 |
报错:连接Ollama失败,connection refused |
① Ollama没启动;② ES是Docker装的,用localhost访问不到宿主机;③ 端口被占用 | 1. 浏览器访问http://localhost:11434,能打开说明Ollama启动了;2. Docker装的ES,把url改成http://host.docker.internal:11434/v1;3. 确认Ollama端口是11434,没有被其他软件占用 |
| ES | QL报错:[COMPLETION] 命令不支持 |
① ES版本低于9.3.0;② ES |
| 查询能运行,但AI生成的内容是空的 | ① Ollama里没有你写的模型;② 模型没启动;③ 提示词格式有问题 | 1. 运行ollama list,确认有你写的模型名,没有就重新pull;2. 运行ollama run 模型名,测试模型能不能正常回复;3. 把instruction改成最简单的"用一句话总结下面的内容:\n",重新测试 |
| 检索不到想要的电影 | ① 索引名写错;② 数据没导入成功;③ 检索字段不对 | 1. 运行GET movies/_search,确认数据已经导入;2. 检查MATCH()里的字段名,和索引里的字段名完全一致 |
九、进阶优化玩法
-
本地模型轻量化优化 :如果你的电脑内存只有8G,换成
ollama pull gemma2:2b,20亿参数的小模型,速度更快,占用内存极低,日常生成完全够用。 -
批量生成内容 :把
LIMIT 1改成LIMIT 10,一次给10部电影生成内容,不用循环调用,ES自动批量处理。 -
检索精度优化 :给
movies索引设置专门的中文分词器(IK分词器),中文检索更精准,不会出现搜"复仇者联盟"匹配不到的情况。 -
RAG进阶增强:给电影剧情生成向量嵌入,用「全文检索+向量检索」混合模式,找到更贴合语义的素材,生成效果更好。