Elasticsearch8入门
版本
8.4
安装
windows本地安装,直接下载zip包解压即可
windows安装官方教程
启动
.\bin\elasticsearch.bat
elasticsearch本地就跑起来了
配置
主配置文件在config下的elasticsearch.yml
elasticsearch默认是要校验身份的,可以暂时去掉xpack.security.enabled
修改为false
# Enable security features
xpack.security.enabled: false
配置可跨域(否则跨域不可访问)
http.cors.enabled: true
http.cors.allow-origin: "*"
http.host: 0.0.0.0
elasticsearch.yml
重启之后既可以开始使用了,简单测试一下是否正常
$ curl localhost:9200
localhost:9200
elasticsearch本地就搭建好了
客户端
就像mysql有navicat等客户端,用起来方便又直观,elasticsearch也有一个勉强可用的客户端
elasticsearch-head,是一个前端的代码,下载下来,运行也很简单: npm install
安装依赖,npm run start
运行,打开界面即可http://localhost:9100/
但从实际效果上看,客户端提供的功能非常少,也不适合初学者学习
概念
Elasticsearch可以看做一个便于搜索的数据库,相比传统关系型数据库如下
Mysql ‐> Databases ‐> Tables ‐> Rows ‐> Columns
Elasticsearch ‐> Indices ‐> Types ‐> Documents ‐> Fields
Elasticsearch 8 已经删除了Types
,所以现在的层级应该是
Elasticsearch ‐> Indices ‐> Documents ‐> Fields
Index
索引,相当于mysql中的一个数据表(原来有type时它相当于数据库,type相当于数据表,现在es8取消了type,index当做一个数据表来理解方便一点)
Documents
一条存储的数据,相当于mysql的一条数据
Fields
字段,类似mysql的子墩
API
Elasticsearch牛在封装了Lucene,提供了强大的搜索功能,同时对外暴露Restful Api使其易于对接,接下来就通过调用api来实现一个小功能:
存储一个网站的文章,并可以通过标题和内容智能检索
第一步,创建文章索引
就好比在mysql中创建一个文章表article
,包含三个字段id
,title
,content
curl --location --request PUT 'http://127.0.0.1:9200/article' \
--header 'Content-Type: application/json' \
--data-raw '{
"mappings": {
"properties": {
"id": {
"type": "long",
"index": false
},
"title": {
"type": "text",
"analyzer": "standard"
},
"content": {
"type": "text",
"analyzer": "standard"
}
}
}
}'
关于索引
的文档,可以参考Index APIs
第二步,添加几个测试文章
curl --location --request POST 'http://127.0.0.1:9200/article/_doc/1' \
--header 'Content-Type: application/json' \
--data-raw '{
"id": 1,
"title": "小李飞刀",
"content": "小李飞刀,例无虚发"
}'
其中url上article
代表索引名,_doc
是默认,1代表id,如果没有则自动生成,请求体即文章的标题和内容
多增加几个文章进行测试
article关于文档
的文档,可以参考Document APIs
第三步,检索
测试数据准备好了,接下来进行搜索测试,我们搜索"刀",并希望所有带"刀"字样的都搜出来,相当于sql的
WHERE (title like '%刀%' OR content like '%刀%')
写法如下,使用布尔过滤器
curl --location --request GET 'http://localhost:9200/article/_search' \
--header 'Content-Type: application/json' \
--data-raw '{
"query": {
"bool": {
"should": [
{ "match": { "title": "刀" }},
{ "match": { "content": "刀" }}
]
}
}
}'
最终输出结果如下
刀可以看到实现了我们的需求,带“刀”的数据都被查了出来
再搜索一下"刀剑"
可以看到相关的都被查出,这种查询在mysql是做不到的
这种搜索查询的语法是ES自己指定的,可以支持很多复杂的查询方式,而且有一个很不错的中文文档,文档可能有些过期,但大部分还好,并且人性化的对照了mysql的场景
整合springboot
-
如果想简单粗暴的代码调用es,其实使用HttpClient也可以,毕竟都是http接口,道理很简单,但写的代码肯定很费劲
-
为了方便用户使用,es肯定是要提供sdk的,即
elasticsearch-rest-high-level-client
,专门针对es的客户端,使用起来肯定更方便 -
为了使用更加方便,spring在elasticsearch-client基础上再次封装出了
spring-data-elasticsearch
,进一步的封装使spring用户调用es非常方便
spring每个阶段会根据spring的当前版本以及es的版本在不同时期适配不同的依赖包,这就导致每个spring-data-elasticsearch
版本肯定会有一个适用的spring版本及es版本,当前的关系如下
很不幸,当前好像并没有适配es8的版本,且我自己用的springboot版本为2.3.x,所以只能尝试使用4.0.x的spring-data-elasticsearch
,考虑到这种牛逼项目都有低版本适配,问题应该也不大
引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
配置Elasticsearch
主要是配置服务器地址,超时时间什么的,创建一个RestHighLevelClient客户端的bean
@Configuration
public class ElasticsearchClientConfig extends AbstractElasticsearchConfiguration {
// 地址
@Value("${spring.data.elasticsearch.host}")
private String host;
// 端口
@Value("${spring.data.elasticsearch.port}")
private String port;
@Override
@Bean
public RestHighLevelClient elasticsearchClient() {
final ClientConfiguration clientConfiguration = ClientConfiguration.builder()
.connectedTo(host + ":" + port)
.build();
return RestClients.create(clientConfiguration).rest();
}
}
到此spring的es配置结束,接下来就是增删查改,用过jpa的会发现基本一个套路
定义实体,映射到索引
创建一个实体Book并映射到es的索引book
@Data
@Document(indexName = "book",createIndex = true) // 映射book索引
public class Book {
// 主键标识
@Id
@Field(type = FieldType.Long)
private Long id;
@Field(analyzer="standard")
private String title;
@Field(analyzer="standard")
private String content;
}
定义仓库
public interface BookRepositoryImpl extends ElasticsearchRepository<Book, Long> {
List<Book> findByTitleOrContent(String title, String content);
}
这个仓库的接口定义好之后,就可以通过spring注入,注入对象默认包含方法
- save 保存,新增/修改
- findAll 查询,带分页
- delete 删除
- 等等
也可以自己定义方法,主要有两种方式
一、直接从方法名称派生查询
例如上面的findByTitleOrContent就会自动转化为根据标题或内容查询
二、使用@Query注解自定义的查询
例如
interface BookRepository extends ElasticsearchRepository<Book, String> {
@Query("{\"match\": {\"name\": {\"query\": \"?0\"}}}")
Page<Book> findByName(String name,Pageable pageable);
}
使用过jpa应该再熟悉不过了,功能十分强大,可以参考官方文档
使用仓库
这就非常简单了,写个小例子
@Autowired
private BookRepository bookRepository;
public void test() {
Book book = new Book();
book.setId(1L);
book.setTitle("雪中悍刀行");
book.setContent("你是我的白月光,我是你的小砒霜");
// 新增文档
bookRepository.save(book);
// 查询所有
Iterable<Book> all = bookRepository.findAll();
for (book po : all) {
}
// 通过标题或内容查询带"刀"的文档
List<Book> hits = bookRepository.findByTitleOrContent("刀", "刀");
}
修改版本不兼容问题
跑了一下还出出问题,报错type不能为null,原因是es8已取消type,而我们低版本客户端还是会校验type必须存在,导致运行出错,报错点如下
type不能为null
修改办法:
没找到太好的解决办法,只是粗暴的重写了DocWriteResponse类
type不能为null解决