ElasticSearch
概述
Lucene
Lucene 是 Apache 下的一个项目,是一个开源的全文检索引擎工具包。
Lucene 是一个全文检索引擎的架构,提供完整的查询引擎和索引引擎。
Libana
Kibana 是一种数据可视化和挖掘工具,可以用于日志和时间序列分析、应用程序监控和运营智能使用案例。
Kibana 提供了强大且易用的功能,例如直方图、线形图、饼图、热图和内置的地理空间支持。
ElasticSearch 简称 es,是一个开源的高扩展到分布式全文检索引擎
ELK
ELK:ElasticSearch、Logstash、Kibana
-
ElasticSearch:基于 Lucene 的分布式搜索框架
-
Logstash:中央数据流引擎,从不同地方收集不同的格式数据过滤输出到不同的目的地
-
Kibana:数据展示框架
数据的收集及清洗 -> 数据分析,存储(ES) -> 数据展示(Kibana)
ES 核心
ElasticSearch 是面向文档的
- 索引
- 映射类型的容器
- 类型(7版本淘汰,8版本弃用)mapping
- 不加上类型也可以自动匹配
- 文档 documents
- 索引和搜索数据的最小单位是文档
- 分片
- 在本质上,一个分片就是一个 Lucene 索引,也是一个包含倒排索引的文件目录
安装
安装 ES
- 官网上下载对应系统下你想选择使用的版本的压缩包
- 解压缩
- 打开 bat 脚本文件(默认端口号9200)
可视化界面安装 – ES head
- 从 GitHub 下载
- 跨域设置(elasticsearch.yaml)
- 访问可视化页面(默认端口号9100)
注意:ES 要求索引名都必须是小写,在 head 中使用大写无法成功但无提示!!
安装 Kibana
注意:与 RabbitMQ 一直,Kibana 版本需要与 ES 版本一致
- 从官网下载与 ES 版本一致的压缩包
- 解压使用
- 打开 bat 脚本文件(默认端口号5601)
另:
需要汉化的可以在 config
文件夹下修改 kibana.yml
文件中的配置
IK 分词器(插件)
概要
将一段语句划分成多个关键词,在检索时将数据库或索引中的数据进行分词并匹配的插件。(中文)
IK 分词器的两种分词算法:
- ik_smart:最少划分
- ik_max_word:最细粒度划分
安装
-
从 GitHub 下载 zip 文件(注意:此处下载下来不应该是源码,使用我提供的链接寻找需要的版本下载即可)源码
-
解压缩放入 ES 中的 plugins 文件夹中的 ik 文件夹
-
使用
elasticsearch-plugin list
命令查看 loaded 的插件(bin目录下)
配置自己的分词可以在 config
文件夹中增加自己的 .dic
文件并配置 IKAnalyzer.cfg.xml
基本操作
Rest 风格
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": "<p class='key' style='color:red'>", "post_tags": "</p>", "fields": { "name": {} } } }
-
SpringBoot集成
需要
- 准备 ElasticSearch
- 准备 idea
使用 SpringBoot 集成 ES 时,根据官方文档进行连接及相关操作,SpringBoot 版本需要与 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 仓库