tio-boot官网

Elasticsearch

Introduction

Elasticsearch 是一个基于分布式架构的搜索和分析引擎,主要用于处理大规模的文本数据。它建立在 Apache Lucene 之上,并提供了一个基于 RESTful API 的接口,使得数据的索引和搜索变得非常简便。以下是 Elasticsearch 的简介和一些基本概念:

简介

Elasticsearch 是一个开源的搜索引擎,最初由 Elasticsearch N.V.(现在是 Elastic)开发。它具有高可用性、可扩展性和实时性的特点,适用于各种搜索、日志和分析应用场景。Elasticsearch 通常与 Logstash、Kibana 和 Beats 共同使用,形成 Elastic Stack(之前称为 ELK Stack)。

基本概念

  1. 索引 (Index)
    索引类似于数据库中的表。在 Elasticsearch 中,索引是一个包含文档的集合,并且这些文档共享相同的结构。每个索引都有一个唯一的名字,通过这个名字来引用索引中的数据。
  2. 文档 (Document)
    文档是 Elasticsearch 中最基本的数据单元,类似于关系数据库中的行。每个文档表示一个 JSON 格式的对象,并存储在索引中。
  3. 类型 (Type)
    在 Elasticsearch 7.0 之前,类型是索引内用于定义文档结构的逻辑分组。在 7.0 及之后的版本中,类型被废弃,每个索引只能有一种类型。
  4. 字段 (Field)
    字段是文档的组成部分,类似于关系数据库中的列。每个字段都有一个名字和一个值,值可以是字符串、数字、布尔值、日期等。
  5. 映射 (Mapping)
    映射定义了文档和字段的结构,包括字段的数据类型、字段是否可被索引、字段的分词器等。类似于关系数据库中的模式定义。
  6. 节点 (Node)
    节点是运行 Elasticsearch 实例的基本单元,每个节点存储数据并参与集群的索引和搜索功能。一个集群可以包含一个或多个节点。
  7. 集群 (Cluster)
    集群是由一个或多个节点组成的集合,具有相同的集群名字。集群中的节点共同协作,分布式地存储数据并提供搜索功能。
  8. 分片 (Shard)
    分片是索引的子集,Elasticsearch 自动将数据分割成多个分片,以便实现分布式存储和处理。每个索引在创建时会分配一个或多个主分片和副本分片。
  9. 副本 (Replica)
    副本是主分片的副本,用于提高数据的可用性和容错性。当主分片发生故障时,副本可以替代主分片提供服务。
  10. 查询 DSL (Query DSL)
    查询 DSL 是 Elasticsearch 提供的一种用于构建复杂查询请求的 JSON 格式的查询语言。通过查询 DSL,用户可以组合多个查询条件来检索数据。

工作原理

  1. 索引数据
    数据通过 RESTful API 或客户端库发送到 Elasticsearch,Elasticsearch 将数据转换为 JSON 格式,并存储在相应的索引中。
  2. 搜索数据
    用户可以通过 RESTful API 或客户端库发送查询请求,Elasticsearch 解析查询条件,搜索相关的索引和分片,并返回匹配的结果。
  3. 分布式处理
    Elasticsearch 将数据分割成多个分片,并在集群中的多个节点上分布式存储和处理。这种分布式架构使得 Elasticsearch 具有高可用性和可扩展性。

Elasticsearch 的这些特性使其成为处理海量数据和复杂搜索需求的理想选择。无论是实时日志分析、全文搜索,还是复杂的数据分析,Elasticsearch 都能提供强大的支持。

安装

安装 Elasticsearch 的方法有很多种,简单的安装的方法如下

mkdir -p /data/docker/elastic-search/
cd /data/docker/elastic-search/
docker run -d \
--name=elastic-search \
--restart=always \
-e "discovery.type=single-node"  \
-e "xpack.security.enabled=true" \
-e "ELASTIC_PASSWORD=YourElasticPassword" \
-p 9200:9200 \
-p 9300:9300 \
-v $(pwd)/elastic-search/data:/usr/share/elasticsearch/data \
litongjava/elasticsearch:7.10.0

Java 工程整合 Elasticsearch

在一个普通的 Java 工程中整合 Elasticsearch,步骤如下:

  1. 添加依赖
    在你的项目中添加 Elasticsearch 的依赖。使用 Maven 或 Gradle 来管理依赖项。以下是 Maven 依赖:
    注意版本 需要和 服务端的版本相匹配
<dependency>
  <groupId>org.elasticsearch.client</groupId>
  <artifactId>elasticsearch-rest-high-level-client</artifactId>
  <version>7.10.0</version>
</dependency>
  1. 创建 Elasticsearch 客户端
    使用 RestHighLevelClient 创建 Elasticsearch 客户端。
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestClientBuilder.HttpClientConfigCallback;
import org.elasticsearch.client.RestHighLevelClient;

public class ElasticsearchConfig {
  private static final String HOST = "192.168.1.2";
  private static final int PORT = 9200;
  private static final String USERNAME = "elastic";
  private static final String PASSWORD = "YourElasticPassword";

  public static RestHighLevelClient createClient() {
    // credentialsProvider
    CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
    credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(USERNAME, PASSWORD));

    // httpHost
    HttpHost httpHost = new HttpHost(HOST, PORT, "http");

    // httpClientConfigCallback
    HttpClientConfigCallback httpClientConfigCallback = httpClientBuilder -> httpClientBuilder
        .setDefaultCredentialsProvider(credentialsProvider);

    // builder
    RestClientBuilder builder = RestClient.builder(httpHost).setHttpClientConfigCallback(httpClientConfigCallback);

    RestHighLevelClient client = new RestHighLevelClient(builder);
    return client;
  }
}
  1. 使用 Elasticsearch 客户端进行操作
    你可以使用 RestHighLevelClient 进行各种操作,如索引文档、搜索文档等。下面是一个示例,展示如何索引和搜索文档:
package com.litongjava.tio.web.hello.example;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;

import com.litongjava.tio.web.hello.config.ElasticsearchConfig;

public class ElasticsearchExample {
  public static void main(String[] args) throws IOException {
    RestHighLevelClient client = ElasticsearchConfig.createClient();

    // 索引文档
    IndexRequest indexRequest = new IndexRequest("posts");
    Map<String, Object> jsonMap = new HashMap<>();
    jsonMap.put("user", "kimchy");
    jsonMap.put("postDate", "2020-01-01");
    jsonMap.put("message", "trying out Elasticsearch");
    indexRequest.source(jsonMap);
    IndexResponse indexResponse = client.index(indexRequest, RequestOptions.DEFAULT);
    System.out.println("Index Response: " + indexResponse.getResult());

    // 搜索文档
    SearchRequest searchRequest = new SearchRequest("posts");
    SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
    searchSourceBuilder.query(QueryBuilders.matchAllQuery());
    searchRequest.source(searchSourceBuilder);
    SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
    System.out.println("Search Response: " + searchResponse.toString());

    client.close();
  }
}
  1. 关闭客户端
    在应用程序结束时,确保关闭 Elasticsearch 客户端以释放资源。
client.close();

output

Index Response: CREATED
ERROR StatusLogger Log4j2 could not find a logging implementation. Please add log4j-core to the classpath. Using SimpleLogger to log to the console...
Search Response: {"took":22,"timed_out":false,"_shards":{"total":1,"successful":1,"skipped":0,"failed":0},"hits":{"total":{"value":0,"relation":"eq"},"max_score":null,"hits":[]}}

通过以上步骤,你就可以在一个普通的 Java 工程中成功整合 Elasticsearch 并进行基本的操作了。

使用 Tio-Boot 集成 Elasticsearch

在本指南中,我们将介绍如何将 Elasticsearch 集成到 Tio-Boot 项目中。完成本教程后,您将了解如何配置 Elasticsearch,创建客户端配置类,并实现一个控制器来与 Elasticsearch 进行交互。

步骤 1:配置

首先,我们需要配置 Elasticsearch 的连接详细信息。这可以通过属性文件 app.properties 来完成:

elasticsearch.rest.urls=http://192.168.1.2:9200
elasticsearch.rest.username=elastic
elasticsearch.rest.password=YourElasticPassword

这些属性包括 Elasticsearch 实例的 URL 以及用于身份验证的用户名和密码。

步骤 2:配置类

接下来,我们创建一个配置类来设置 Elasticsearch 的 RestHighLevelClient。这个类从配置文件中读取属性,并初始化客户端。

import java.io.IOException;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import com.litongjava.jfinal.aop.annotation.ABean;
import com.litongjava.jfinal.aop.annotation.AConfiguration;
import com.litongjava.tio.boot.server.TioBootServer;
import com.litongjava.tio.utils.environment.EnvUtils;
import com.litongjava.tio.utils.hutool.StrUtil;
import lombok.extern.slf4j.Slf4j;

@AConfiguration
@Slf4j
public class ElasticsearchConfig {

  @ABean
  public static RestHighLevelClient createClient() {
    // 读取配置属性
    String urls = EnvUtils.get("elasticsearch.rest.urls");
    String username = EnvUtils.get("elasticsearch.rest.username");
    String password = EnvUtils.get("elasticsearch.rest.password");

    if (StrUtil.isEmpty(urls)) {
      return null;
    }

    // 创建 HttpHost 实例
    HttpHost httpHost = HttpHost.create(urls);

    // 配置 RestClientBuilder
    RestClientBuilder builder = RestClient.builder(httpHost);

    if (StrUtil.isNotEmpty(username)) {
      // 设置凭证提供者
      CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
      credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(username, password));

      // 配置 HTTP 客户端回调
      builder.setHttpClientConfigCallback(httpClientBuilder -> httpClientBuilder
          .setDefaultCredentialsProvider(credentialsProvider));
    }

    // 创建 RestHighLevelClient
    RestHighLevelClient client = new RestHighLevelClient(builder);

    // 确保在关闭时关闭客户端
    TioBootServer.me().addDestroyMethod(() -> {
      try {
        client.close();
      } catch (IOException e) {
        e.printStackTrace();
      }
    });

    // 记录连接状态
    try {
      log.info("client:{}", client.ping(RequestOptions.DEFAULT));
    } catch (IOException e) {
      e.printStackTrace();
    }

    return client;
  }
}

解释

在配置类 ElasticsearchConfig 中,createClient 方法执行以下操作:

  1. 读取 Elasticsearch 连接的配置属性。
  2. 从 URL 创建 HttpHost 实例。
  3. 使用凭证配置 RestClientBuilder
  4. 初始化 RestHighLevelClient 并确保在服务器关闭时正确关闭。
  5. 记录连接状态,以验证客户端是否可以 ping 通 Elasticsearch 服务器。

RestHighLevelClient 被注解为 @ABean,这使得它成为 Tio-Boot 应用上下文中的一个管理 bean。这允许我们在应用的其他部分取出和使用该客户端。

步骤 3:控制器

现在,我们创建一个控制器来处理请求并与 Elasticsearch 进行交互。这个控制器将提供用于创建和搜索文档的端点。

package com.litongjava.tio.web.hello.controller;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import org.elasticsearch.action.DocWriteResponse.Result;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import com.litongjava.jfinal.aop.Aop;
import com.litongjava.tio.http.server.annotation.RequestPath;
import com.litongjava.tio.utils.resp.RespVo;

@RequestPath("/elastic-search")
public class ElasticSearchController {

  public RespVo create() {
    RestHighLevelClient client = Aop.get(RestHighLevelClient.class);

    // 索引文档
    IndexRequest indexRequest = new IndexRequest("posts");
    Map<String, Object> jsonMap = new HashMap<>();
    jsonMap.put("user", "kimchy");
    jsonMap.put("postDate", "2020-01-01");
    jsonMap.put("message", "trying out Elasticsearch");
    indexRequest.source(jsonMap);
    IndexResponse indexResponse;
    try {
      indexResponse = client.index(indexRequest, RequestOptions.DEFAULT);
    } catch (IOException e) {
      e.printStackTrace();
      return RespVo.fail(e.getMessage());
    }
    Result result = indexResponse.getResult();
    return RespVo.ok(result);
  }

  public RespVo search() {
    RestHighLevelClient client = Aop.get(RestHighLevelClient.class);

    // 搜索文档
    SearchRequest searchRequest = new SearchRequest("posts");
    SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
    searchSourceBuilder.query(QueryBuilders.matchAllQuery());
    searchRequest.source(searchSourceBuilder);
    SearchResponse searchResponse;
    try {
      searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
    } catch (IOException e) {
      e.printStackTrace();
      return RespVo.fail(e.getMessage());
    }
    return RespVo.ok(searchResponse);
  }
}

解释

ElasticSearchController 类定义了两个端点:

  1. 创建端点 (/elastic-search/create):该端点将一个新文档索引到 posts 索引中,并包含示例数据。
  2. 搜索端点 (/elastic-search/search):该端点在 posts 索引中搜索所有文档。

这两个端点都使用 Aop.get 方法注入的 RestHighLevelClient bean,演示了如何从应用上下文中检索管理 bean。

启动项目

整合完成后,启动速度由 300ms 增加到了 1452ms.
启动项目后。您应该看到一个日志条目,表明客户端已成功连接到 Elasticsearch:

2024-08-06 14:45:35.892 [main] INFO  c.l.t.w.h.c.ElasticsearchConfig.createClient:68 - client:true

您可以通过以下 URL 在浏览器中测试端点:

create 端点应返回一个表示文档已创建的响应:

{ "data": "CREATED", "ok": true, "msg": null, "code": 1 }

search 端点应返回一个包含搜索结果的响应:

{
  "data": {
    "hits": {
      "total": { "value": 1, "relation": "eq" },
      "hits": [
        {
          "_index": "posts",
          "_id": "1",
          "_source": {
            "user": "kimchy",
            "postDate": "2020-01-01",
            "message": "trying out Elasticsearch"
          }
        }
      ]
    },
    "took": 599
  },
  "ok": true,
  "msg": null,
  "code": 1
}

结论

在本指南中,我们演示了如何将 Elasticsearch 集成到 Tio-Boot 项目中。通过将 RestHighLevelClient 配置为一个管理的 bean,我们可以在控制器中轻松注入和使用它,实现与 Elasticsearch 的无缝交互。


李通
215 声望0 粉丝