草庐IT

springboot中es的使用与学习

春风骀了谁的心 2023-04-20 原文

在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);
}

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

有关springboot中es的使用与学习的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby - 使用 RubyZip 生成 ZIP 文件时设置压缩级别 - 2

    我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看ruby​​zip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d

  3. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  4. ruby-on-rails - 使用 Ruby on Rails 进行自动化测试 - 最佳实践 - 2

    很好奇,就使用ruby​​onrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提

  5. ruby - 在 Ruby 中使用匿名模块 - 2

    假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于

  6. ruby - 使用 ruby​​ 和 savon 的 SOAP 服务 - 2

    我正在尝试使用ruby​​和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我

  7. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  8. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

  9. ruby - 使用 ruby​​ 将 HTML 转换为纯文本并维护结构/格式 - 2

    我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h

  10. ruby - 在 64 位 Snow Leopard 上使用 rvm、postgres 9.0、ruby 1.9.2-p136 安装 pg gem 时出现问题 - 2

    我想为Heroku构建一个Rails3应用程序。他们使用Postgres作为他们的数据库,所以我通过MacPorts安装了postgres9.0。现在我需要一个postgresgem并且共识是出于性能原因你想要pggem。但是我对我得到的错误感到非常困惑当我尝试在rvm下通过geminstall安装pg时。我已经非常明确地指定了所有postgres目录的位置可以找到但仍然无法完成安装:$envARCHFLAGS='-archx86_64'geminstallpg--\--with-pg-config=/opt/local/var/db/postgresql90/defaultdb/po

随机推荐