使用步骤
1.环境准备
用的是windows版,自行下载
链接: 下载地址
2.针对索引操作
这里是kibana上操作的(也可以用postman操作):
#创建索引,指定文档id PUT /test1/type1/1 { "name":"张三", "age":30 } #创建索引规则(类似数据库建表) PUT /test2 { "mappings": { "properties": { "name":{ "type":"text" }, "age":{ "type": "integer" }, "birthday":{ "type": "date" } } } } #获取索引的信息,properties类型 GET test2 #创建索引,properties不指定类型会有默认类型 #也可以用作修改,但是必须写上全部字段,不然会丢失未写字段 PUT /test3/_doc/1 { "name":"张三", "age":30, "birth":"1991-06-23" } GET test3 #查看es健康状态 GET _cat/health #查看所有索引状态 GET _cat/indices?v #修改 POST /test3/_doc/1/_update { "doc":{ "name":"李四" } }
3.针对doc操作(增删改)
代码如下(示例):
#新增索引,并添加doc POST /chen/user/1 { "name":"张三", "age":11, "desc":"一顿操作猛如虎,一看工资2500", "tags":["技术宅","温暖","直男"] } POST /chen来源gaodai$ma#com搞$$代**码网/user/2 { "name":"李四", "age":12, "desc":"憨批", "tags":["渣男","旅游","交友"] } POST /chen/user/3 { "name":"王五", "age":13, "desc":"瓜怂", "tags":["靓女","旅游","美食"] } POST /chen/user/4 { "name":"刘六", "age":14, "desc":"锅盔", "tags":["衰仔","旅游","美食"] } #获取数据 GET chen/user/1 #更新数据 POST chen/user/1/_update { "doc":{ "name":"更新" } } #删除 DELETE chen/user/1 #条件查询,匹配度越高,_score(分值)越高 GET chen/user/_search?q=name:李 GET chen/user/_search?q=name:李四 #等价于上面 GET chen/user/_search { "query": { "match": { "name": "李四" } } }
4.针对doc操作(查)
查询1(示例):
#_source结果过滤(指定需要字段结果集) #sort排序 #from-size分页(类似limit ) #注意:这个查询是不可以些多个字段的(我试过了) GET chen/user/_search { "query": { "match": { "name": "李四" } }, "_source": ["name","age"], "sort": [ { "age": { "order": "asc" } } ], "from":0, "size":1 } #多条件精确查询 #以下都是bool的二级属性 #must:必须 #should,满足任意条件 #must_not,表示不满足 GET chen/user/_search { "query": { "bool": { "must": [ {"match": { "name": "李四" }}, {"match": { "age": 11 }} ] } } } #过滤.注意filter是bool(多条件)的二级属性 GET chen/user/_search { "query": { "bool": { "must": [ {"match": { "name": "李四" }} ], "filter": { "range": { "age": { "gte": 10, "lte": 20 } } } } } } #分词器依然有效 #多个条件空格隔开就行,只要满足其中一个,就会被逮到 GET chen/user/_search { "query": { "match": { "tags": "男 技术" } } } #精确查询,结果只能为1,多条直接不显示 GET chen/user/_search { "query": { "term": { "name": "李四" } } }
查询2(示例):
#新建索引 PUT test4 { "mappings": { "properties": { "name":{ "type": "text" }, "desc":{ "type": "keyword" } } } } #插入数据 PUT test4/_doc/1 { "name":"张三name", "desc":"张三desc" } PUT test4/_doc/2 { "name":"张三name2", "desc":"张三desc2" } #分词器查询(并不是查询索引里的数据,而是将text的内容用分词器拆分的结果) GET _analyze { "analyzer": "keyword", "text": ["张三name"] } GET _analyze { "analyzer": "standard", "text": "张三name" } GET test4/_search { "query": { "term": { "name": "张" } } } #==keyword不会被分词器解析== GET test4/_search { "query": { "term": { "desc": "张三desc" } } }
查询3(示例):
PUT test4/_doc/3 { "t1":"22", "t2":"2020-4-6" } PUT test4/_doc/4 { "t1":"33", "t2":"2020-4-7" } #精确查询多个值 GET test4/_search { "query": { "bool": { "should": [ { "term": { "t1": "22" } }, { "term": { "t1": "33" } } ] } } } #highlight:高亮 #pre_tags,post_tags:自定义高亮条件,前缀后缀 GET chen/user/_search { "query": { "match": { "name": "李四" } }, "highlight": { "pre_tags": "", "fields": { "name":{} } } }
5.java-api
索引操作:
public class ES_Index { private static final String HOST_NAME = "localhost"; private static final Integer PORT = 9200; private static RestHighLevelClient client; //创建ES客户端 static { RestClientBuilder restClientBuilder = RestClient.builder(new HttpHost(HOST_NAME, PORT)); client = new RestHighLevelClient(restClientBuilder); } //关闭ES客户端 public void close() { if (null != client) { try { client.close(); } catch (IOException e) { e.printStackTrace(); } } } //创建索引 public void addIndex() throws IOException { //创建索引 CreateIndexRequest request = new CreateIndexRequest("chen"); CreateIndexResponse respOnse= client.indices().create(request, RequestOptions.DEFAULT); //响应状态 System.out.println("索引创建操作: " + response.isAcknowledged()); } //查询索引 public void selectIndex() throws IOException { GetIndexRequest request = new GetIndexRequest("chen"); GetIndexResponse respOnse= client.indices().get(request, RequestOptions.DEFAULT); System.out.println("索引查询操作: " +response.getAliases()); System.out.println("索引查询操作: " +response.getMappings()); System.out.println("索引查询操作: " +response.getSettings()); } //删除索引 public void deleteIndex() throws IOException { DeleteIndexRequest request = new DeleteIndexRequest("chen"); AcknowledgedResponse respOnse= client.indices().delete(request, RequestOptions.DEFAULT); System.out.println("索引删除操作: "+response.isAcknowledged()); } public static void main(String[] args) throws IOException { ES_Index index=new ES_Index(); //index.addIndex(); //index.selectIndex(); index.deleteIndex(); index.close(); } }
文档操作:
public class ES_Doc { private static final String HOST_NAME = "localhost"; private static final Integer PORT = 9200; private static RestHighLevelClient client; //创建ES客户端 static { RestClientBuilder restClientBuilder = RestClient.builder(new HttpHost(HOST_NAME, PORT)); client = new RestHighLevelClient(restClientBuilder); } //关闭ES客户端 public void close() { if (null != client) { try { client.close(); } catch (IOException e) { e.printStackTrace(); } } } //插入数据 public void addDoc() throws IOException { IndexRequest request = new IndexRequest(); User user = new User("张三", "男", 18); //向es插入数据,必须将数据转换为json格式 String userJson = new ObjectMapper().writeValueAsString(user); request.index("user").id("1001").source(userJson, XContentType.JSON); IndexResponse respOnse= client.index(request, RequestOptions.DEFAULT); System.out.println("文档创建操作: " + response.getResult()); } //修改数据(局部修改) public void updateDoc() throws IOException { UpdateRequest request = new UpdateRequest(); request.index("user").id("1001").doc(XContentType.JSON, "sex", "女"); UpdateResponse respOnse= client.update(request, RequestOptions.DEFAULT); System.out.println("文档修改操作: " + response.getResult()); } //获取数据 public void getDoc() throws IOException { GetRequest request = new GetRequest(); request.index("user").id("1001"); GetResponse respOnse= client.get(request, RequestOptions.DEFAULT); User user = new ObjectMapper().readValue(response.getSourceAsString(), User.class); System.out.println("文档获取操作: " + user); } //删除数据 public void deleteDoc() throws IOException { DeleteRequest request = new DeleteRequest(); request.index("user").id("1001"); DeleteResponse respOnse= client.delete(request, RequestOptions.DEFAULT); System.out.println("文档删除操作: " + response.getResult()); } //批量插入数据 public void addBatch() throws IOException { BulkRequest request = new BulkRequest(); request.add(new IndexRequest().index("user").id("1001").source(XContentType.JSON, "name", "张三", "sex", "男", "age", 10)); request.add(new IndexRequest().index("user").id("1002").source(XContentType.JSON, "name", "李四", "sex", "男", "age", 20)); request.add(new IndexRequest().index("user").id("1003").source(XContentType.JSON, "name", "王五", "sex", "女", "age", 30)); request.add(new IndexRequest().index("user").id("1004").source(XContentType.JSON, "name", "赵六", "sex", "男", "age", 40)); request.add(new IndexRequest().index("user").id("1005").source(XContentType.JSON, "name", "孙七", "sex", "女", "age", 50)); BulkResponse respOnse= client.bulk(request, RequestOptions.DEFAULT); System.out.println("文档批量新增操作: " + response.getTook()); System.out.println("文档批量新增操作: " + !response.hasFailures());//是否失败 } //批量删除数据 public void deleteBatch() throws IOException { BulkRequest request = new BulkRequest(); request.add(new DeleteRequest().index("user").id("1001")); request.add(new DeleteRequest().index("user").id("1002")); request.add(new DeleteRequest().index("user").id("1003")); request.add(new DeleteRequest().index("user").id("1004")); request.add(new DeleteRequest().index("user").id("1005")); BulkResponse respOnse= client.bulk(request, RequestOptions.DEFAULT); System.out.println("文档批量删除操作: " + response.getTook()); System.out.println("文档批量删除操作: " + !response.hasFailures());//是否失败 } //查询(重点) public void searchDoc() throws IOException { SearchRequest request = new SearchRequest(); request.indices("user"); //1.查询索引中的全部数据 //request.source(new SearchSourceBuilder().query(QueryBuilders.matchAllQuery())); //2.查询年龄为30的数据 //request.source(new SearchSourceBuilder().query(QueryBuilders.termQuery("age", 30))); //3.分页查询,当前第0页,每页两条 //request.source(new SearchSourceBuilder().query(QueryBuilders.matchAllQuery()).from(0).size(2)); //4.排序,倒序 //request.source(new SearchSourceBuilder().query(QueryBuilders.matchAllQuery()).sort("age", SortOrder.DESC)); //5.过滤字段(排除和包含,也可以是数组) //request.source(new SearchSourceBuilder().fetchSource("name", null)); //6.组合查询 //BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery(); //6.1 must相当于and //boolQueryBuilder.must(QueryBuilders.matchQuery("age", 30)); //boolQueryBuilder.must(QueryBuilders.matchQuery("sex", "女")); //6.2 should相当于or //boolQueryBuilder.should(QueryBuilders.matchQuery("age", 30)); //boolQueryBuilder.should(QueryBuilders.matchQuery("sex", "女")); //request.source(new SearchSourceBuilder().query(boolQueryBuilder)); //7.范围查询 //request.source(new SearchSourceBuilder().query(QueryBuilders.rangeQuery("age").gte(30).lte(40))); //8.模糊查询Fuzziness.ONE即只差1个字符 //request.source(new SearchSourceBuilder().query(QueryBuilders.fuzzyQuery("name", "王五").fuzziness(Fuzziness.ONE))); //9.高亮显示 //SearchSourceBuilder builder = new SearchSourceBuilder().query(QueryBuilders.matchPhraseQuery("name", "张三")); //builder.highlighter(new HighlightBuilder().preTags("").postTags("").field("name")); //request.source(builder); //10.聚合查询 //SearchSourceBuilder builder = new SearchSourceBuilder(); //MaxAggregationBuilder aggregatiOnBuilder= AggregationBuilders.max("maxAge").field("age"); //builder.aggregation(aggregationBuilder); //request.source(builder); //11.分组查询 SearchSourceBuilder builder = new SearchSourceBuilder(); TermsAggregationBuilder aggregatiOnBuilder= AggregationBuilders.terms("ageGroup").field("age"); builder.aggregation(aggregationBuilder); request.source(builder); SearchResponse respOnse= client.search(request, RequestOptions.DEFAULT); SearchHits hits = response.getHits(); System.out.println("--条数: " + hits.getTotalHits()); System.out.println("--用时: " + response.getTook()); hits.forEach((item)->{ System.out.println("--数据: " + item.getSourceAsString()); }); } public static void main(String[] args) throws IOException { ES_Doc doc = new ES_Doc(); //doc.addDoc(); //doc.updateDoc(); //doc.getDoc(); //doc.deleteDoc(); //doc.addBatch(); //doc.deleteBatch(); doc.searchDoc(); doc.close(); } }
6.spring-data-elasticsearch
实体类: [email protected]@Field注解
shards 代表分片
replicas 代表副本
@Data @NoArgsConstructor @AllArgsConstructor @Document(indexName = "product", shards = 3, replicas = 1) public class Product { @Id private Long id;//商品唯一标识 @Field(type = FieldType.Text) private String title;//商品名称 @Field(type = FieldType.Keyword) private String category;//分类名称 @Field(type = FieldType.Double) private Double price;//商品价格 @Field(type = FieldType.Keyword,index = false) private String images;//图片地址 }
dao层: 这样就已经可以了,类似mybatis-plus的BaseMapper,封装好了一些操作
@Repository public interface ProductDao extends ElasticsearchRepository { }
yaml :不用怎么配置,默认就去找localhost:9200
测试 :不知道为啥dao的很多方法都过时了,看源码注释让回去用elasticsearchRestTemplate,感觉更繁琐
@SpringBootTest class ElasticsearchApplicationTests { @Autowired ElasticsearchRestTemplate elasticsearchRestTemplate; @Autowired ProductDao productDao; @Test void createIndex() { //创建索引,系统初始化会自动创建索引 System.out.println("创建索引"); } @Test void deleteIndex() { //创建索引,系统初始化会自动创建索引 boolean flg = elasticsearchRestTemplate.deleteIndex(Product.class); System.out.println("删除索引 = " + flg); } //新增数据 @Test void addDoc() { Product product = new Product(); product.setId(1001L); product.setTitle("华为手机"); product.setCategory("手机"); product.setPrice(2999.0); product.setImages("www.huawei.com"); productDao.save(product); } //修改 @Test void updateDoc() { Product product = new Product(); product.setId(1001L); product.setTitle("小米手机"); product.setCategory("手机"); product.setPrice(4999.0); product.setImages("www.xiaomi.com"); productDao.save(product); } //根据 id 查询 @Test void findById() { Product product = productDao.findById(1001L).get(); System.out.println(product); } //查询所有 @Test void findAll() { Iterable products = productDao.findAll(); for (Product product : products) { System.out.println(product); } } //删除 @Test public void delete() { productDao.deleteById(1001L); } //批量新增 @Test public void saveAll() { List productList = new ArrayList(); for (int i = 0; i <10; i++) { Product product = new Product(); product.setId((long) i); product.setTitle("[" + i + "]小米手机"); product.setCategory("手机"); product.setPrice(1999.0 + i); product.setImages("http://www.atguigu/xm.jpg-600"); productList.add(product); } productDao.saveAll(productList); } //分页查询 @Test void findByPageable() { Sort orders = Sort.by(Sort.Direction.DESC, "id"); Pageable pageable = PageRequest.of(0, 5, orders); Page products = productDao.findAll(pageable); products.forEach(System.out::println); } /** * term 查询 * search(termQueryBuilder) 调用搜索方法,参数查询构建器对象 */ @Test void termQuery() { TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("category", "手机"); Iterable products = productDao.search(termQueryBuilder); products.forEach(System.out::println); } /** * term 查询加分页 */ @Test void termQueryByPage() { PageRequest pageRequest = PageRequest.of(0, 5); TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("category", "手机"); Iterable products = productDao.search(termQueryBuilder, pageRequest); products.forEach(System.out::println); } }