Lucene 是 Apache 下的一个项目,是一个开源的全文检索引擎工具包。
Lucene 是一个全文检索引擎的架构,提供完整的查询引擎和索引引擎。
Kibana 是一种数据可视化和挖掘工具,可以用于日志和时间序列分析、应用程序监控和运营智能使用案例。
Kibana 提供了强大且易用的功能,例如直方图、线形图、饼图、热图和内置的地理空间支持。
ElasticSearch 简称 es,是一个开源的高扩展到分布式全文检索引擎
ELK:ElasticSearch、Logstash、Kibana
ElasticSearch:基于 Lucene 的分布式搜索框架
Logstash:中央数据流引擎,从不同地方收集不同的格式数据过滤输出到不同的目的地
Kibana:数据展示框架
数据的收集及清洗 -> 数据分析,存储(ES) -> 数据展示(Kibana)
ElasticSearch 是面向文档的
注意:ES 要求索引名都必须是小写,在 head 中使用大写无法成功但无提示!!
注意:与 RabbitMQ 一直,Kibana 版本需要与 ES 版本一致
另:
需要汉化的可以在 config
文件夹下修改 kibana.yml
文件中的配置
将一段语句划分成多个关键词,在检索时将数据库或索引中的数据进行分词并匹配的插件。(中文)
IK 分词器的两种分词算法:
从 GitHub 下载 zip 文件(注意:此处下载下来不应该是源码,使用我提供的链接寻找需要的版本下载即可)源码
解压缩放入 ES 中的 plugins 文件夹中的 ik 文件夹
使用 elasticsearch-plugin list
命令查看 loaded 的插件(bin目录下)
配置自己的分词可以在 config
文件夹中增加自己的 .dic
文件并配置 IKAnalyzer.cfg.xml
method | url | comment |
---|---|---|
PUT | xxxx:port/index/type/document_id | create document(指定id) |
POST | xxxx:port/index/type | create document(随机id) |
POST | xxxx:port/index/type/document_id/_update | update document |
DELETE | xxxx:port/index/type/document_id | delete document |
GET | xxxx:port/index/type/document_id | get document by id |
POST | xxxx:port/index/type/document_id/_search | search data |
索引操作和文档操作的命令在 Kibana 中的 Dev Tools 中进行
创建索引
# PUT /索引名/[:类型名]/文档id
PUT /test-01/type-01/01
# 请求体
{
"name": "xiaoming",
"age": "3"
}
创建索引规则(mapping 映射)
PUT /test-02
{
"mappings": {
"properties": {
"name": {
"type": "text"
},
"age": {
"type": "long"
},
"birthday": {
"type": "date"
}
}
}
}
创建索引及 document(不指定 type,默认_doc)
PUT /test-03/_doc/01
{
"name": "xiaoming",
"age": 3,
"birthday": "xxxx-xx-xx"
}
查看某个索引具体信息
GET test-02
查看 ES 索引情况
GET _cat/
修改 document
直接覆盖,使用原 REST 语句(_version 会更新)(PUT)
PUT /test-03/_doc/01
{
"name": "xiaoyang",
"age": 3,
"birthday": "xxxx-xx-xx"
}
使用修改 document 的 REST(POST)
# POST /{index}/_update/{id}
POST /test-03/_update/01
{
"name": "Test-user",
"age": 3,
"birthday": "xxxx-xx-xx"
}
删除索引
# DELETE {index}/{id}
DELETE test-01
创建文档
# PUT /index/[:type]/id
PUT /test-study/_doc/01
查询文档
# GET /index/[:type]/id
GET /test-study/01
更新文档
直接覆盖,使用原 REST 语句(_version 会更新)(PUT)
PUT /test-03/_doc/01
{
"name": "xiaoyang",
"age": 3,
"birthday": "xxxx-xx-xx"
}
使用修改 document 的 REST(POST)
# POST /{index}/_update/{id}
POST /test-03/_update/01
{
"name": "Test-user",
"age": 3,
"birthday": "xxxx-xx-xx"
}
#
POST /test-03/_update/01
{
"doc": {
"name": "Test-user"
}
}
查询操作(条件查询)
text
:数据类型,会通过分词器进行分词
keyword
:数据类型,不会进行分词
match
:模糊查询
term
:精确匹配查询
简单条件查询
# GET /index/_search?q=查询条件(key:value)
GET /test-03/_search?q=name:Test-user
复杂条件查询
GET /index/_search
{
"query":{
"match": {
"key": "value"
}
},
# 结果过滤,类比数据库查询中 指定返回字段的语句
"_source": ["key-01", "key-02"],
# 排序,
"sort": [
{
"age": {
# desc: 降序 asc:升序
"order": "asc"
}
}
],
# 分页查询 from:从第几页开始,size:返回多少个文档
"from": 0,
"size": 1,
}
布尔查询
# and 查询
GET /index/_search
{
"query":{
"bool": {
"must": [
"match": {
"key": "value"
},
"match": {
"key": "value"
}
]
}
}
}
# or 查询
GET /index/_search
{
"query":{
"bool": {
"should": [
"match": {
"key": "value"
},
"match": {
"key": "value"
}
]
}
}
}
# not 查询
should -> must_not
# filter 过滤查询
"filter": [
{
"range": {
"age": {
"gt": 33
}
}
}
]
# 匹配查询 match会使用分词器进行查询(对文档进行分析分词后,再进行查询)
"match":{
"tags": "xx xx"
}
# 精确查询 term 倒排索引
"query": {
"term": {
"key": "value"
}
}
# 高亮查询
GET /index/type/_search
{
"query": {
"match": {
"name": "xxx"
}
},
#
"highlight": {
"fields": {
"name": {}
}
}
# 自定义高亮
"highlight": {
"pre_tags": ""
,
"post_tags": "",
"fields": {
"name": {}
}
}
}
使用 SpringBoot 集成 ES 时,根据官方文档进行连接及相关操作,SpringBoot 版本需要与 ES 版本对应,否则会报错!
Java 集成 ES 官方文档
创建索引
// 官方文档Demo
// Create the low-level client
RestClient restClient = RestClient.builder(
new HttpHost("localhost", 9200)).build();
// Create the transport with a Jackson mapper
ElasticsearchTransport transport = new RestClientTransport(
restClient, new JacksonJsonpMapper());
// And create the API client
ElasticsearchClient client = new ElasticsearchClient(transport);
// Create the "products" index
client.indices().create(c -> c.index("products"));
索引存在与否
BooleanResponse response = elasticsearchClient.indices().exists(c -> c.index("products"));
System.out.println(response.value());
删除索引
DeleteIndexResponse response = elasticsearchClient.indices().delete(c -> c.index("products"));
System.out.println(response);
添加文档
单条数据添加(若文档不存在会创建)
// 创建对象
User user1 = new User("xiaoming_001", 20);
User user2 = new User("xiaoming_002", 23);
User user3 = new User("xiaoming_003", 24);
// 1.方式一
// i indexRequest.Builder
IndexResponse response = elasticsearchClient.index(i -> i
// 索引名称
.index("user_index")
// 设置document id
.id("2")
.document(user1)
);
System.out.println(response.version());
// 2.方式二
IndexRequest<User> request = IndexRequest.of(i -> i
.index("user_index")
.id("3")
.document(user2)
);
IndexResponse indexResponse = elasticsearchClient.index(request);
System.out.println(indexResponse);
// 3.方式三
IndexRequest.Builder<User> userBuilder = new IndexRequest.Builder<>();
userBuilder.index("user_index")
.id("4")
.timeout(Time.of(t -> t.time("1s")))
.document(user3);
IndexResponse resp = elasticsearchClient.index(userBuilder.build());
System.out.println(resp);
多条数据添加
BulkRequest.Builder brBuilder = new BulkRequest.Builder();
List<User> userList = new ArrayList<>();
userList.add(new User("xiaoming_001", 1));
userList.add(new User("xiaoming_002", 2));
userList.add(new User("xiaoming_003", 3));
userList.add(new User("xiaoming_004", 4));
userList.add(new User("Lihua_001", 5));
userList.add(new User("Lihua_002", 15));
userList.add(new User("Lihua_003", 25));
for (int i = 0; i < userList.size(); i++) {
int finalI = i;
brBuilder.operations(op -> op
.index(idx -> idx
.index("idea_levin_index")
.document(userList.get(finalI)
)
)
);
}
文档查询
// 通过id查询
public void testSearchDocumentById() throws IOException {
// 第一个参数为request请求 第二个参数为json映射成的类
GetResponse<User> resp = elasticsearchClient.get(g -> g
.index("idea_levin_index")
.id("2"),
User.class);
if (resp.found()) {
User user = resp.source();
assert user != null;
System.out.println("User: "+user.toString());
}
}
// 条件查询查询多条文档
public void testSearchDocuments() throws IOException {
SearchResponse<User> resp = elasticsearchClient.search(s -> s
// 搜索的索引名称
.index("idea_levin_index")
// 搜索请求的查询部分
.query(q -> q
// 选择查询体,此处选择匹配查询(全文搜索)
.match(t -> t
// 配置匹配查询,字段中搜索一个词
.field("name")
.query("xxx")
)
),
// 匹配文档的目标类
User.class);
List<Hit<User>> hits = resp.hits().hits();
System.out.println(hits);
TotalHits total = resp.hits().total();
assert total != null;
System.out.println(total.value());
}
// 搜索体查询
void TestSearchQueries() throws IOException {
// 构建搜索体
// MatchQuery by name
Query queryByName = MatchQuery.of(m -> m
.field("name")
.query("Levin")
)._toQuery();
// RangeQuery by age
Query qeuryByAge = RangeQuery.of(m -> m
.field("age")
.gte(JsonData.of(3))
)._toQuery();
// search the index
SearchResponse<User> resp = elasticsearchClient.search(s -> s
.index("idea_levin_index")
.query(q -> q
.bool(b -> b
.must(queryByName)
.must(qeuryByAge)
)
),
User.class
);
List<Hit<User>> hits = resp.hits().hits();
System.out.println(hits);
assert resp.hits().total() != null;
System.out.println(resp.hits().total().value());
}
此实战使用的Demo来自狂神的讲解,感谢狂神!
代码存放于我的 gitee 仓库