elasticsearch-RestClient索引库以及基本文档操作

ES 官方提供了各种不同语言的客户端,用来操作 ES。这些客户端的本质就是组装 DSL 语句,通过 http 请求发送给 ES。官方文档地址:https://www.elastic.co/guide/en/elasticsearch/client/index.html

其中的Java Rest Client又包括两种:

  • Java Low Level Rest Client
  • Java High Level Rest Client

img

我们使用Java HighLevel Rest Client 客户端 API

SQL文件

这次学习有对应的数据库数据,我们从mysql获取数据,在elasticsearch中创建索引,sql文件已经准备好,请点击下载:tb_hotel.sql,原始项目,请点击下载:hotel-demo.zip

初始化RestClient

在 elasticsearch 提供的 API 中,elasticsearch 一切交互都封装在一个名为 RestHighLevelClient 的类中,必须先完成这个对象的初始化,建立与 elasticsearch 的连接。

<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-high-level-client</artifactId>
</dependency>

SpringBoot 默认的 ES 版本是 7.6.2,我们需要覆盖默认的ES版本

<properties>
    <java.version>1.8</java.version>
    <elasticsearch.version>7.12.1</elasticsearch.version>
</properties>

我们创建一个测试类 HotelIndexTest,然后将初始化的代码编写在 @BeforeEach 方法,关闭连接写在@AfterEach方法中。

public class HotelIndexTest {

    private RestHighLevelClient client;

    /**
     * 初始化客户端
     */
    @BeforeEach
    void setup(){
        client = new RestHighLevelClient(RestClient.builder(
                HttpHost.create("http://192.168.113.130:9200")
        ));
    }

    /**
     * 关闭客户端
     * @throws IOException
     */
    @AfterEach
    void close() throws IOException {
        client.close();
    }
}

索引库操作

创建索引库
 /**
     * 创建索引库
     * @throws IOException
     */
    @Test
    void createHotelIndex() throws IOException {
        // 1.创建Request对象
        CreateIndexRequest request = new CreateIndexRequest("hotel");
        // 2.准备请求的参数:DSL语句
        request.source(MAPPING_TEMPLATE, XContentType.JSON);
        // 3.发送请求
        client.indices().create(request, RequestOptions.DEFAULT);
    }
public class HotelConstants {
    public static final String MAPPING_TEMPLATE = "{\n" +
            "  \"mappings\": {\n" +
            "    \"properties\": {\n" +
            "      \"id\": {\n" +
            "        \"type\": \"keyword\"\n" +
            "      },\n" +
            "      \"name\":{\n" +
            "        \"type\": \"text\",\n" +
            "        \"analyzer\": \"ik_max_word\",\n" +
            "        \"copy_to\": \"all\"\n" +
            "      },\n" +
            "      \"address\":{\n" +
            "        \"type\": \"keyword\",\n" +
            "        \"index\": false\n" +
            "      },\n" +
            "      \"price\":{\n" +
            "        \"type\": \"integer\"\n" +
            "      },\n" +
            "      \"score\":{\n" +
            "        \"type\": \"integer\"\n" +
            "      },\n" +
            "      \"brand\":{\n" +
            "        \"type\": \"keyword\",\n" +
            "        \"copy_to\": \"all\"\n" +
            "      },\n" +
            "      \"city\":{\n" +
            "        \"type\": \"keyword\",\n" +
            "        \"copy_to\": \"all\"\n" +
            "      },\n" +
            "      \"starName\":{\n" +
            "        \"type\": \"keyword\"\n" +
            "      },\n" +
            "      \"business\":{\n" +
            "        \"type\": \"keyword\"\n" +
            "      },\n" +
            "      \"location\":{\n" +
            "        \"type\": \"geo_point\"\n" +
            "      },\n" +
            "      \"pic\":{\n" +
            "        \"type\": \"keyword\",\n" +
            "        \"index\": false\n" +
            "      },\n" +
            "      \"all\":{\n" +
            "        \"type\": \"text\",\n" +
            "        \"analyzer\": \"ik_max_word\"\n" +
            "      }\n" +
            "    }\n" +
            "  }\n" +
            "}";
}
删除索引库
@Test
void deleteHotelIndex() throws IOException {
    DeleteIndexRequest hotel = new DeleteIndexRequest("hotel");
    restHighLevelClient.indices().delete(hotel,RequestOptions.DEFAULT);
}
判断索引库是否存在
@Test
void existHotelIndex() throws IOException {
    GetIndexRequest hotel = new GetIndexRequest("hotel");
    boolean exists = restHighLevelClient.indices().exists(hotel, RequestOptions.DEFAULT);
    System.out.println(exists);
}

文档操作

我们将从数据库中查出数据,写入到elasticsearch中。

索引库实体类
@Data
@TableName("tb_hotel")
public class Hotel {
    @TableId(type = IdType.INPUT)
    private Long id;
    private String name;
    private String address;
    private Integer price;
    private Integer score;
    private String brand;
    private String city;
    private String starName;
    private String business;
    private String longitude;
    private String latitude;
    private String pic;
}

与我们的索引库结构存在差异:

  • longitude和latitude需要合并为location

因此,我们需要定义一个新的类型,与索引库结构吻合:

@Data
@NoArgsConstructor
public class HotelDoc {
    private Long id;
    private String name;
    private String address;
    private Integer price;
    private Integer score;
    private String brand;
    private String city;
    private String starName;
    private String business;
    private String location;
    private String pic;

    public HotelDoc(Hotel hotel) {
        this.id = hotel.getId();
        this.name = hotel.getName();
        this.address = hotel.getAddress();
        this.price = hotel.getPrice();
        this.score = hotel.getScore();
        this.brand = hotel.getBrand();
        this.city = hotel.getCity();
        this.starName = hotel.getStarName();
        this.business = hotel.getBusiness();
        this.location = hotel.getLatitude() + ", " + hotel.getLongitude();
        this.pic = hotel.getPic();
    }
}
新增文档
@SpringBootTest
public class HotelDocTest {
    private RestHighLevelClient client;

    @Autowired
    private HotelService hotelService;

    /**
     * 初始化客户端
     */
    @BeforeEach
    void setup() {
        client = new RestHighLevelClient(RestClient.builder(
                HttpHost.create("http://192.168.113.130:9200")
        ));
    }

    /**
     * 新增文档
     * @throws IOException
     */
    @Test
    void testAddDoc() throws IOException {
        //通过id获取数据
        Hotel hotel = hotelService.getById("38609");
        HotelDoc hotelDoc = new HotelDoc(hotel);

        // 创建Request对象
        IndexRequest hotelRequest = new IndexRequest("hotel").id(hotelDoc.getId().toString());

        // 准备Json文档
        hotelRequest.source(JSON.toJSONString(hotelDoc),XContentType.JSON);

        // 发送请求
        client.index(hotelRequest,RequestOptions.DEFAULT);
    }

    /**
     * 关闭客户端
     *
     * @throws IOException
     */
    @AfterEach
    void close() throws IOException {
        client.close();
    }
}
查询文档
@Test
void testGetDocumentById() throws IOException {
    // 1.准备Request
    GetRequest hotel = new GetRequest("hotel", "38609");
    // 2.发送请求,得到响应
    GetResponse hotelResponse = client.get(hotel, RequestOptions.DEFAULT);
    // 3.解析响应结果
    String hotelDocSourceAsString = hotelResponse.getSourceAsString();
    // 4.json转实体类
    HotelDoc hotelDoc = JSON.parseObject(hotelDocSourceAsString, HotelDoc.class);
    System.out.println(hotelDoc);
}
删除文档
@Test
void testDeleteDocumentById() throws IOException {
    DeleteRequest hotel = new DeleteRequest("hotel", "38609");
    client.delete(hotel,RequestOptions.DEFAULT);
}

修改文档

前面我们说过,修改文档有两种方式:

  • 全量修改:直接覆盖原来的文档
  • 增量修改:修改文档中的部分字段

在 RestClient 的 API 中,全量修改与新增的 API 完全一致,判断依据是 ID

  • 如果新增时,ID已经存在,则修改
  • 如果新增时,ID不存在,则新增

所以全量修改写法与新增文档一样,下面我们主要是介绍增量修改。

@Test
void testUpdateDocument() throws IOException {
    // 1.准备Request
    UpdateRequest request = new UpdateRequest("hotel", "38609");
    // 2.准备请求参数
    request.doc(
        "price", "952",
        "starName", "四钻"
    );
    // 3.发送请求
    client.update(request, RequestOptions.DEFAULT);
}
批量导入文档
@Test
void testBulk() throws IOException {
    BulkRequest bulkRequest = new BulkRequest();
    List<Hotel> hotelList = hotelService.list();
    hotelList.forEach(item -> {
        HotelDoc hotelDoc = new HotelDoc(item);
        bulkRequest.add(new IndexRequest("hotel")
                .id(hotelDoc.getId().toString())
                .source(JSON.toJSONString(hotelDoc), XContentType.JSON));
    });
    client.bulk(bulkRequest, RequestOptions.DEFAULT);
}

elasticsearch-RestClient索引库以及基本文档操作
https://www.zhaojun.inkhttps://www.zhaojun.ink/archives/1008
作者
卑微幻想家
发布于
2022-01-20
许可协议