在Elasticsearch中,为java提供了2种客户端,一种是REST风格的客户端,另一种是Java API的客户端。 https://www.elastic.co/guide/...
1.REST客户端
Elasticsearch提供了2种REST客户端,一种是低级客户端,一种是高级客户端。
2.构造数据
curl -X POST "http://47.101.129.45:9200/test/house/_bulk?pretty" -H 'Content-Type: application/json' --data-binary ' {"index":{"_index":"test","_type":"house"}} {"id":"1001","title":"整租 · 南丹大楼 1居室 7500","price":"7500"} {"index":{"_index":"test","_type":"house"}} {"id":"1002","title":"陆家嘴板块,精装设计一室一厅,可拎包入住诚意租。","price":"8500"} {"index":{"_index":"test","_type":"house"}} {"id":"1003","title":"整租 · 健安坊 1居室 4050","price":"7500"} {"index":{"_index":"test","_type":"house"}} {"id":"1004","title":"整租 · 中凯城市之光+视野开阔+景色秀丽+拎包入住","price":"6500"} {"index":{"_index":"test","_type":"house"}} {"id":"1005","title":"整租 · 南京西路品质小区 21213三轨交汇配套齐* 拎包入住","price":"6000"} {"index":{"_index":"test","_type":"house"}} {"id":"1006","title":"祥康里简约风格 *南户型拎包入住看房随时","price":"7000"} '
3.REST低级客户端
1)用IDEA创建SpringBoot工程spring-elasticsearch
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.0.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example</groupId> <artifactId>elasticsearch</artifactId> <version>0.0.1-SNAPSHOT</version> <name>elasticsearch</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> <dependency> <groupId>org.elasticsearch.client</groupId> <artifactId>elasticsearch-rest-client</artifactId> <version>6.5.4</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.4</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
2)编写测试
/** * REST低级客户端 */ public class TestElasticSearch { private static final ObjectMapper MAPPER = new ObjectMapper(); private RestClient restClient; @Before public void init() { RestClientBuilder restClientBuilder = RestClient.builder( new HttpHost("47.101.129.45", 9200, "http")); restClientBuilder.setFailureListener(new RestClient.FailureListener() { @Override public void onFailure(Node node) { System.out.println("出错了 -> " + node); } }); this.restClient = restClientBuilder.build(); } @After public void after() throws IOException { restClient.close(); } /** * 查询集群状态 * * @throws IOException */ @Test public void testGetInfo() throws IOException { Request request = new Request("GET", "/_cluster/state"); request.addParameter("pretty", "true"); Response response = this.restClient.performRequest(request); System.out.println(response.getStatusLine()); System.out.println(EntityUtils.toString(response.getEntity())); } /** * 新增数据 * * @throws IOException */ @Test public void testCreateData() throws IOException { Request request = new Request("POST", "/test/house"); request.addParameter("pretty", "true"); Map<String, Object> data = new HashMap<>(); data.put("id", "2001"); data.put("title", "张江高科"); data.put("price", "3500"); request.setJsonEntity(MAPPER.writeValueAsString(data)); Response response = this.restClient.performRequest(request); System.out.println(response.getStatusLine()); System.out.println(EntityUtils.toString(response.getEntity())); } /** * 根据id查询数据 */ @Test public void testQueryData() throws IOException { Request request = new Request("GET", "/test/house/3xNNOW4BpJzEX51okOM5"); request.addParameter("pretty", "true"); Response response = this.restClient.performRequest(request); System.out.println(response.getStatusLine()); System.out.println(EntityUtils.toString(response.getEntity())); } /** * 搜索数据 */ @Test public void testSearchData() throws IOException { Request request = new Request("POST", "/test/house/_search"); String searchJson = "{/"query/": {/"match/": {/"title/": /"拎包入住/"}}}"; request.setJsonEntity(searchJson); request.addParameter("pretty", "true"); Response response = this.restClient.performRequest(request); System.out.println(response.getStatusLine()); System.out.println(EntityUtils.toString(response.getEntity())); } }
从使用中,可以看出,基本和我们使用RESTful api使用几乎是一致的
4.REST高级客户端
pom.xml引入依赖
<dependency> <groupId>org.elasticsearch.client</groupId> <artifactId>elasticsearch-rest-high-level-client</artifactId> <version>6.5.4</version> </dependency>
编写测试
/** * REST高级客户端 */ public class TestRestHighLevel { private RestHighLevelClient client; @Before public void init() { RestClientBuilder restClientBuilder = RestClient.builder( new HttpHost("47.101.129.45", 9200, "http") ); this.client = new RestHighLevelClient(restClientBuilder); } @After public void after() throws Exception { this.client.close(); } /** * 新增文档,同步操作 * * @throws Exception */ @Test public void testCreate() throws Exception { Map<String, Object> data = new HashMap<>(); data.put("id", "2002"); data.put("title", "南京西路 拎包入住 一室一厅"); data.put("price", "4500"); IndexRequest indexRequest = new IndexRequest("test", "house").source(data); IndexResponse indexResponse = this.client.index(indexRequest, RequestOptions.DEFAULT); System.out.println(indexResponse); System.out.println("id->" + indexResponse.getId()); System.out.println("index->" + indexResponse.getIndex()); System.out.println("type->" + indexResponse.getType()); System.out.println("version->" + indexResponse.getVersion()); System.out.println("result->" + indexResponse.getResult()); System.out.println("shardInfo->" + indexResponse.getShardInfo()); } /** * 新增文档,异步操作 */ @Test public void testCreateAsync() throws Exception { Map<String, Object> data = new HashMap<>(); data.put("id", "2003"); data.put("title", "南京东路最新房源二室一厅"); data.put("price", "5500"); IndexRequest indexRequest = new IndexRequest("test", "house").source(data); this.client.indexAsync(indexRequest, RequestOptions.DEFAULT, new ActionListener<IndexResponse>() { @Override public void onResponse(IndexResponse indexResponse) { System.out.println(indexResponse); } @Override public void onFailure(Exception e) { System.out.println(e); } }); Thread.sleep(2000); } /** * 指定返回字段查询 */ @Test public void testQuery() throws Exception { GetRequest request = new GetRequest("test", "house", "4hN-OW4BpJzEX51oe-Of"); //指定返回字段 String[] includes = new String[]{"title", "id"}; String[] excludes = Strings.EMPTY_ARRAY; FetchSourceContext fetchSourceContext = new FetchSourceContext(true, includes, excludes); request.fetchSourceContext(fetchSourceContext); GetResponse response = this.client.get(request, RequestOptions.DEFAULT); System.out.println("数据 -> " + response); } /** * 判断是否存在 */ @Test public void testExists() throws Exception { GetRequest getRequest = new GetRequest("test", "house", "4hN-OW4BpJzEX51oe-Of"); //不返回字段 getRequest.fetchSourceContext(new FetchSourceContext(false)); boolean exists = this.client.exists(getRequest, RequestOptions.DEFAULT); System.out.println("exists -> " + exists); } /** * 删除数据 */ @Test public void testDelete() throws Exception { DeleteRequest deleteRequest = new DeleteRequest("test", "house", "4hN-OW4BpJzEX51oe-Of"); DeleteResponse response = this.client.delete(deleteRequest, RequestOptions.DEFAULT); System.out.println(response.status());// OK or NOT_FOUND } /** * 更新数据 */ @Test public void testUpdate() throws Exception { UpdateRequest updateRequest = new UpdateRequest("test", "house", "4BN4OW4BpJzEX51o3-PZ"); Map<String, Object> data = new HashMap<>(); data.put("title", "南京西路2 一室一厅2"); data.put("price", "4000"); updateRequest.doc(data); UpdateResponse response = this.client.update(updateRequest, RequestOptions.DEFAULT); System.out.println("version -> " + response.getVersion()); } /** * 查询数据 */ @Test public void testSearch() throws Exception { SearchRequest searchRequest = new SearchRequest("test"); searchRequest.types("house"); SearchSourceBuilder sourceBuilder = new SearchSourceBuilder(); sourceBuilder.query(QueryBuilders.matchQuery("title", "拎包入住")); sourceBuilder.from(0); sourceBuilder.size(5); sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS)); searchRequest.source(sourceBuilder); SearchResponse search = this.client.search(searchRequest, RequestOptions.DEFAULT); System.out.println("搜索到->" + search.getHits().totalHits + "条数据"); SearchHits hits = search.getHits(); for (SearchHit hit : hits) { System.out.println(hit.getSourceAsString()); } } }
Spring Data项目对Elasticsearch做了支持,其目的就是简化对Elasticsearch的操作, https://spring.io/projects/sp... 。
1.导入依赖
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.0.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example</groupId> <artifactId>elasticsearch</artifactId> <version>0.0.1-SNAPSHOT</version> <name>elasticsearch</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> <dependency> <groupId>org.elasticsearch.client</groupId> <artifactId>elasticsearch-rest-client</artifactId> <version>6.5.4</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.4</version> </dependency> <!--REST高级客户端--> <dependency> <groupId>org.elasticsearch.client</groupId> <artifactId>elasticsearch-rest-high-level-client</artifactId> <version>6.5.4</version> </dependency> <!--SpringBoot整合--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-elasticsearch</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
2.编写application.yml
spring: application: name: spring-elasticsearch data: elasticsearch: cluster-name: docker-cluster cluster-nodes: 47.101.129.45:9300
这里要注意,使用的端口是9300,而并非9200,原因是9200是RESTful端口,9300是API端口。
3.编写测试
@Data @AllArgsConstructor @NoArgsConstructor @Document(indexName = "demo", type = "person", createIndex = false) public class Person { /** * 1.索引库(indices) indices是index的复数,代表许多的索引, * 2.类型(type) 类型是模拟mysql中的table概念,一个索引库下可以有不同类型的索引,比如商品索引,订单索引,其数据格式不同。不过这会导致索引库混乱,因此未来版本中会移除这个概念 * 3.文档(document) 存入索引库原始的数据。比如每一条商品信息,就是一个文档 * 4.字段(field) 文档中的属性 * 5.映射配置(mappings) 字段的数据类型、属性、是否索引、是否存储等特性 */ /** * @Document 作用在类,标记实体类为文档对象,一般有两个属性 * 1.indexName:对应索引库名称 * 2.type:对应在索引库中的类型 * 3.shards:分片数量,默认5 * 4.replicas:副本数量,默认1 * @Id 作用在成员变量,标记一个字段作为id主键 * @Field 作用在成员变量,标记为文档的字段,并指定字段映射属性: * 1.type:字段类型,是枚举:FieldType,可以是text、long、short、date、integer、object等 * 2.text:存储数据时候,会自动分词,并生成索引 * 3.keyword:存储数据时候,不会分词建立索引 * 4.Numerical:数值类型,分两类 * 基本数据类型:long、interger、short、byte、double、float、half_float * 浮点数的高精度类型:scaled_float * 需要指定一个精度因子,比如10或100。elasticsearch会把真实值乘以这个因子后存储,取出时再还原。 * 5.Date:日期类型 * elasticsearch可以对日期格式化为字符串存储,但是建议我们存储为毫秒值,存储为long,节省空间。 * 6.index:是否索引,布尔类型,默认是true * 7.store:是否存储,布尔类型,默认是false * 8.analyzer:分词器名称,这里的ik_max_word即使用ik分词器 */ @Id private Long id; @Field(store = true) private String name; @Field private Integer age; @Field private String mail; @Field(store = true) private String hobby; }
1)新增数据
/** * Spring Data ElasticSearch */ @RunWith(SpringRunner.class) @SpringBootTest public class TestSpringBootES { @Autowired private ElasticsearchTemplate elasticsearchTemplate; /** * 添加数据 */ @Test public void save() { User user = new User(); user.setId(1001L); user.setName("赵柳"); user.setAge(20); user.setHobby("足球、篮球、听音乐"); IndexQuery indexQuery = new IndexQueryBuilder() .withObject(user).build(); String index = this.elasticsearchTemplate.index(indexQuery); System.out.println(index); } }
2)批量插入
@Test public void testBulk() { List list = new ArrayList<>(); for (int i = 0; i < 5000; i++) { User person = new User(); person.setId(1001L + i); person.setAge(i % 50 + 10); person.setName("张三" + i); person.setHobby("足球、篮球、听音乐"); IndexQuery indexQuery = new IndexQueryBuilder().withObject(person).build(); list.add(indexQuery); } Long start = System.currentTimeMillis(); this.elasticsearchTemplate.bulkIndex(list); System.out.println("用时:" + (System.currentTimeMillis() - start)); }
3)局部更新,全部更新使用index覆盖即可
@Test public void testUpdate() { IndexRequest indexRequest = new IndexRequest(); indexRequest.source("age", "30"); UpdateQuery updateQuery = new UpdateQueryBuilder() .withId("1002") .withClass(User.class) .withIndexRequest(indexRequest).build(); UpdateResponse response = this.elasticsearchTemplate.update(updateQuery); System.out.println(response); }
4)删除
@Test public void testDelete() { String result = this.elasticsearchTemplate.delete(User.class, "1002"); System.out.println(result); }
5)查询
@Test public void testSearch() { PageRequest pageRequest = PageRequest.of(0, 10);//设置分页参数 SearchQuery searchQuery = new NativeSearchQueryBuilder() .withQuery(QueryBuilders.matchQuery("name", "赵柳"))//match查询 .withPageable(pageRequest) .build(); AggregatedPage<User> persons = this.elasticsearchTemplate.queryForPage(searchQuery, User.class); System.out.println("persons ->" + persons); System.out.println("总页数:" + persons.getTotalPages()); //获取总页数 List<User> content = persons.getContent();// 获取搜索到的数据 for (User p : content) { System.out.println(p); } }
3.编写测试
1)创建实体Pojo
import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.data.annotation.Id; import org.springframework.data.elasticsearch.annotations.Document; import org.springframework.data.elasticsearch.annotations.Field; import org.springframework.data.elasticsearch.annotations.FieldType; @Data @AllArgsConstructor @NoArgsConstructor @Document(indexName = "commodity", type = "docs", shards = 1, replicas = 0) public class Commodity { @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; // 图片地址 }
2)继承ElasticsearchRepository
import com.example.elasticsearch.pojo.Commodity; import org.springframework.data.elasticsearch.repository.ElasticsearchRepository; import java.util.List; public interface CommodityRepository extends ElasticsearchRepository<Commodity, Long> { }
3)测试
@RunWith(SpringRunner.class) @SpringBootTest public class TestSpringBootES2 { @Resource private CommodityRepository commodityRepository; /** * 创建索引 */ @Test public void createIndex() { boolean index = elasticsearchTemplate.createIndex(Commodity.class); System.out.println(index); } /** * 添加数据 */ @Test public void testInsert() { Commodity commodity = new Commodity(1L, "小米手机7", " 手机", "小米", 3499.00, "http://image.baidu.com/13123.jpg"); Commodity save = commodityRepository.save(commodity); System.out.println(save); } }