在我们熟悉了 es 的基本rest 的操作之后,我们将使用SpringBoot进行整合,进一步熟悉Java API的相关操作。

1.创建一个标准的Springboot项目,引入Boot相关依赖之后,还需要导入依赖(与es服务端版本需要保持一致):

<dependency><groupId>org.elasticsearch.client</groupId><artifactId>transport</artifactId><version>6.5.1</version>
</dependency>

2.注入比要的配置类,这里注意要新建一个 classpath:es-config.properties:

@Component
@PropertySource("classpath:es-config.properties")
@Data
public class EsConfig {//集群名称@Value("${es.cluster.name}")private String clusterName;// master ip@Value("${es.host.ip}")private String ip;//master port@Value("${es.host.port}")private int port;
}
@Configuration
public class SearchConfig {@AutowiredEsConfig esConfig;@Beanpublic TransportClient client() throws UnknownHostException {InetSocketTransportAddress node = new InetSocketTransportAddress(InetAddress.getByName(esConfig.getIp()),esConfig.getPort());Settings settings = Settings.builder().put("cluster.name", esConfig.getClusterName()).build();TransportClient client = new PreBuiltTransportClient(settings);client.addTransportAddress(node);return client;}
}

3.创建针对es的增删改服务类,我们将其想象为一个数据库,这样子能优化我们的理解:

@Service
public class BookService {private String indexName = "book"; //相当于数据库名称private String indexType = "technology"; //相当于数据表名称@Autowiredprivate TransportClient client;public GetResponse getById(String id) {return this.client.prepareGet(indexName, indexType, id).get();}// 增加public IndexResponse add(String name, Double price, String publicationDate) throws Exception {XContentBuilder content = XContentFactory.jsonBuilder().startObject().field("name", name).field("price", price).field("publication_date", publicationDate).endObject();IndexResponse response = this.client.prepareIndex(indexName, indexType).setSource(content).get();return response;}// 删除public DeleteResponse remove(String id) {return this.client.prepareDelete(indexName, indexType, id).get();}//修改public UpdateResponse modify(String id, String name, Double price) throws Exception {UpdateRequest request = new UpdateRequest(indexName, indexType, id);XContentBuilder builder = XContentFactory.jsonBuilder().startObject();if (name != null) {builder.field("name", name);}if (price != null) {builder.field("price", price);}builder.endObject();request.doc(builder);return this.client.update(request).get();}
}

  这样子就完成最基本的增删改的操作服务,那么还有个查询呢?那么接下去我们采用一个简单的搜索附近的人的例子来理解一下查询的流程:

1.定义实体:

@Data
public class People {private Double lat;        //纬度private Double lon;        //经度private String wxNo;    //微信号private String nickName;//昵称private String sex;        //性别public People(String wxNo, String nickName, String sex, Double lat, Double lon) {this.wxNo = wxNo;this.nickName = nickName;this.sex = sex;this.lat = lat;this.lon = lon;}
}

2.由于属性均为随机生成,这里提供一个随机数工具类:

public class RandomUtil {private static Random random = new Random();private static final char[] sexs = "男女".toCharArray();private static final char[] wxNo = "abcdefghijklmnopqrstuvwxyz0123456789".toLowerCase().toCharArray();private static final char[] firstName = "赵钱孙李周吴郑王冯陈卫蒋沈韩杨朱秦许何吕施张孔曹严金魏陶姜谢邹窦章苏潘葛范彭谭夏胡".toCharArray();//确保车牌号不重复,声明一个缓存区private static Set<String> wxNoCache;/*** 随机生成性别** @return*/public static String randomSex() {int i = random.nextInt(sexs.length);return ("" + sexs[i]);}/*** 随机生成微信号** @return*/public static String randomWxNo() {//初始化缓冲区openCache();//微信号自动生成规则,wx_开头加上10位数字字组合StringBuffer sb = new StringBuffer();for (int c = 0; c < 10; c++) {int i = random.nextInt(wxNo.length);sb.append(wxNo[i]);}String carNum = ("wx_" + sb.toString());//为了防止微信号重复,生成以后检查一下//如果重复,递归重新生成,直到不重复为止if (wxNoCache.contains(carNum)) {return randomWxNo();}wxNoCache.add(carNum);return carNum;}/*** 随机生成坐标*/public static double[] randomPoint(double myLat, double myLon) {//随机生成一组附近的坐标double s = random.nextDouble();//格式化保留6位小数DecimalFormat df = new DecimalFormat("######0.000000");String slon = df.format(s + myLon);String slat = df.format(s + myLat);Double dlon = Double.valueOf(slon);Double dlat = Double.valueOf(slat);return new double[]{dlat, dlon};}/*** 随机生成微信名称** @return*/public static String randomNickName(String sex) {int i = random.nextInt(firstName.length);return firstName[i] + ("男".equals(sex) ? "先生" : "女士");}/*** 开启缓存区*/public static void openCache() {if (wxNoCache == null) {wxNoCache = new HashSet<String>();}}/*** 清空缓存区*/public static void clearCache() {wxNoCache = null;}}

3.配置我当前的点位:

@Component
@PropertySource("classpath:my-point.properties")
@Data
public class MyPointConfig {@Value("${my.point.lon}")private double lon;@Value("${my.point.lat}")private double lat;
}

4.主要操作的类:

@Service
@Slf4j
public class NearbyService {@Autowiredprivate TransportClient client;private String indexName = "nearby"; //相当于数据库名称private String indexType = "wechat";    //相当于数据表名称//建库建表建约束/*** 建库建表建约束的方法*/public void recreateIndex() throws IOException {try {//后台级的操作,关乎到删除跑路的危险if (client.admin().indices().prepareExists(indexName).execute().actionGet().isExists()) {//先清除原来已有的数据库client.admin().indices().prepareDelete(indexName).execute().actionGet();}} catch (Exception e) {e.printStackTrace();}createIndex();}/*** 创建索引** @throws IOException*/private void createIndex() throws IOException {//表结构(建约束)XContentBuilder mapping = createMapping();//建库//建库建表建约束CreateIndexResponse createIndexResponse = client.admin().indices().prepareCreate(indexName).execute().actionGet();if (!createIndexResponse.isAcknowledged()) {log.info("无法创建索引[" + indexName + "]");}//建表PutMappingRequest putMapping = Requests.putMappingRequest(indexName).type(indexType).source(mapping);AcknowledgedResponse response = client.admin().indices().putMapping(putMapping).actionGet();if (!response.isAcknowledged()) {log.info("无法创建[" + indexName + "] [" + indexType + "]的Mapping");} else {log.info("创建[" + indexName + "] [" + indexType + "]的Mapping成功");}}/*** 准备造假数据,这些数值会随机生成** @param myLat 维度* @param myLon 经度* @param count 生成多少个*/public Integer addDataToIndex(double myLat, double myLon, int count) {List<XContentBuilder> contents = new ArrayList<XContentBuilder>();//开启重复校验的缓存区RandomUtil.openCache();//一个循环跑下来就产生了10W条模拟记录,也得要具有一定的真实性for (long i = 0; i < count; i++) {People people = randomPeople(myLat, myLon);contents.add(obj2XContent(people));}//清空重复校验的缓存区RandomUtil.clearCache();//把数据批量写入到数据库表中BulkRequestBuilder bulkRequest = client.prepareBulk();for (XContentBuilder content : contents) {IndexRequest request = client.prepareIndex(indexName, indexType).setSource(content).request();bulkRequest.add(request);}BulkResponse bulkResponse = bulkRequest.execute().actionGet();if (bulkResponse.hasFailures()) {log.info("创建索引出错!");}return bulkRequest.numberOfActions();}/*** 检索附近的人** @param lat* @param lon* @param radius* @param size*/public SearchResult search(double lat, double lon, int radius, int size, String sex) {SearchResult result = new SearchResult();//同一单位为米String unit = DistanceUnit.METERS.toString();//坐标范围计量单位//获取一个查询规则构造器//查是哪个库哪个表//完成了相当于 select * from 数据库.表名SearchRequestBuilder srb = client.prepareSearch(indexName).setTypes(indexType);//实现分页操作//相当于MySQL中的  limit 0,sizesrb.setFrom(0).setSize(size);//取出优先级最高的size条数据//拼接查询条件//性别、昵称,坐标//构建查询条件//地理坐标,方圆多少米以内都要给找出来QueryBuilder qb = QueryBuilders.geoDistanceQuery("location").point(lat, lon).distance(radius, DistanceUnit.METERS)
//                .optimizeBbox("memory").geoDistance(GeoDistance.PLANE); //设置计算规则,是平面还是立体 (方圆多少米)//        //相对于 where location > 0 and location < radiussrb.setPostFilter(qb);//继续拼接where条件//and sex = ?BoolQueryBuilder bq = QueryBuilders.boolQuery();if (!(sex == null || "".equals(sex.trim()))) {bq.must(QueryBuilders.matchQuery("sex", sex));}srb.setQuery(bq);//设置排序规则GeoDistanceSortBuilder geoSort = SortBuilders.geoDistanceSort("location", lat, lon);geoSort.unit(DistanceUnit.METERS);geoSort.order(SortOrder.ASC);//按距离升序排序,最近的要排在最前面//order by location asc 升序排序srb.addSort(geoSort);//到此为止,就相当于SQL语句构建完毕//开始执行查询//调用  execute()方法//ResponseSearchResponse response = srb.execute().actionGet();//高亮分词SearchHits hits = response.getHits();SearchHit[] searchHists = hits.getHits();//搜索的耗时Float usetime = response.getTook().getMillis() / 1000f;result.setTotal(hits.getTotalHits());result.setUseTime(usetime);result.setDistance(DistanceUnit.METERS.toString());result.setData(new ArrayList<Map<String, Object>>());for (SearchHit hit : searchHists) {// 获取距离值,并保留两位小数点BigDecimal geoDis = new BigDecimal((Double) hit.getSortValues()[0]);Map<String, Object> hitMap = hit.getSourceAsMap();// 在创建MAPPING的时候,属性名的不可为geoDistance。hitMap.put("geoDistance", geoDis.setScale(0, BigDecimal.ROUND_HALF_DOWN));result.getData().add(hitMap);}return result;}/*** 创建mapping,相当于创建表结构** @return*/private XContentBuilder createMapping() {XContentBuilder mapping = null;try {mapping = XContentFactory.jsonBuilder().startObject()// 索引库名(类似数据库中的表).startObject(indexType).startObject("properties")//微信号(唯一的索引)  keyword  text.startObject("wxNo").field("type", "keyword").endObject()//昵称.startObject("nickName").field("type", "keyword").endObject()//性别.startObject("sex").field("type", "keyword").endObject()//位置,专门用来存储地理坐标的类型,包含了经度和纬度.startObject("location").field("type", "geo_point").endObject().endObject().endObject().endObject();} catch (IOException e) {e.printStackTrace();}return mapping;}/*** 将Java对象转换为JSON字符串(所谓的全文检索,玩的就是字符串)*/private XContentBuilder obj2XContent(People people) {XContentBuilder jsonBuild = null;try {// 使用XContentBuilder创建json数据jsonBuild = XContentFactory.jsonBuilder();jsonBuild.startObject().field("wxNo", people.getWxNo()).field("nickName", people.getNickName()).field("sex", people.getSex()).startObject("location").field("lat", people.getLat()).field("lon", people.getLon()).endObject().endObject();
//            jsonData = ;} catch (IOException e) {e.printStackTrace();}return jsonBuild;}/*** 构造一个人** @param myLat 所在的纬度* @param myLon 所在的经度*/public People randomPeople(double myLat, double myLon) {//随机生成微信号String wxNo = RandomUtil.randomWxNo();//造人计划,性别随机String sex = RandomUtil.randomSex();//随机生成昵称String nickName = RandomUtil.randomNickName(sex);//随机生成坐标double[] point = RandomUtil.randomPoint(myLat, myLon);return new People(wxNo, nickName, sex, point[0], point[1]);}
}

5.对查询结果进行封装:

@Data
public class SearchResult {private Long total;//记录总数private Float useTime;//搜索花费时间(毫秒)private String distance;//距离单位(米)private List<Map<String, Object>> data = new ArrayList<Map<String, Object>>();//数据集合
}

6.提供一个Controller 进行测试:

@RestController
public class SearchController {@Autowiredprivate BookService bookService;@Autowiredprivate NearbyService nearbyService;@Autowiredprivate MyPointConfig myPointConfig;//这是我所在的坐标值private String myName = "wuzz";//我的名字@GetMapping("/get/book/technology")public ResponseEntity get(@RequestParam(name = "id", defaultValue = "") String id) {GetResponse response = bookService.getById(id);if (!response.isExists()) {return new ResponseEntity(HttpStatus.NOT_FOUND);}return new ResponseEntity(response.getSource(), HttpStatus.OK);}@PostMapping("add/book/technology")public ResponseEntity add(@RequestParam(name = "name") String name,@RequestParam(name = "price") String price,@RequestParam(name = "publicationDate") String publicationDate) {IndexResponse response;try {response = bookService.add(name, Double.parseDouble(price), publicationDate);} catch (Exception e) {e.printStackTrace();return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR);}return new ResponseEntity(response, HttpStatus.OK);}@DeleteMapping("remove/book/technology")public ResponseEntity remove(@RequestParam(name = "id") String id) {DeleteResponse response = bookService.remove(id);return new ResponseEntity(response.getResult().toString(), HttpStatus.OK);}@PutMapping("modify/book/technology")public ResponseEntity modify(@RequestParam(name = "id") String id,@RequestParam(name = "name", required = false) String name,@RequestParam(name = "price", required = false) String price) {UpdateResponse response;try {response = bookService.modify(id, name, Double.parseDouble(price));} catch (Exception e) {return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR);}return new ResponseEntity(response.getResult().toString(), HttpStatus.OK);}@GetMapping("searchNearby")@ResponseBodypublic void searchNearby() {int size = 1000, radius = 1000000000;System.out.println("开始获取距离" + myName + radius + "米以内人");SearchResult result = nearbyService.search(myPointConfig.getLat(), myPointConfig.getLon(), radius, size, null);System.out.println("共找到" + result.getTotal() + "个人,优先显示" + size + "人,查询耗时" + result.getUseTime() + "秒");for (Map<String, Object> taxi : result.getData()) {String nickName = taxi.get("nickName").toString();String location = taxi.get("location").toString();Object geo = taxi.get("geoDistance");System.out.println(nickName + "," +"微信号:" + taxi.get("wxNo") +",性别:" + taxi.get("sex") +",距离" + myName + geo + "米" +"(坐标:" + location + ")");}System.out.println("以上" + size + "人显示在列表中......");}@GetMapping("/initData")@ResponseBodypublic void initData() {int total = 1000;int inserted = 0;try {//建库、建表、建约束nearbyService.recreateIndex();//随机产生10W条数据inserted = nearbyService.addDataToIndex(myPointConfig.getLat(), myPointConfig.getLon(), total);} catch (Exception e) {e.printStackTrace();}System.out.println("\n========= 数据初始化工作完毕,共随机产生" + inserted + "条数据,失败(" + (total - inserted) + ")条 =========\n");}
}

  这里需要注意的点,我们需要先进性 initData 才能进行查找,在查找的时候如果报错,需要查看index的结构:

  注意 location 的type,是否是这个,如果不是这个 ,建议把index删了重新创建。这样子对es的基本操作就有一定的认识了。

ElasticSearch整合SpringBoot的API操作相关推荐

  1. Elasticsearch整合Springboot实现基本的全文检索

    本教程仅做个人工作笔记,可能不适用于他人的工作/学习 写在前面 实际生产中,除了考虑产品的性能跟用户体验之外,生产成本也是要考虑的,如果系统是小系统,想对某一个表(200w)做全文检索的话,可以考虑使 ...

  2. elasticsearch整合springBoot

    elasticsearch的安装请参考:https://blog.csdn.net/qq_42410605/article/details/97884456 elasticsearch插件head的安 ...

  3. MongoDB入门学习(一)简介与基本操作、整合SpringBoot集合操作、整合SpringBoot文档操作

    文章目录 1. 简介 1.1 NoSQL和MongoDB 1.2 MongoDB特点 1.2.1 MongoDB 技术优势 1.2.2 Json 模型快速特性 1.3 MongoDB 应用场景 1.4 ...

  4. 关于ElasticSearch整合SpringBoot

    首先导入需要的依赖:这里要注意导入的Jest版本号和你的elasticsearch版本号在同一大版本,我的ES是6.5.4,所以这里我用的6版本的jest docker run -e ES_JAVA_ ...

  5. Elasticsearch 7.6.2 API操作

    **本文基于elasticsearch 7.6.2 的API进行测试,话不多说,直接上代码!!!** /*** es 7.6.x高级API测试*/ @SpringBootTest class Spri ...

  6. Elastic search入门到集群实战操作详解(原生API操作、springboot整合操作)-step1

    Elastic search入门到集群实战操作详解(原生API操作.springboot整合操作)-step2 https://blog.csdn.net/qq_45441466/article/de ...

  7. java与es8实战之五:SpringBoot应用中操作es8(带安全检查:https、账号密码、API Key)

    欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 本篇概览 本篇是<java与es8实战>系 ...

  8. es springboot 不设置id_es(elasticsearch)整合SpringCloud(SpringBoot)搭建教程详解

    注意:适用于springboot或者springcloud框架 1.首先下载相关文件 2.然后需要去启动相关的启动文件 3.导入相关jar包(如果有相关的依赖包不需要导入)以及配置配置文件,并且写一个 ...

  9. core 实例化接口_实例讲解Springboot整合MongoDB进行CRUD操作的两种方式

    1 简介 Springboot是最简单的使用Spring的方式,而MongoDB是最流行的NoSQL数据库.两者在分布式.微服务架构中使用率极高,本文将用实例介绍如何在Springboot中整合Mon ...

最新文章

  1. 影视,高清 音乐 工具
  2. QT的QCullFace类的使用
  3. 【java】StringBuilder的常用两种方法与练习
  4. 在Ubuntu上安装JDK、Ant、Jmeter和Jenkins
  5. 学习OpenCV(2)OpenCV初探-2
  6. java 判断浏览器_Java怎么判断访问者使用的是360浏览器
  7. 乘幂法求矩阵的特征值及特征向量
  8. 互联网 年龄歧视_太老了,无法玩:年龄歧视和游戏
  9. 技巧_MFC_标题栏背景
  10. 二叉树节点x所在的层数
  11. java操作es聚合操作并显示其他字段_深入浅析Elasticsearch中的聚合操作
  12. 【flutter】使用permission_handler配置android和 iOS的权限
  13. 最近发现百度云分享都要设置有提取码, 无法设置为无提取码的分享.本文将教你怎么绕过百度设置无提取码的分享(即公开的), 一行代码搞定!
  14. 基于COMSOL Multiphysics的静电场仿真分析
  15. MySQL-count(*)、count(1)、count(主键)、count(非索引列)、count(索引列)性能分析
  16. php基础语法——输出语句
  17. [转]split命令:对文件进行分割
  18. ITPUB BLOG
  19. 大学计算机老师面试说课,大学老师面试讲课技巧
  20. 九月英语学习之整装出发!

热门文章

  1. 市场营销问题 (二):产品属性的效用函数
  2. Android APP签名找回终极版
  3. NEON码农指导 Chapter 4 : NEON Intrinsics
  4. 【渝粤题库】陕西师范大学292021 初级宏观经济学 作业(高起专)
  5. 7-7 韩信点兵 (10 分)
  6. candidate master_已毕业研究生
  7. 7-15 福到了 c语言,福到啦L1-6 福到了(15 分) “
  8. 密码学——对称加密加密模式
  9. fp5139应用电路图_基于FP5139的可调节电压源适配器
  10. mysql 字段值分布很少的字段要不要加索引