在java中使用es的一些基本操作,干货满满,记得点赞哦!

引入与配置

我这里不写关于 es的部署,如果要看es的部署,请移步 ~

首先在springboot项目的pom文件中引入需要的包
<!-- ES搜索 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>

<!-- elasticsearch -->
<dependency>
    <groupId>org.elasticsearch</groupId>
    <artifactId>elasticsearch</artifactId>
    <version>6.5.4</version>
</dependency>

<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-high-level-client</artifactId>
    <version>6.5.4</version>
</dependency>

这里呢
不建议引用最新的包,
至于原因嘛,有很多,例如,我的jdk还是1.8。

第二步也很简单,配置文件的配置

我用的是yml,只说yml。

spring:
    #指明es服务器地址
    elasticsearch:
        rest:
            uris: http://103.59.148.103:9200
            username: hehe
            password: *********

下面,进入重点课程,es的java使用。

实体类的构建
/**
 * @Author: zhaoz
 * @CreateTime: 2022年11月11日
 * @Description: ES 数据结构
 */
@AllArgsConstructor
@NoArgsConstructor
@Document(indexName = "test_console")
@Accessors(chain = true)
@Data
public class InfoEntity implements Serializable {


    private static final long serialVersionUID = -2942121322430364691L;

    @Id
    @ApiModelProperty("id")
    private String id;

    @ApiModelProperty("info时间")
    @Field(name = "info_time", type = FieldType.Date, format = {}, pattern = "yyyy-MM-dd HH:mm:ss")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime infoTime;

    @ApiModelProperty("标题")
    @Field(name = "title", type = FieldType.Text, analyzer = "ik_max_word")
    private String title;

    @ApiModelProperty("内容")
    @Field(name = "content", type = FieldType.Text, analyzer = "ik_max_word")
    private String content;

    @ApiModelProperty("地址")
    @Field(name = "address", type = FieldType.Text, analyzer = "ik_max_word")
    private String address;
}
index索引:es的索引的添加
@Autowired
private ElasticsearchTemplate elasticsearchTemplate;

@PostMapping("/createdIndex2")
@ApiOperation(value = "学习创建索引")
public String createdIndex2(@RequestParam("index") String index) {
    // 判断索引是否存在
    try {
        GetIndexRequest getIndexRequest = new GetIndexRequest(index).local(false).humanReadable(true);
        if (client.indices().exists(getIndexRequest, RequestOptions.DEFAULT)) {
            return "存在索引!";
        } else {
            // 设置settings映射
            Settings settings = Settings.builder().put("number_of_shards", 1).put("number_of_replicas", 0).build();
            // 设置mapping映射
            XContentBuilder mapping = XContentFactory.jsonBuilder()
                    .startObject()
                    .startObject("properties")
                    // keyId
                    .startObject("id").field("type", "long").endObject()
                    // title
                    .startObject("info_title").field("type", "keyword").endObject()
                    // content
                    .startObject("info_content").field("type", "text").endObject()
                    // birthday
                    .startObject("info_time")
                    .field("type", "date")
                    .field("format", "yyyy-MM-dd HH:mm:ss")
                    .field("ignore_malformed", true).endObject()
                    // address
                    .startObject("address").field("type", "text").endObject()
                    .endObject().endObject();
            boolean createIndexResponse = getCreateIndexResponse(new CreateIndexRequest(index).settings(settings).mapping(mapping));
            if (createIndexResponse) {
                return "创建索引成功";
            } else {
                return "创建索引失败";
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
        return e.getLocalizedMessage();
    }
}
private boolean getCreateIndexResponse(CreateIndexRequest createIndexRequest) throws Exception {
   String index = createIndexRequest.index();
   try {
       // 超时时间设置为 1m
       createIndexRequest.setTimeout(TimeValue.timeValueMinutes(1));
       CreateIndexResponse createIndexResponse = client.indices().create(createIndexRequest, RequestOptions.DEFAULT);
       if (createIndexResponse.isAcknowledged()) {
           // 创建ES索引成功
           return true;
       } else {
           // 创建ES索引失败
           return false;
       }
   } catch (Exception e) {
       throw new Exception("创建ES索引[" + index + "]异常", e);
   }
}
index索引: ES索引的删除

删除索引 会删除数据

/**
*  删除索引 会删除数据
 * @param index
 * @return
 */
@DeleteMapping("/deleteIndex")
@ApiOperation(value = "学习删除索引")
public String deleteIndex(@RequestParam("index") String index) {
    // 判断索引是否存在
    try {
        GetIndexRequest getIndexRequest = new GetIndexRequest(index).local(false).humanReadable(true);
        if (client.indices().exists(getIndexRequest, RequestOptions.DEFAULT)) {
            DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest(index);
            deleteIndexRequest.indicesOptions(IndicesOptions.LENIENT_EXPAND_OPEN);
            AcknowledgedResponse acknowledgedResponse = client.indices().delete(deleteIndexRequest, RequestOptions.DEFAULT);
            if (acknowledgedResponse.isAcknowledged()) {
                return "删除索引成功";
            } else {
                return "删除索引失败";
            }
        } else {
            return "索引不存在!";
        }
    } catch (Exception e) {
        e.printStackTrace();
        return e.getLocalizedMessage();
    }
}
添加es索引内容
@PostMapping("/addESFieldContent")
@ApiOperation(value = "添加字段内容(map格式)")
public R addESFieldContent(@RequestBody Map<String, String> maps) throws IOException {
    // 可以使用Map作为参数
    IndexRequest indexRequest = new IndexRequest();
    indexRequest.index(INDEXES_TYPE);
    indexRequest.source(maps);
    // 可以使用XConttentBuilder构建内容
//        XContentBuilder builder = XContentFactory.jsonBuilder();
//        builder.startObject();
//        {
//            builder.field("user", "kimchy");
//            builder.timeField("postDate", new Date());
//            builder.field("message", "trying out Elasticsearch");
//        }
//        builder.endObject();
//        IndexRequest indexRequest = new IndexRequest("posts")
//                .id("1").source(builder);
    // 发送请求到ES
    IndexResponse response = client.index(indexRequest, RequestOptions.DEFAULT);
    return R.ok(response);
}

还有一种,就需要用到我们创建好的实体类InfoEntity

  1. 创建接口InfoRepository继承ElasticsearchRepository
package com.whisper.db.esRepository;

import com.whisper.db.domain.InfoEntity;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface InfoRepository extends ElasticsearchRepository<InfoEntity, String> {

}

  1. 引用并实现新增(save)、批量新增(saveAll);
@Autowired
private InfoRepository infoRepository;

@PostMapping("/addESContent")
@ApiOperation(value = "保存es内容")
 public R addESContent(@RequestBody InfoEntity entity) throws Exception {
     InfoEntity save = infoRepository.save(entity);
     return R.ok(save);
 }

查询es索引下所有数据
@GetMapping("/match/all")
@ApiOperation(value = "学习数据查询")
public String matchAll(@RequestParam("index") String index) throws IOException {
//        String index = "test_console";
    SearchRequest request = new SearchRequest(index);
    //2.指明使用matchall查询
    SearchSourceBuilder builder = new SearchSourceBuilder();
    builder.query(QueryBuilders.matchAllQuery());
    // 查询条数
    builder.size(10);
    request.source(builder);
    //3.发送请求
    SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    //4.输出
    return response.toString();
}
es 对新增索引内容的修改

这里我只写一种我们可能会经常用到的修改方式;

@PutMapping("/editESFieldContent")
@ApiOperation(value = "修改字段内容")
public R editFieldContent(@RequestBody Map<String, String> maps) throws IOException {
    // 这是我前面创建的索引,记得替换成自己的
    String index = "test_console";
    UpdateRequest update = new UpdateRequest();
    update.index(index).id(maps.get("id"));
    // 拓展:局部更新可以这样写:update.doc(XContentType.JSON, "name", "李四", "age", 25);,其中"name"和"age"是User对象中的字段名称,而"小美"和25是对应的字段值
    update.doc(XContentType.JSON, "info_title", maps.get("title"), "info_content", maps.get("content"));
    // 全部更新需要重新传入数据
//        update.doc(JSONObject.toJSONString(maps), XContentType.JSON);
    // 3、发送请求到ES
    UpdateResponse response = client.update(update, RequestOptions.DEFAULT);
    return R.ok(response);
}

这里需要注意 map里面的id是es生成的id
在这里插入图片描述
再附上一个有用的es 语句。

POST /test_console/_doc/LWNgf4QBMMqlRJmSXSlf/_update
{
  "doc":{
    "info_title": "外交部发言人回应达苏恐袭案宣判:这是对正义的伸张、对遇难中国同胞的告慰。"
  }
}

es 搜索 条件检索内容(激动人心的时刻就在这里)
  1. 最简单的es模糊查询(单字段匹配)
@GetMapping("/match/search")
@ApiOperation(value = "es模糊搜索")
public String matchSearch(
        @RequestParam("index") String index,
        @RequestParam("keyword") String keyword) throws IOException {
    if (StringUtils.isEmpty(keyword)) {
        return "";
    }
//        String index = "test_console";
    SearchRequest request = new SearchRequest(index);
    //2.指明使用match查询
    SearchSourceBuilder builder = new SearchSourceBuilder();
    MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("info_content", keyword);
    builder.query(matchQueryBuilder);
    builder.size(10);
    //3.发送请求
    SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    return response.toString();
}
  1. 查询不同字段内的关键字内容
    多字段检索,是组合查询的另一种形态,如果考察多字段检索,并不一定必须使用multi_match,也可以使用bool query
@GetMapping("/multiMatch/search")
@ApiOperation(value = "es模糊搜索")
public String multiMatch(
        @RequestParam("index") String index,
        @RequestParam("keyword") String keyword) throws IOException {
    if (StringUtils.isEmpty(keyword)) {
        return "";
    }
//        String index = "test_console";
    SearchRequest request = new SearchRequest(index);
    //2.指明使用match查询
    String[] fieldNames = {"info_content", "info_title"};
    SearchSourceBuilder builder = new SearchSourceBuilder();
    MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery(keyword, fieldNames);
    builder.query(multiMatchQueryBuilder);
    builder.size(10);
    //3.发送请求
    SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    return response.toString();
}
  1. 查询不同字段内关键字(完整关键字,不分词)
    multi_match type:
    • best_fields:侧重于字段维度,单个字段的得分权重大,对于同一个 query,单个field匹配更多的term,则优先排序。
    • most_fields:侧重于查询维度,单个查询条件的得分权重大,如果一次请求中,对于同一个doc,匹配到某个term的field越多,则越优先排序。
    • cross_fields:对于一些实体,标识信息会在多个字段中出现,每个字段中只含有一部分信息。
    • phrase_prefix:等同于 最左前缀查询。
    • phrase: 等同于 短语查询
MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery(keyword, fieldNames).type("phrase");

这里使用的也比较简单 就是.type(“phrase”)
4. 查询不同字段不同关键字的查询
这里使用的是 es 查询语句的 bool query
需要注意的是 must、和 should的区别。

// 附上 es的语法,更清晰的明白Java的写法。
GET /test_console/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "multi_match": {
            "query": "宙斯盾号军舰89",
            "fields": ["info_content","info_title"],
            "type": "phrase"
          }
        },
        {
          "multi_match": {
            "query": "空军",
            "fields": ["info_content","info_title"],
            "type": "phrase"
          }
        }
      ]
    }
  },
  "from": 0,
  "size": "20"
}
@GetMapping("/match/bool/multiQuery")
@ApiOperation(value = "es模糊搜索")
public R matchBoolPhraseQuery(@Param("index") String index,
                              @Param("fields") String fields,
                              @Param("keywords") String keywords) throws IOException {
   // String index = "test_console";
    SearchRequest request = new SearchRequest(index);
    SearchSourceBuilder builder = new SearchSourceBuilder();
    if (StringUtils.isEmpty(keywords)) {
        builder.query(QueryBuilders.matchAllQuery());
        builder.size(10);
    } else {
        String[] keywordg = keywords.split(" ");
        //2.指明使用match查询
        String[] fieldNames = {};
        if (StringUtils.isNotEmpty(fields)) {
            fieldNames = fields.split(" ");
        } else {
            fieldNames = new String[]{"news_content", "news_title"};
        }
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        for (String keyword:keywordg) {
            boolQueryBuilder.must(QueryBuilders.multiMatchQuery(keyword, fieldNames).type("phrase"));
        }
        builder.query(boolQueryBuilder);
        builder.size(10);
    }
    request.source(builder);
    //3.发送请求
    SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    // 结果解析
    SearchHits hits = response.getHits();
    List<Map<String, Object>> results = new ArrayList<>();
    for (SearchHit documentFields : hits.getHits()) {
        Map<String, Object> sourceAsMap = documentFields.getSourceAsMap();
        results.add(sourceAsMap);
    }
    return R.ok(results);
}

继续学习中。。。
敬请期待 ~

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐