ElasticSearch 简介
简介
Elasticsearch 是基于 java 开发的一个开源分布式搜索引擎,它的特点有:分布式,零配置,自动发现,索引自动分片,索引副本机制,restful 风格接口,多数据源,自动搜索负载等。
手动安装
下载 Elasticsearch,ES 启动会占用 9200(http) 和 9300(集群通信) 端口。ES 会占用大量内存,可在配置文件
jvm.options中修改 Java 虚拟机参数。下载 Kibana,它是一款开源的数据分析和可视化平台,设计用于和 ES 协作,需要在配置中指定 ES 的地址(默认
http://localhost:9200),它启动会占用 5601 端口。提示
第一次访问 Kibana 时,可能会要求输入 ES Token,账号和密码,可用如下指令获取:
# 新建Token bin/elasticsearch-create-enrollment-token --scope kibana # 重置 ES 密码(默认用户名为 elastic) bin/elasticsearch-reset-password -u elasticDocker Compose 安装
还需要为 ES 安装analysis-ik中文分词器,十分简单,下载压缩包并【解压】到 ES 的插件目录(plugins 目录,通常在 ES 的安装根目录,注意需要创建一个父目录存放解压文件),重启 ES 即可。也可以使用 ES 插件安装命令行工具,推荐使用解压方式安装。
# 将二进制包上传服务器中,并解压
# 注意不能直接解压到 plugins 目录下,需创建一个父级目录
mkdir -p /path/to/es-location/plugins/analysis-ik
unzip elasticsearch-analysis-ik-8.17.0.zip -d ./plugins/analysis-ik# 进入 ES 容器中,使用 ES 插件安装工具运行如下指令(注意版本号需和 ES 一致)
# 推荐使用二进制压缩包安装,指令安装可能会非常慢
bin/elasticsearch-plugin install https://get.infini.cloud/elasticsearch/analysis-ik/8.17.0analysis-ik 分词器支持两种分词模式:ik_smart(按词语切分,粒度粗) 和 ik_max_word(按字切分,粒度细)。
最后,访问 Kibana 面板 localhost:5601 查看效果
ES 语法
在 Kibana 面板的主菜单中找到 Dev Tools 选项,可以在控制台中输入 DSL(Domain Specific Language)语句操作 ES。
索引库
索引库类似于 MySQL 中的表,用于定义文档(JSON)数据结构。如下:
JSON 示例{ "id": "110", "name": "ZJX", "info": "啊!吉林长春药店,每一个都很哇塞呀!", "age": 18, "isMarried": true, "address": { "city": "成都", "country": "中国" }, "phone": [ { "name": "达州号", "value": "18282998944" } ], "createTime": "2024-09-01 12:00:00" }新增索引库# type 属性值 keyword 表示不分词,text 表示分词。index 属性值默认 true,表示这个字段参与搜索 PUT /test-my-es-index { "mappings": { "dynamic_date_formats": ["yyyy-MM-dd","yyyy-MM-dd HH:mm:ss"], "properties": { "id":{"type":"keyword"}, "name": { "type": "keyword", "index": true }, "info":{ "type": "text", "analyzer": "ik_smart" }, "age": {"type": "integer","index": false}, "isMarried":{"type": "boolean"}, "address":{ "properties": { "city": {"type": "keyword"}, "country":{"type": "keyword"} } }, "phone":{ "type": "nested", "properties": { "name": {"type": "keyword"}, "value": {"type": "keyword"} } }, "createTime": { "type": "date", "format": "yyyy-MM-dd HH:mm:ss" } } } }查/删/改索引库# 查询索引库 GET /test-my-es-index # 删除索引库 DELETE /test-my-es-index # 修改索引库,ES中不允许修改!!文档
文档类似于 MySQL 中的一行记录。
新增# 语法为: POST /索引库名/_doc/文档id ;若不写文档id,ES会随机生成一个 POST /test-my-es-index/_doc/1 { "id": "110", "name": "ZJX", "info": "啊!吉林长春药店,每一个都很哇塞呀!", "age": 18, "isMarried": true, "address": { "city": "成都", "country": "中国" }, "phone": [ { "name": "达州号", "value": "18282998944" } ], "createTime": "2024-09-01 12:00:00" }删除# 语法为: DELETE /索引库名/_doc/文档id DELETE /test-my-es-index/_doc/1修改# 语法为: 1.全部修改 PUT /索引库名/_doc/文档id 2.局部修改 POST /索引库名/_update/文档id # 方式一:全部修改,先将之前的删掉,再添加新的。若文档id存在则替换,不存在则新增 PUT /test-my-es-index/_doc/1 { "name": "ZZZ", "info": "啊!吉林长春药店,每一个都很哇塞呀!", "age": 21 } # 方式二:局部修改 POST /test-my-es-index/_update/1 { "doc": { "name": "XXX", "info": "啊!吉林长春药店,每一个都很哇塞呀!", "age": 23 } }查询# 根据id查询,语法为: GET /索引库名/_doc/文档id GET /test-my-es-index/_doc/1 # 查询全部 GET /test-my-es-index/_search { "query": { "match_all": {} } } # 分页查询 GET /test-my-es-index/_search { "query": { "match_all": {} }, "from": 0, "size": 10 }
整合 SpringBoot
提示
笔者在安装 ES8.X 时发现默认会用 https 通信,查看的 ES 配置文件,发现它使用的自签证书,这会导致 Java 客户端无法连接 https://localhost:9200,因为证书不受信任。
如果需要 https 通信,自行研究如何将证书添加到 Java 信任库中(很简单,懒得写了)。为了方便,直接修改 ES 配置文件将 https 关掉。
xpack.security.http.ssl.enabled: falseEasy-Es
Easy-Es(简称 EE)是一款基于 ElasticSearch(简称 Es)官方提供的 RestHighLevelClient 打造的 ORM 开发框架,它和 Mybatis-Plus(简称 MP)使用及其相似,都来自于同一个组织(dromara ,国内顶级开源社区)。
具体的整合方式参考官网即可,Easy-Es 对国人十分友好,文档看着很舒服,推荐使用,但是更新速度较慢,目前还不支持 ES8.X。
Spring Boot Starter
ES 官网提供了各种客户端 SDK,包括 Java 语言的elasticsearch-java,它一个全新的客户端库,与旧版 High Level Rest Client (HLRC) 没有任何关系。
SpringBoot 提供的 starter,支持各种 Java 客户端,在 pom 中添加客户端依赖,SpringBoot 会装配相应的 bean,如添加elasticsearch-java依赖,则使用 ElasticsearchClient,添加 elasticsearch-rest-client 依赖则使用 RestClient。
SpringBoot 更新速度比较快,且支持 ES8.X,优点是非常与时俱进,缺点就是文档看着不爽,某些功能需要慢慢研究他的 API 才能琢磨出来。
创建一个名为 elastic-search-demo 的 SpringBoot 项目:
@SpringBootApplication
@EntityScan("com.zjx.elasticsearch.demo.entity")
@EnableElasticsearchRepositories("com.zjx.elasticsearch.demo.mapper")
public class ElasticSearchDemoApplication {
public static void main(String[] args) {
SpringApplication.run(ElasticSearchDemoApplication.class, args);
}
}<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
<!-- Elasticsearch Client-->
<dependency>
<groupId>co.elastic.clients</groupId>
<artifactId>elasticsearch-java</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>spring:
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: Asia/Shanghai
application:
name: elastic-search-demo
elasticsearch:
uris: http://localhost:9200
username: elastic
password: aYBUgY9gUc4t4Y_hK7QC虽然 ElasticsearchClient 能支持 ES 的全部功能,但需要直接处理较多的底层细节和 API。在 SpringBoot 中,可以使用 ElasticsearchTemplate 或者 ElasticsearchOperations 来操作 ES,他帮我们简化了 ES 操作的抽象层,一般情况下都够用,以下为一些简单示例:
@Data
@Document(indexName = "test-my-es-index") // 索引库名称
public class User {
@Id
private String id;
// Keyword 表示这个字段不用分词,Text表示分词
@Field(type = FieldType.Keyword)
private String name;
@Field(type = FieldType.Text, analyzer = "ik_smart")
private String info;
private int age;
private boolean isMarried;
private Address address;
private List<Phone> phone;
// 为啥这样写? 时间序列化问题卡了我两天,各种百度都找不到合适的
// 最后查看Spring官网,10秒钟解决。 ES 服务端推荐使用 uuuu 替代 yyyy
@Field(type = FieldType.Date, format = {}, pattern = "uuuu-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createTime;
}@Slf4j
@Service
public class UserServiceImpl implements IUserService {
@Autowired
private UserMapper userMapper;
@Autowired
private ElasticsearchOperations elasticsearchOperations;
@Override
public User saveUser(User user) { return userMapper.save(user); }
@Override
public void deleteUser(String id) { userMapper.deleteById(id); }
@Override
public String upDateById(User user) { return elasticsearchOperations.update(user).getResult().name(); }
@Override
public void deleteAllUsers() { userMapper.deleteAll(); }
@Override
public Optional<User> getUserById(String id) { return userMapper.findById(id); }
@Override
public List<User> getAllUsers() { return StreamSupport.stream(userMapper.findAll().spliterator(), false).toList(); }
@Override
public Page<User> getUsersOfInfoByPage(String info, int page, int size) {
Pageable pageable = PageRequest.of(page, size);
return userMapper.findByInfo(info, pageable);
}
}public interface UserMapper extends ElasticsearchRepository<User, String> {
// 根据 info 分页查询,Spring 会自动生成实现,复杂场景可使用 @Query 注解
// @Query("{\"match\": {\"Info\": \"?0\"}}")
// @Query("{\"bool\": {\"must\": [{\"match\": {\"Info\": \"?0\"}}], \"sort\": [{\"createTime\": {\"order\": \"desc\"}}]}}")
Page<User> findByInfo(String Info, Pageable pageable);
}
