本文基于 Elasticsearch 8.x,总结了一套从基础操作到进阶查询、再到中文分词优化的完整实践流程,适合初学者快速上手。
一、Elasticsearch 基础概念
在传统数据库(如 MySQL)中,我们有:
| MySQL | Elasticsearch |
|---|---|
| database | 没有 |
| table | index |
| row | document |
| column | field |
ES 没有数据库概念,直接就是 index(索引)
二、基础操作(CRUD)
1. 查看所有索引
bash
GET _cat/indices
2. 插入数据
(1)指定 ID(PUT)
bash
PUT account/_doc/1
{
"name":"lele",
"balance":10000,
"address":[
"bj1",
"sh"
]
}
(2)自动生成 ID(POST)
bash
POST account/_doc
{
"name":"lele1",
"balance":9999,
"address":[
"bj",
"sh"
]
}
(3)必须不存在才创建
bash
POST account/_create/1
如果 ID 已存在 → 报错
3. 查询数据
根据 ID 查询
bash
GET account/_doc/1
只返回数据源
bash
GET account/_source/1
查看 index 信息
bash
GET account
4. 更新数据
bash
POST account/_update/1
{
"doc": {
"name":"lele1",
"balance":9999
}
}
特点:
- 返回
_version、_seq_no - 没变化 → 不更新
5. 删除
bash
DELETE account/_doc/xxx
删除 index:
bash
DELETE user
三、搜索查询(核心)
1. 简单查询(URL)
bash
GET _search?q=lele
全局搜索
bash
GET account/_search?q=lele
指定 index
2. DSL 查询(推荐)
查询全部
bash
GET account/_search
{
"query": {
"match_all": {}
}
}
3. 分页查询
bash
GET user/_search
{
"query": {
"match": {
"address": "street"
}
},
"size": 10,
"from": 0
}
类似 SQL:
sql
LIMIT 10 OFFSET 0
四、常见查询类型
1. match(模糊查询)
bash
GET user/_search
{
"query": {
"match": {
"address": "street"
}
}
}
2. match_phrase(短语匹配)
bash
GET user/_search
{
"query": {
"match_phrase": {
"address": "Madison Street"
}
}
}
必须连续匹配
3. multi_match(多字段)
bash
GET user/_search
{
"query": {
"multi_match": {
"query": "Bond",
"fields": ["address","firstname"]
}
}
}
可加权:
json
"fields": ["address^2","firstname"]
4. query_string
bash
GET user/_search
{
"query": {
"query_string": {
"query": "Madison AND Street"
}
}
}
五、Term 级查询(精准查询)
不分词!!!
1. term 查询
bash
GET user/_search
{
"query": {
"term": {
"address": "street"
}
}
}
2. range 查询
bash
GET user/_search
{
"query": {
"range": {
"age": {
"gte": 10,
"lte": 20
}
}
}
}
3. exists 查询
bash
GET user/_search
{
"query": {
"exists": {
"field": "school"
}
}
}
4. fuzzy 查询
bash
GET user/_search
{
"query": {
"fuzzy": {
"address": "streat"
}
}
}
拼写错误也能查到
六、复合查询(bool)
bash
GET user/_search
{
"query": {
"bool": {
"must": [
{ "term": { "state": "tn" }},
{ "range": { "age": { "gte": 20,"lte": 30 }}}
],
"must_not": [
{ "term": { "gender": "f" }}
],
"should": [
{ "match": { "firstname": "Hattie" }}
],
"filter": [
{ "range": { "age": { "gte": 25,"lte": 30 }}}
]
}
}
}
解释:
| 字段 | 作用 |
|---|---|
| must | 必须匹配(参与评分) |
| should | 加分项 |
| must_not | 排除 |
| filter | 过滤(不参与评分,性能更好) |
七、批量操作
1. bulk 操作
bash
POST _bulk
{"index":{"_index":"account","_id":2 }}
{"name":"lele"}
{"index":{"_index":"user","_id":1 }}
{"name":"user_lele"}
{"delete":{"_index":"user","_id":1 }}
特点:
- 一行 metadata,一行数据
- delete 只需一行
2. 批量查询
bash
GET /_mget
{
"docs":[
{
"_index":"account",
"_id":"1"
},
{
"_index":"user",
"_id":"1"
}
]
}
八、倒排索引(核心原理)
ES 的底层核心:倒排索引(Inverted Index)
举例
文档:
Doc1: 我爱上海
Doc2: 上海金融很好
倒排索引:
| 词 | 文档 |
|---|---|
| 我 | Doc1 |
| 爱 | Doc1 |
| 上海 | Doc1, Doc2 |
| 金融 | Doc2 |
查询"上海"时:
直接定位 Doc1、Doc2,而不是扫描全文
优点:
- 查询极快
- 支持全文检索
九、Mapping(字段映射)
常见类型
| 类型 | 说明 |
|---|---|
| text | 会分词 |
| keyword | 不分词 |
示例
bash
PUT user
{
"mappings": {
"properties": {
"name": {
"type": "text"
},
"status": {
"type": "keyword"
}
}
}
}
区别:
- text → 用于全文搜索
- keyword → 用于精确匹配 / 聚合
十、Analyzer(分词器)
示例
bash
GET _analyze
{
"text":"中华牙膏",
"analyzer":"standard"
}
默认分词器对中文支持很差
十一、为什么中文分词难?
原因:
-
中文没有空格
-
存在歧义:
- "研究生命起源"
- 切分不同 → 结果不同
十二、IK 中文分词器
两种模式
1. ik_max_word(最细粒度)
bash
GET _analyze
{
"text":"中华牙膏",
"analyzer":"ik_max_word"
}
2. ik_smart(智能)
bash
GET _analyze
{
"text":"中华牙膏",
"analyzer":"ik_smart"
}
十三、自定义词库
示例测试
bash
GET _analyze
{
"text":"慕课网的课程资源非常丰富",
"analyzer":"ik_max_word"
}
如果"慕课网"被拆开 → 说明词库没生效
手机型号测试
bash
GET _analyze
{
"text":"我的手机是mate40",
"analyzer":"ik_max_word"
}
如果被拆 → 加入 custom.dic
自定义词库示例
mate40
慕课网
王乐乐
生效方式
必须重启 ES 或 reload
bash
POST _plugins/_ik/reload
十四、数据导入说明
这里有上千条的user表测试数据,可以自行导入使用:account.json