TECHJavaJava 核心技术

Elasticsearch8入门

2022-10-09  本文已影响0人  pq217

版本

8.4

安装

windows本地安装,直接下载zip包解压即可
windows安装官方教程
启动

.\bin\elasticsearch.bat

elasticsearch本地就跑起来了

docker安装更方便

配置

主配置文件在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/

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

spring每个阶段会根据spring的当前版本以及es的版本在不同时期适配不同的依赖包,这就导致每个spring-data-elasticsearch版本肯定会有一个适用的spring版本及es版本,当前的关系如下

spring-data-elasticsearch

很不幸,当前好像并没有适配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注入,注入对象默认包含方法

也可以自己定义方法,主要有两种方式
一、直接从方法名称派生查询
例如上面的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解决
上一篇下一篇

猜你喜欢

热点阅读