文章目录
1、前言
2、es配置
3、Maven配置
4、springboot配置
5、创建表(通过json格式文件)
6、添加单条记录
7、批量添加记录
8、更新单条记录
9、通过id获取记录
10、通过id删除记录
11、分页查询(多条件情况)
1、前言
踩了好多坑,弄了一个通宵终于搞定了。有问题可以给我留言。
elasticsearch-analysis-ik-8.2.3 分词器下载地址 (注意:分词器和es需要版本一致)
查看文档配置【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());
}
}