springboot2 集成 elasticsearch8.2.3 CRUD操作

文章目录

        1、前言

        2、es配置

        3、Maven配置

        4、springboot配置

        5、创建表(通过json格式文件)

        6、添加单条记录

        7、批量添加记录

        8、更新单条记录

        9、通过id获取记录

        10、通过id删除记录

        11、分页查询(多条件情况)

1、前言

        踩了好多坑,弄了一个通宵终于搞定了。有问题可以给我留言。

        elasticsearch8.2.3下载地址

        elasticsearch-analysis-ik-8.2.3 分词器下载地址 (注意:分词器和es需要版本一致)

        ES 官方 Client文档

        ES 官方 RestAPI文档

        查看文档配置【GET】:http://localhost:9200/{indices}/_mapping

        查看某条记录数据【GET】:http://localhost:9200/{indices}/_doc/{id}

        查看某个字段分词结果【GET】:http://localhost:9200/{indices}/_termvectors/{id}?fields={fieldName}

        查看分词规则【POST】:http://localhost:9200/_analyze

        { "analyzer":"ik_smart", "text":"广东省广州市荔湾区育贤路30号" }

2、es配置

        打开 /elasticsearch-8.2.3/config/elasticsearch.yml

xpack.license.self_generated.type: basic

xpack.security.enrollment.enabled: true

3、Maven配置

<!-- es 依赖包(三个) -->
<dependency>
    <groupId>co.elastic.clients</groupId>
    <artifactId>elasticsearch-java</artifactId>
    <version>8.2.3</version>
</dependency>
<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-client</artifactId>
    <version>8.2.3</version>
</dependency>
<dependency>
    <groupId>org.glassfish</groupId>
    <artifactId>jakarta.json</artifactId>
    <version>2.0.1</version>
</dependency>

<!-- 生成get、set方法 -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>

4、springboot配置

        配置文件如下:

frame:
  elasticsearch:
    host: 127.0.0.1
    port: 9200
    # 由于我这里测试关闭了账号密码、所以我就不写了
    username: xxx
    password: xxx

         Java配置:

/**
 * 配置
 */
@Configuration
public class Config {

    @Value("${frame.elasticsearch.host}")
    private String host;
    @Value("${frame.elasticsearch.port}")
    private int port;
    @Value("${frame.elasticsearch.username:}")
    private String userName;
    @Value("${frame.elasticsearch.password:}")
    private String passWord;

    // es 连接客户端
    @Bean
    public ElasticsearchClient elasticsearchClient() {
        final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();

        // 设置账号密码
        credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(userName, passWord));

        // Create the low-level client
        RestClient restClient = RestClient.builder(new HttpHost(host, port))
                .setHttpClientConfigCallback(httpClientBuilder -> httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider))
                .build();

        // 使用Jackson映射器创建传输
        ElasticsearchTransport transport = new RestClientTransport(restClient, new JacksonJsonpMapper());

        // 创建API客户端
        return new ElasticsearchClient(transport);
    }
}

5、创建表(通过json格式文件)

         5.1、确定需要记录的数据格式。实体类如下:

// 用户信息
@Data
@Accessors(chain = true)
public class Staff {
    // 主键
    private String id;
    // 姓名
    private String name;
    // 性别:男、女
    private String sex;
    // 年龄
    private Integer age;
    // 居住地址
    private String address;
    // 兴趣爱好
    private String[] hobbys;
    // 学校
    private List<School> schools;

    @Data
    public static class School {
        // 学校名称
        private String name;
        // 学校地址
        private String address;

        public School() {}

        public School(String name, String address) {
            this.name = name;
            this.address = address;
        }
    }
}

        5.2、json格式文件如下:

        文件存放路径:resources/es/staff.json

        (注意:json文件中的注释需要删除,是我为了解释才临时添加上去的)

        具体配置规则可参考《官网:字段数据类型》《引用:mapping详细说明》

{
  "mappings": {
    "properties": {
      "id": {
        // keyword: 全词匹配,不会建立分词
        "type": "keyword"
      },
      "name": {
        // text: 会建立分词
        "type": "text",
        // 分词规则:ik_max_word、ik_smart
        "analyzer": "ik_max_word",
        // 如果text类型的字段需要排序、分组操作,需要额外进行定义类型为keyword
        "fields": {
          "keyword": {
            "type": "keyword"
          }
        }
      },
      "sex": {
        "type": "keyword"
      },
      "age": {
        "type": "integer"
      },
      "address": {
        "type": "text",
        "analyzer": "ik_max_word"
      },
      "hobbys": {
        "type": "text",
        "analyzer": "ik_max_word"
      },
      "schools": {
        "type": "object",
        "properties": {
          "name": {
            "type": "text",
            "analyzer": "ik_max_word"
          },
          "address": {
            "type": "text",
            "analyzer": "ik_max_word"
          }
        }
      }
    }
  }
}

         5.3、创建、删除表

// 判断是否已经存在
BooleanResponse exists = elasticsearchClient.indices().exists(r -> r.index("staff"));
if (exists.value()) {
	// 删除表
	elasticsearchClient.indices().delete(d -> d.index("staff"));
}

// 创建
// >> 获取mapping配置文件
File file = ResourceUtils.getFile("classpath:es/staff.json");
FileReader fileReader = new FileReader(file);
// >> 创建
CreateIndexResponse indexResponse = elasticsearchClient.indices()
		.create(c -> c
				.index("staff")
				.withJson(fileReader)
		);

6、添加单条记录

Staff staff = new Staff().setId("001").setName("张三").setAge(20).setSex("男").setAddress("广东省")
		.setHobbys(new String[]{"学习", "弹钢琴"})
		.setSchools(new ArrayList<Staff.School>() {{
			add(new Staff.School("广州市第一中学(高中校区)", "广东省广州市荔湾区育贤路30号"));
			add(new Staff.School("暨南大学(广州石牌校区)", "广州市天河区黄埔大道西601号"));
		}});
IndexResponse response = elasticsearchClient.index(i -> i.index("staff").id(staff.getId()).document(staff));

7、批量添加记录

// 批量数据
ArrayList<Staff> list = new ArrayList<>();
list.add(new Staff().setId("001").setName("张三").setAge(20).setSex("男").setAddress("广东省")
		.setHobbys(new String[]{"学习", "弹钢琴"})
		.setSchools(new ArrayList<Staff.School>() {{
			add(new Staff.School("广州市第一中学(高中校区)", "广东省广州市荔湾区育贤路30号"));
			add(new Staff.School("暨南大学(广州石牌校区)", "广州市天河区黄埔大道西601号"));
		}}));
list.add(new Staff().setId("002").setName("李三").setAge(45).setSex("男").setAddress("湖北省")
		.setHobbys(new String[]{"学习", "打篮球"})
		.setSchools(new ArrayList<Staff.School>() {{
			add(new Staff.School("荆州中学", "湖北省荆州市荆州区楚源大道"));
			add(new Staff.School("武汉大学", "湖北省武汉市武昌区珞珈山16号"));
		}}));
list.add(new Staff().setId("003").setName("张美").setAge(18).setSex("女").setAddress("湖北省")
		.setHobbys(new String[]{"逛街"})
		.setSchools(new ArrayList<Staff.School>() {{
			add(new Staff.School("荆州中学", "湖北省荆州市荆州区楚源大道"));
			add(new Staff.School("华中科技大学", "湖北省武汉市洪山区珞喻路1037号"));
		}}));

// 处理数据并保存
BulkRequest.Builder br = new BulkRequest.Builder();
for (Staff staff : list) {
	br.operations(op -> op
			.index(idx -> idx
					.index("staff")
					.id(staff.getId())
					.document(staff)
			)
	);
}
BulkResponse result = elasticsearchClient.bulk(br.build());

// 判断结果
if (result.errors()) {
	System.out.println("Bulk had errors");
	for (BulkResponseItem item: result.items()) {
		if (item.error() != null) {
			System.out.println(item.error().reason());
		}
	}
} else {
	System.out.println("批量添加成功");
}

8、更新单条记录

Staff staff = new Staff().setId("001").setName("张三三");
UpdateResponse<Staff> response = elasticsearchClient.update(u -> u
		.index(DOCUMENT_NAME)
		.id(staff.getId())
		.doc(staff),
	Staff.class
);

9、通过id获取记录

GetResponse<Staff> response = elasticsearchClient.get(g -> g.index("staff").id(id), Staff.class);
if (response.found()) {
	Staff staff = response.source();
	System.out.println(JSON.toJSONString(staff));
	return staff;
} else {
	return null;
}

10、通过id删除记录

elasticsearchClient.delete(d -> d.index("staff").id(id));

11、分页查询(多条件情况)

         查询条件:

// 搜索条件
@Data
@Accessors(chain = true)
public class StaffQuery {
    // 分页:起始行
    private int form;
    // 分页:页大小
    private int size;

    // 搜索全表的关键字,匹配多个字段
    private String keywords;

    // 名称
    private String name;
    // 性别
    private String sex;
    // 最小年龄
    private Integer minAge;
    // 地址
    private String address;
    // 兴趣爱好
    private String hobby;
    // 学校地址
    private String schoolAddress;
}

        搜索方法:

public void findPage(StaffQuery query) throws IOException {
    // 查询请求
	SearchRequest.Builder builder = new SearchRequest.Builder();
	builder.index("staff");

	// 查询的字段
    // builder.source(f -> f.filter(v -> v.includes("id", "name")));

	/*
	 * 组合搜索条件
	 *  should = or
	 *  must = and
	 */
	BoolQuery.Builder boolQuery = new BoolQuery.Builder();

	// >> 匹配多个字段
	if (StringUtils.isNotEmpty(query.getKeywords())) {
		boolQuery.should(q -> q.combinedFields(c -> c
				.query(query.getKeywords())
				.fields("address", "hobbys", "schools.name", "schools.address")
		));
		boolQuery.should(q -> q.combinedFields(c -> c
				.query(query.getKeywords())
				.fields("name")
				.boost(2F)
		));
	}
	// >> 用户名称
	if (StringUtils.isNotEmpty(query.getName())) {
		// 添加上.keyword 是查询等于该字段的记录,不会分词搜索
        boolQuery.must(q -> q.match(m -> m.query(query.getName()).field("name.keyword")));
	}
	// >> 用户性别
	if (StringUtils.isNotEmpty(query.getSex())) {
		boolQuery.must(q -> q.match(m -> m.query(query.getSex()).field("sex")));
	}
	// >> 最小年龄
	if (query.getMinAge() != null) {
		boolQuery.must(q -> q.range(m -> m.gte(JsonData.of(query.getMinAge())).field("age")));
	}
	// >> 用户地址
	if (StringUtils.isNotEmpty(query.getAddress())) {
		boolQuery.must(q -> q.match(m -> m.query(query.getAddress()).field("address")));
	}
	// >> 用户兴趣爱好
	if (StringUtils.isNotEmpty(query.getHobby())) {
		boolQuery.must(q -> q.match(m -> m.query(query.getHobby()).field("hobbys")));
	}
	// >> 用户学校地址
	if (StringUtils.isNotEmpty(query.getSchoolAddress())) {
		boolQuery.must(q -> q.match(m -> m.query(query.getSchoolAddress()).field("schools.address")));
	}



	// >> 过滤低分数据
	builder.minScore(0.5);

	// >> 配置搜索条件
	builder.query(q -> q.bool(boolQuery.build()));

	// >> 设置分页信息
	builder.from(query.getForm()).size(query.getSize());

	// >> 排序规则:若指定排序字段,score值将不计算。默认score排序
	/*SortOptions sortId = SortOptionsBuilders.field(f -> f.field("id").order(SortOrder.Asc));
	SortOptions sortName = SortOptionsBuilders.field(f -> f.field("name.keyword").order(SortOrder.Asc));
	builder.sort(sortId, sortName);*/

	// 查询数据
	SearchResponse<Staff> response = elasticsearchClient.search(builder.build(), Staff.class);


    // 打印信息
	TotalHits total = response.hits().total();
	boolean isExactResult = total.relation() == TotalHitsRelation.Eq;
	if (isExactResult) {
		System.out.println("There are " + total.value() + " results");
	} else {
		System.out.println("There are more than " + total.value() + " results");
	}

	List<Hit<Staff>> hits = response.hits().hits();
	for (Hit<Staff> hit: hits) {
		Staff staff = hit.source();
		System.out.println(JSON.toJSONString(staff));
		System.out.println("id= " + staff.getId() + ", name " + staff.getName() + ", score " + hit.score());
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值