本笔记写于2020年2月,使用的ES版本为7.5.2,SpringBoot的版本为2.2.4.RELEASE。在这个时间节点,ES官方推荐使用elasticsearch-rest-high-level-client作为ES的客户端访问工具。因此maven的pom文件中只需要添加以下依赖即可。
org.springframework.boot
spring-boot-starter-data-elasticsearch
@Configuration
public class ElasticSearchConfig {
private static final Logger log = LoggerFactory.getLogger(ElasticSearchConfig.class);
private static final int ADDRESS_LENGTH = 2;
private static final String HTTP_SCHEME = "http";
// ES的访问地址从配置文件中读入
@Value("${elasticsearch.ip}")
String[] ipAddress;
@Autowired
RestClientBuilder restClientBuilder;
@Bean
public RestClientBuilder restClientBuilder() {
HttpHost[] hosts = Arrays.stream(ipAddress)
.map(this::makeHttpHost)
.filter(Objects::nonNull)
.toArray(HttpHost[]::new);
return RestClient.builder(hosts);
}
@Bean(name = "highLevelClient")
public RestHighLevelClient highLevelClient(@Autowired RestClientBuilder restClientBuilder) {
//TODO 此处可以进行其它操作
return new RestHighLevelClient(restClientBuilder);
}
HttpHost makeHttpHost(String s) {
assert StringUtils.isNotEmpty(s);
String[] address = s.split(":");
if (address.length == ADDRESS_LENGTH) {
String ip = address[0];
int port = Integer.parseInt(address[1]);
log.info("ElasticSearch: " + ip + ":" + port);
return new HttpHost(ip, port, HTTP_SCHEME);
} else {
return null;
}
}
}
@Document(indexName = "item",type = "docs", shards = 5, replicas = 1)
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Item {
@Id
private Long id;
@Field(type = FieldType.Text, analyzer = "ik_max_word")
private String title; //标题
@Field(type = FieldType.Keyword)
private String category;// 分类
@Field(type = FieldType.Keyword)
private String brand; // 品牌
@Field(type = FieldType.Double)
private Double price; // 价格
//默认情况下分词,一般默认分词就好,除非这个字段你确定查询时不会用到
@Field(index = false, type = FieldType.Keyword)
private String images; // 图片地址
}
import com.example.demo.domain.Item;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
public interface ItemRepository extends ElasticsearchRepository<Item, Long> {
}
完成上述步骤之后,就可以在代码中读写ES了。
通过单元测试来实践创建索引和增删查改等常规操作。首先需要引入客户端等
@SpringBootTest
class ElasticSearchStudyApplicationTests {
@Autowired
private RestHighLevelClient highLevelClient;
@Autowired
private ItemRepository itemRepository;
…………………………其他代码…………………………
}
可以借助ElasticsearchRepository简化索引创建操作,在save某个实体之后会自动创建索引并写入数据。
@Test
public void addIndex() throws IOException {
Item it1 = new Item();
it1.setId(1L);
it1.setBrand("brand");
it1.setCategory("category");
it1.setTitle("title");
it1.setImages("images");
it1.setPrice(1.00);
// 使用Repository写入数据的时候会自动创建index和type
itemRepository.save(it1);
}
@Test
public void insertOrUpdateOne() {
// 构造记录
Item it1 = new Item();
it1.setId(3L);
it1.setBrand("品牌3");
it1.setCategory("种类3");
it1.setTitle("标题3");
it1.setImages("图片3");
it1.setPrice(3.00);
// 发送请求
IndexRequest request = new IndexRequest("item");// 指定index
request.type("docs");//指定type
request.id("3");// 指定id,如果不指定则是自动生成.如果指定了,记录存在则是更新
request.source(JSON.toJSONString(it1), XContentType.JSON);
try {
IndexResponse indexResponse = highLevelClient.index(request, RequestOptions.DEFAULT);
out.println(indexResponse);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Test
public void update() throws IOException {
// 模拟入参一个item
Item it1 = new Item();
it1.setId(3L);
it1.setBrand("品牌");
it1.setCategory("种类3");
it1.setTitle("标题3");
it1.setImages("图片3");
it1.setPrice(3.00);
UpdateRequest request = new UpdateRequest("item", "docs", "2");
request.doc(JSON.toJSONString(it1), XContentType.JSON);
UpdateResponse updateResponse = highLevelClient.update(request, RequestOptions.DEFAULT);
System.out.println("update: " + JSON.toJSONString(updateResponse));
}
提供id删除对应文档
/**
* 删除记录
*/
@Test
public void delete() throws IOException {
DeleteRequest deleteRequest = new DeleteRequest("item", "docs", "2");
DeleteResponse response = highLevelClient.delete(deleteRequest, RequestOptions.DEFAULT);
System.out.println("delete: " + JSON.toJSONString(response));
}
@Test
public void getByRepository() {
Iterable<Item> all = itemRepository.findAll();
// 格式化为普通的List返回
ArrayList<Item> items = Lists.newArrayList(all);
out.println(items);
}
@Test
public void getById() throws Exception {
GetRequest getRequest = new GetRequest("item", "docs", "1");
GetResponse getResponse = highLevelClient.get(getRequest, RequestOptions.DEFAULT);
Item item = JSON.parseObject(getResponse.getSourceAsString(), new TypeReference<Item>() {
});
out.println("get: " + JSON.toJSONString(getResponse));
out.println("转换成Item实体: " + item);
}
@Test
public void bulkAdd() throws IOException {
Item it1 = new Item(1L, "围城", "图书", "小说", 2.00, "image");
Item it2 = new Item(2L, "Java编程思想", "图书", "技术", 3.00, "image");
Item it3 = new Item(3L, "范特西", "音乐", "流行", 10.00, "image");
Item it4 = new Item(4L, "数据库设计", "图书", "技术", 15.00, "image");
Item it5 = new Item(5L, "华为手机", "数码", "华为", 11.00, "image");
List<Item> testsList = Lists.newArrayList(it1, it2, it3, it4, it5);
// 批量增加
BulkRequest bulkAddRequest = new BulkRequest();
for (int i = 0; i < testsList.size(); i++) {
Item tests = testsList.get(i);
IndexRequest indexRequest = new IndexRequest("item", "docs", tests.getId().toString());
indexRequest.source(JSON.toJSONString(tests), XContentType.JSON);
bulkAddRequest.add(indexRequest);
}
BulkResponse bulkAddResponse = highLevelClient.bulk(bulkAddRequest, RequestOptions.DEFAULT);
System.out.println("bulkAdd: " + JSON.toJSONString(bulkAddResponse));
}
@Test
public void bulkUpdate() throws IOException {
Item it1 = new Item(1L, "东方快车谋杀案", "图书", "小说", 2.00, "image");
Item it2 = new Item(2L, "Java编程思想", "图书", "技术", 3.00, "image");
Item it3 = new Item(3L, "范特西", "音乐", "流行", 10.00, "image");
Item it4 = new Item(4L, "数据库设计", "图书", "技术", 15.00, "image");
Item it5 = new Item(5L, "华为手机", "数码", "华为", 11.00, "image");
List<Item> testsList = Lists.newArrayList(it1, it2, it3, it4, it5);
// 批量更新
BulkRequest bulkUpdateRequest = new BulkRequest();
for (int i = 0; i < testsList.size(); i++) {
Item tests = testsList.get(i);
tests.setImages(tests.getImages() + "_updated");
UpdateRequest updateRequest = new UpdateRequest("item", "docs", tests.getId().toString());
updateRequest.doc(JSON.toJSONString(tests), XContentType.JSON);
bulkUpdateRequest.add(updateRequest);
}
BulkResponse bulkUpdateResponse = highLevelClient.bulk(bulkUpdateRequest, RequestOptions.DEFAULT);
System.out.println("bulkUpdate: " + JSON.toJSONString(bulkUpdateResponse));
}
@Test
public void bulkDelete() throws IOException {
List<Item> testsList = new ArrayList<>();
// 批量删除
BulkRequest bulkDeleteRequest = new BulkRequest();
for (int i = 0; i < testsList.size(); i++) {
Item tests = testsList.get(i);
DeleteRequest deleteRequest = new DeleteRequest("item", "docs", tests.getId().toString());
bulkDeleteRequest.add(deleteRequest);
}
BulkResponse bulkDeleteResponse = highLevelClient.bulk(bulkDeleteRequest, RequestOptions.DEFAULT);
System.out.println("bulkDelete: " + JSON.toJSONString(bulkDeleteResponse));
}
/**
* 查询
*/
@Test
public void search() throws IOException {
BoolQueryBuilder boolBuilder = QueryBuilders.boolQuery();
// 这里可以根据字段进行搜索,must表示符合条件的,相反的mustnot表示不符合条件的
boolBuilder.should(QueryBuilders.matchQuery("title", "Java"));
boolBuilder.should(QueryBuilders.matchQuery("brand", "技术"));
// boolBuilder.must(QueryBuilders.matchQuery("id", tests.getId().toString()));
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
sourceBuilder.query(boolBuilder);
// 分页
sourceBuilder.from(0);
sourceBuilder.size(100); // 获取记录数,默认10
// 第一个是获取字段,第二个是过滤的字段,默认获取全部
//sourceBuilder.fetchSource(new String[] { "id", "name" }, new String[] {});
SearchRequest searchRequest = new SearchRequest("item");
searchRequest.types("docs");
searchRequest.source(sourceBuilder);
SearchResponse response = highLevelClient.search(searchRequest, RequestOptions.DEFAULT);
System.out.println("search: " + JSON.toJSONString(response));
SearchHits hits = response.getHits();
SearchHit[] searchHits = hits.getHits();
for (SearchHit hit : searchHits) {
System.out.println("search -> " + hit.getSourceAsString());
}
}