Elasticsearch 快速入门

官网:https://www.elastic.co/

Elasticsearch 分布式 可扩展 是一个分布式RESTful搜索和分析引擎 简称ES,它与Solr都是建立在 Apache Lucene™ 基础上的搜索引擎。
它可以帮助你用前所未有的速度去处理大规模数据。Elasticsearch允许您以任何方式执行和组合多种类型的搜索

  • 结构化,非结构化,地理位置,度量标准。

ES国内外使用优秀案例
1) 2013年初,GitHub抛弃了Solr,采取ElasticSearch 来做PB级的搜索。 “GitHub使用ElasticSearch搜索20TB的数据,包括13亿文件和1300亿行代码”。

2)维基百科:启动以elasticsearch为基础的核心搜索架构。
3)SoundCloud:“SoundCloud使用ElasticSearch为1.8亿用户提供即时而精准的音乐搜索服务”。
4)百度:百度目前广泛使用ElasticSearch作为文本数据分析,采集百度所有服务器上的各类指标数据及用户自定义数据,通过对各种数据进行多维分析展示,辅助定位分析实例异常或业务层面异常。目前覆盖百度内部20多个业务线(包括casio、云分析、网盟、预测、文库、直达号、钱包、风控等),单集群最大100台机器,200个ES节点,每天导入30TB+数据。

**

最全Elasticsearch学习

**

1.相关概念

Lucene:是一个开放源代码的全文检索引擎工具包,功能强大,接入复杂。
Solr:是一个高性能,采用Java5开发,基于Lucene的全文搜索服务器。
Elasticsearch:是一个分布式,基于Lucene的全文搜索服务器。

ES首先使用场景: 记录与日志分析和数据可视化(ELK)、全文检索、高使用频率、多条件组合、及时响应等。

ES基础概念:
node: 节点,它是作为群集一部分的单个服务器,存储数据并参与群集的索引和搜索功能,形成集群的每个服务器称为节点。
cluster: 集群,由多个节点组成的架构。
index: 索引,相当于关系型数据库的database。
shard: 索引分片,索引可以设置多个分片(可以把一个分片放到一个节点上进行性能的优化)。
replicas: 索引副本,ES创建索引默认5个分片和1个副本,1个副本是对5个分片分别进行1个副本备份(5个分片也就5个备份)。
type: 类型,相当于关系型数据库的table。
doucment: 文档,相当于关系型数据库表中的行,而列对应的就是ES的字段。
在这里插入图片描述

Elasticsearch优点:
1)分布式实时文件存储,可将每一个字段存入索引,使其可以被检索到。
2)实时分析的分布式搜索引擎。
分布式:索引分拆成多个分片,每个分片可有零个或多个副本。集群中的每个数据节点都可承载一个或多个分片,并且协调和处理各种操作;
负载再平衡和路由在大多数情况下自动完成。
3)可以扩展到上百台服务器,处理PB级别的结构化或非结构化数据。也可以运行在单台PC上(已测试)
4)支持插件机制,分词插件、同步插件、Hadoop插件、可视化插件等。

Elasticsearch缺点:
只有一名开发者(当前Elasticsearch GitHub组织已经不只如此,已经有了相当活跃的维护者)
还不够自动(不适合当前新的Index Warmup API)

这里网上搜集下Elasticsearch与Solr的比较,让大家有个基本认识区分
1 ES 最大的特点就是支持分布式。
2.在搜索数据中单纯的对已有数据进行搜索时,Solr更快。
3.ES在实时建立索引时, Elasticsearch具有明显的优势,Solr会产生io阻塞,查询性能较差。
4.随着数据量的增加,Solr的搜索效率会变得更低,而Elasticsearch却没有明显的变化。

2.安装

自己查阅安装(很简单,到处都有就不说了)

3.相关语法

命令分类

索引管理: 创建、配置(type)、删除索引(Index)
文档管理: 创建、修改、删除文档(doucment)
数据查询: 空查询、指定索引查询,指定类型查询、请求体查询(过滤查询,匹配度查询)

提示 理解完ES的语法结构,自己在去学习ES JAVA API的操作就很明白。

ES请求方式:
在请求中以JSON数据格式发送请求,ES的数据返回也是一个JSON格式(请看下列语法)。

GET(查询)、 POST(查询,新增,修改)、 PUT(新增,修改) 、 DELETE(删除)
通常规范可以用GET来查询,PUT来修改,POST来新增,DELETE来删除。(后面会解释)
注:关键字请求语句虽然是模拟HTTP关键字的请求模式,但是不要混为一谈。
在关键字GET中,发送请求并不是以一个get协议去发送一个请求,实际上内部还是以一个POST请求发送。(知道这么回事就OK!)

路径访问拼接: —— ES/index/type/doucment

ES 提供 _search端点访问ES服务器(如_cat还有很多很多,对于我们现在使用意义不大,具体查看ES官方文档,这里针对讲解6.0以上的版本)
例如命令: GET /_search 或者 GET /movies/_search
http://localhost:9200/_search - 搜索所有索引和所有类型。
http://localhost:9200/movies/_search - 在电影索引中搜索所有类型
http://localhost:9200/movies/movie/_search - 在电影索引中显式搜索电影类型的文档。
一 【索引管理】:创建、配置(type)、删除索引(Index)

索引管理-创建索引
语法:
PUT /索引名称
{
“settings”:{
“number_of_shards”:分片数目,
“number_of_replicas”:副本数量
},
“mappings”:{…}
}
注:
1.不配置参数也可以创建,创建索引默认5个分片一个副本.(PUT /索引名称 {})
2.索引名称必须小写,不能出现下划线开头,不能使用逗号。
3.索引的创建只能用PUT。在ES中,路径映射对“/”做了处理(一级目录前索引名称的“/”可以省略,为了规范我们统一都加上)

索引管理-配置索引
语法:
PUT /索引名称
{
“settings”:{
“number_of_shards”:5, //5个分片数目
“number_of_replicas”:0 //不要副本
},
“mappings”:{
“type名称”:{
“properties”:{
“字段名称1”:{
“type”:“字段1类型”, //ES字段类型后面列出来
“analyzer”:“分词器类型” //分词器后面列出来
},
“字段名称2”:{
“type”:“字段2类型”,
“analyzer”:“分词器类型”
}
}
}
}
}

比如:
    #kibana dev tools配置索引
    PUT /sms
    {
      "settings": {
        "number_of_shards": 5, 
        "number_of_replicas": 1
      },
      "mappings": {
        "course":{ 
          "properties":{
            "id":{           
              "type":"keyword"
            },
            "courseName":{
              "type":"text"
            },
            "title":{
              "type":"text",
              "analyzer": "ik_max_word"
            }
          }
        }
      }
    }
注:1.建议在创建索引时,最好创建type,定义分词器。(type不指定语义也能通过)
   2.在集群环境中 每台集群需要安装IK分词器,每台机子需要重启ES才能生效

索引管理-删除索引
语法:
DELETE /索引名称
注:通过GET /_cat/indexs/?v 查看删除的索引名称("/?v"开启详细输出)

1.ES字段类型
在这里插入图片描述
注:ES5.0之后数据类型有所变化,主要是对字符串类型进行了细分。
string变成了text、keyword

2.分词器类型
在这里插入图片描述
注:分词器主要对text类型进行拆分,然后进行关键字匹配。(不同分词器拆分策略不一样) 常用IK分词器

es自带了许多内置的Analyzer分析器,无需配置就可以直接在index中使用比如

标准分词器(standard):不支持中文,根据Unicode文本分割算法。它会移除大部分的标点符号,小写分词后的term,支持停用词。
简单分词器(simple):不支持中文,该分词器会在遇到非字母时切分字符串,小写所有的term。
空格分词器(whitespace):不支持中文,遇到空格字符时切分字符串, 停用词分词器(stop):类似简单分词器,同时支持移除停用词。
关键词分词器(keyword):无操作分词器,会输出与输入相同的内容作为一个single term。
语言分词器(language):支持许多基于特定语言的分词器,比如德语,俄语,日语等等
签名分词器(fingerprint):是一个专家分词器,会产生一个签名,可以用于去重检测。
自定义分词器(custom):很多分词器无法满足,不支持中文分词器,可以自定义IK分词器。

二 【文档管理】:创建、修改、删除文档

****文档管理-新增文档++修改文档****

 PUT /索引名称/类型名称/文档ID
 {
 	"file_name":"file_value",
 	...
 }
 或
 
 POST /索引名称/类型名称/文档ID
 {
 	"file_name":"file_value",
 	...
 }
 
 注:
 1.指定索引,类型名称和文档ID情况下,PUT和POST语法执行效果一样(ID存在两个也都会修改)。
 
 2.修改:在ID存在情况下,执行会进行修改操作(在es系统中,他的修改其实是,旧数据
   标记删除,新数据通过新增)这样速度会快很多,具体在去研究。
   
 3.PUT和POST区别在于:
 PUT必须指定文档ID,不然语义错误,而POST可以不用指定文档ID,会自动生成一串ID字符。
 同时POST在不指定文档ID的情况下,在继续新增,会产生不同的ID字符。
 建议:基于这些 我们通常规范可以用GET来查询,PUT来修改,POST来新增,DELETE删除
 
 4.在创建doucment时,如果该index没有定义type (创建索引可以不创建type),es系统
 会自动新增对应type。(知道有这么个情况就OK!) 对于大量数据一般都会导入。
文档管理-删除文档

DELETE /索引名称/类型名称/文档ID

三 【数据查询】:空查询、指定索引查询,指定类型查询、请求体查询(过滤查询,匹配度查询)
这里只讲解常用查询(跨度查询,地理查询等不讲解)

语法:
    GET /_search    //空查询
    GET /索引名称/类型名称/文档ID   //指定索引查询,指定类型查询
    GET /索引名称/类型名称/_search
    例如:
    GET /_search   //查询所有库中的结果
    GET /le/user/01       //查询le库中user表下01的字段信息
    GET /le/user/_search  //查询le库中user下的所有字段信息

查询结果分析(查询之后ES会给你一个JSON的数据结构里面包含信息):

took: 搜索请求耗费时间,单位为毫秒(ms 毫秒,s 秒,m分)。
_shards: 查询中参与分片的总数,以及这些分片成功和失败的个数。
timed_out:表示查询是否超时(?timeout=1ms)
hist:查询出来的结果集,数据格式为JSON格式。

请求体查询(过滤查询,匹配度查询)
拆开两个类:过滤查询,匹配度查询来详细讲解,这样更容易理解查询机制
当然我们要知道在实际运用中,过滤和匹配度查询也是可以组合一起查询的。
请求体查询一般使用query子语句进行实现

过滤查询:对文档进行匹配,不进行打分,条件多为精准查询。效率比较快
(意思为查询条件不是模糊的,没有匹配度的概念,比如性别男或者女)
常用filter + 其他子句进行。

 语句:
 GET /索引名称/类型名称/文档ID
 {
   "query":{
   	  "bool":{
   	    "filter":{
   	      "term":{
   	        "sex":1
   	      }
   	    }
   	  }
   }
 }
 文档ID可以不给,这个类似于数据库的主键。
 注:这里是一个过滤查询 同时也是个复合查询,bool子句不是唯一的,(后面会说)
 通常在query下的子句都会进行打分,filter子句不会进行打分所以嵌套在bool子句的后面进行一
 个精准查询条件。
 在查询中打分高的数据在前面,低的在后面。

匹配度查询:对文档进行匹配,进行打分,条件多为全文检索查询。
原理基于全文索引,过滤查询也是基于全文索引,对查询文本进行分词,对分词出来的关键字去做索引,然后去匹配。
常用match子句实现

语句:
 GET /索引名称/类型名称/文档ID
 {
   "query":{
     "match":{
       "name":"刘"
     }
   }
 }
 注:字段指定的匹配条件是name字段里面包含"刘"的这个词。

了解查询子句:(注:可以用于精准查询,全文检索查询)

(有很多)常用子句:match 、 term 、terms 、range

match:

match查询是一个标准查询,不管你需要全文本查询还是精确查询基本上都要用到它。

如果你使用 match 查询一个全文本字段,它会在真正查询之前用分析器先分析match一下查询字符:

{ 
    "match": { 
        "tweet": "About" 
    } 
}

如果用match下指定了一个确切值,在遇到数字,日期,布尔值或者not_analyzed 的字符串时,它将为你搜索你给定的值:

{ "match": { "age":    26           }} 
{ "match": { "date":   "2000-01-01" }} 
{ "match": { "public": true         }} 
{ "match": { "tag":    "full_text"  }}

注: 做精确匹配搜索时,你最好用过滤语句(term 、filter),因为过滤语句可以缓存数据,效率更加快。

match查询只能就指定某个确切字段某个确切的值进行搜索,而你要做的就是为它指定正确的字段名以避免语法错误。

term:

term 过滤 term主要用于精确匹配哪些值,比如数字,日期,布尔值,你也可以理解类似于等于

{ "term": { "age":    26           }} 
{ "term": { "date":   "2000-01-01" }} 
{ "term": { "public": true         }} 
{ "term": { "tag":    "full_text"  }}

完整的例子, sex字段完全匹配成数据:

{ 
  "query": { 
    "term": { 
      "sex": 1
    } 
  } 
}
注:大家认真看了上面的注解没有(注解有写过,子句:可以用于精准查询,全文检索查询)
在上面完整的例子中term直接在query子句下使用(其实语法是通过的,但是不推荐这么用)
上面也说过在query子句下使用子句查询会对结果进行打分,而term是一个精确
查询,所以打分意义不大,还影响查询效率(知道这么回事就OK)。

terms:

terms 过滤 terms 跟 term 有点类似,但 terms 允许指定多个匹配条件。
如果某个字段指定了多个值,那么文档需要一起去做匹配:

{ 
    "terms": { 
        "tag": [ "search", "full_text", "nosql" ] 
        } 
}

完整的例子,在ES中状态是数字类型的字段,可以不用加" "。:

{ 
  "query": { 
    "terms": { 
      "status": [ 
        "full_text", 
        "nosql"
      ] 
    } 
  } 
}

range:

range过滤允许我们按照指定范围查找一批数据:

{ 
    "range": { 
        "age": { 
            "gte":  20,  //大于等于(加e就多个等于)
            "lt":   30 //小于
        } 
    } 
}
注:gt:大于,  gte:大于等于,  lt :小于,  lte:小于等于

一个完整的例子, 请求页面耗时大于1秒的数据,upstream_response_time 是 nginx 日志中的耗时,ES中是数字类型。

{ 
  "query": { 
    "range": { 
      "upstream_response_time": { 
        "gt": 1 
      } 
    } 
  } 
}

结合不同的子句进行查询 我们可以叫复合查询,也可以说是组合查询。
复合查询: 同时对多个字段进行匹配检索,并且根据一系列的标准来过滤的复合查询

实现方式: constant_score 、 bool 、dis_max 、function_score 、boosting
深入了解不同的子句,自己查阅官方讲解,这里只介绍bool。
复合查询 自己用的多了就知道怎么回事了,这里简单让大家知道怎么回事。

  • bool : must (必须)、must_not(否定)、filter (过滤,准确)、should(影响打分)

must
子句(查询)必须出现在匹配的文档中,并有助于得分。

must_not
子句(查询)不得出现在匹配的文档中。子句在过滤器上下文中执行,这意味着忽略评分并考虑使用子句进行高速缓存。由于忽略了评分,因此0会返回所有文档的分数。

filter
子句(查询)必须出现在匹配的文档中。但是不同于
must查询的分数将被忽略。过滤器子句在过滤器上下文中执行,这意味着忽略评分并考虑使用子句进行高速缓存。

should
子句(查询)应出现在匹配的文档中。如果 bool查询位于查询上下文中并且具有mustor filter子句,则bool即使没有
should查询匹配,文档也将与查询匹配。在这种情况下,这些条款仅用于影响分数。如果bool查询是过滤器上下文,
或者既没有must或者filter至少有一个should查询必须与文档匹配,以便与bool查询匹配。可以通过设置minimum_should_match参数来显式控制此行为

列举语法:
GET /_search
{
  "query":{
    "bool":{
      "过滤": ----filter{ term,range ...}
    "匹配度":----must,should{ match ... }
    }
  }
}

GET /_search
{
  "query": {
    "bool": {
      "filter":   { "term" : { "age" : 1}},
      "must":     { "match": { "title": "quick" }},
      "must_not": { "match": { "title": "lazy"  }},
      "should": [
                  { "match": { "title": "brown" }},
                  { "match": { "title": "dog"   }}
      ]
    }
  }
}

分页查询:

通过from size两个参数(和传统分页差不多,没什么难理解的)
from:分页的开始位置(从0开始)
size:页面大小
比如:第一页取10行数据
如果默认from:0 size:10 就是从每个shard取前10,然后统一排序取1到10
比如:第二页取10行数据,from值以此类推
如果from:10 size:10 那就是每个shard取前20,然后统一排序取11到20。

总结:
ES基础概念:node(节点),cluster(集群),type(类型),doucment(文档),
index(索引),shard(索引分片) replicas(副本)
ES文档三元素:_index + _type + _ID
ES请求拼接:es路径/index/type/doucment
ES常用命令:索引管理 + 文档管理 + 数据查询
ES查询子句{
组合查询:bool(must 、must_not、filter、should)
过滤查询:filter
匹配度:match
子句: term 、terms 、range (嵌套在过滤或匹配度子句下面)
}

查询例子太多了oneself查阅资料(查询就不一一介绍)。
ES java 官方文档:
https://www.elastic.co/guide/en/elasticsearch/client/java-api/6.2/index.html

熟悉以上知识,然后就可以进行JAVA客户端的ES搜索运用啦(这里不详细说)。
1.在项目中引入Maven依赖(选择你用的版本 https://search.maven.org/)
需要注意的是,版本不同连接语法和其他用法也有小的差别

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

2.通过java api 建立连接,关闭连接
注:9300 为 ES 的默认 Transport 端口,节点和客户端的通讯

@Component
@RestController
public class EsUtils {
    private final static Logger logger = LoggerFactory.getLogger(EsUtils.class);
    private static TransportClient client = null;

    @Autowired
    private EsConfig esConfig;

    public void getConnection() throws UnknownHostException {
        logger.info("es getConnection start ...");
        Settings settings = Settings.builder()
                .put("cluster.name", esConfig.getClusterName())
                .build();
        if (client == null) {
            client = new PreBuiltTransportClient(settings)
                    .addTransportAddress(new TransportAddress(InetAddress.getByName(esConfig.getIp()),
                            esConfig.getPort()));
            logger.info(BasicRestStatus.OK.toString(),"ElasticsearchClient 连接成功");
        }
    }

3 .请求ES构建

/**
 * 请求ES构建
 *
 * @param esSettingDto
 * @return
 */
public SearchRequestBuilder esBuilder(EsSettingDto esSettingDto) throws Exception {
    logger.info("es esBuilder start info: " + esSettingDto);
    SearchRequestBuilder searchRequestBuilder =
            client.prepareSearch(esSettingDto.getIndexSmsCourse(),
                    esSettingDto.getIndexSmsTeacher());
    searchRequestBuilder.setTypes(esSettingDto.getTypeCourseName(),
                    esSettingDto.getTypeTeacherName());
    //节点切片之间抓取数据的策略(QUERY_THEN_FETCH :检索然后抓取,QUERY_AND_FETCH  :检索并且抓取)
    searchRequestBuilder.setSearchType(SearchType.QUERY_THEN_FETCH);
    //是否根据匹配度进行排行
    searchRequestBuilder.setExplain(true);
    return searchRequestBuilder;
}

4.新增索引、配置索引 、

//新增索引
public void addIndex() throws IOException{
    //通过client调用admin()方法,在调用所有索引 indices(),在这之下可以进行增,删,改
    client.admin().indices().prepareCreate("索引名称").get(); //创建一个默认的索引
    注:到这里了,自己可以写个mian入口,进行方法测试。查看索引库是否创建成功!
}
//配置索引
public void addIndex() throws IOException {
    // 创建一个默认的index
    client.admin().indices().prepareCreate("sc_31").get();
    //内容构建器(更加直观的构建一个JSON数据格式,以调用方法的形式去构建)
    XContentBuilder content = XContentFactory.jsonBuilder() 
            .startObject()// {  "开启对象结构"
                .startObject("properties")// "properties" : {    
                    .startObject("name")        // "name": {
                        .field("type", "text")// "type" : "text",
                        .field("analyzer", "ik_max_word")// "analyzer" : "ik_max_word"
                    .endObject()    // } "结束对象结构"
                    .startObject("age")
                        .field("type", "integer")
                    .endObject()
                    .startObject("sex")
                        .field("type", "integer")
                    .endObject()
                    .startObject("address")        // "address": {
                        .field("type", "text")// "type" : "text",
                        .field("analyzer", "ik_max_word")// "analyzer" : "ik_max_word"
                    .endObject()
                .endObject() // }
            .endObject();// }
    client.admin().indices().preparePutMapping("sc_31")
                            .setType("user")
                            //主要设置属性source(source 有四种重载)
                            //在setSource中使用String 重载方法格式如下(其他重载实现格式自己查询了解,这里只写两种参考)
                            //XContentType.JSON 是以一个JSON字符串的格式定义                          
                            //.setSource("{\"properties\":{\"name\":{\"type\":\"text\",\"analyzer\":\"ik_max_word\",}}}", XContentType.JSON)
                            //XContentBuilder 重载方法
                            .setSource(content)
                            .get();
    // 关闭
    client.close();
}

// 添加文档

public void addDocument() throws IOException {
    XContentBuilder content = XContentFactory.jsonBuilder()
            .startObject()
                .field("name", "王老五")
                .field("age", 88)
                .field("sex", 1)
                .field("address", "北京市海淀区成府路")
            .endObject();
    client.prepareIndex("sc_31", "user", "01") // POST sc_31/user/id
        .setSource(content) 
        .get(); 

    client.close();
}
针对JAVA API 就不写了,实现ES集群模式,对于Es搜索功能实现(类似于腾讯课堂),实战代码参考可以找我。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
智慧校园建设方案旨在通过信息化手段提升教育、管理和服务水平,实现资源数字化、工作流程化、管理高效化和决策智能化。方案包括智慧校园信息化平台和安防平台的建设,涉及教学、科研、管理和服务等多个方面,以满足现代教育和培训需求。 技术服务要求强调了统一支撑平台的建设,包括数据标准、接口标准、代码标准和用户信息标准的统一制定。平台需满足信创和X86交叉适配要求,确保安全自主可控的系统开发环境。此外,方案还涵盖了用户中心系统、统一认证授权中心、统一工作流中心、统一智能报表中心等多个模块,以及数据共享中心、语音识别、移动服务终端等功能,以实现校园内外部信息的互联互通和资源共享。 智慧校园信息化平台的建设还包括了对教学管理、人事管理、公文管理、档案管理、即时通讯、会议管理、督办工作、资产管理等方面的数字化和自动化升级。这些模块的集成旨在提高工作效率,优化资源配置,加强监督管理,并通过移动应用等技术手段,实现随时随地的信息访问和业务处理。 安防平台的建设则侧重于校园安全,包括停车场管理、人脸识别测温、访客自助登记、视频监控等多个系统。这些系统的集成旨在提高校园的安全管理水平,实现对校园内外人员和车辆的有效监控和管理,确保校园环境的安全稳定。 最后,方案还提到了对固定资产的管理,包括购置、使用、归还、报废等全生命周期的管理,以及对网络设备、安防设备、服务器等硬件设施的配置和管理。通过这些措施,智慧校园建设方案旨在为校园提供一个安全、高效、便捷的学习和工作环境。
Elasticsearch是一款非常强大的开源搜索引擎,它可以帮助我们从海量数据中快速找到需要的内容。它是elastic stack(ELK)的核心组件之一,结合kibana、Logstash、Beats等工具,被广泛应用在日志数据分析、实时监控等领域。\[1\] 在Elasticsearch中,为了提高搜索的性能,它使用了倒排索引的概念。倒排索引是指将文档中的每个词都建立索引,然后通过这些索引来快速定位到包含该词的文档。当我们向Elasticsearch插入一条记录时,它会将记录中的字段建立倒排索引,以便能够快速搜索和检索数据。\[2\] 为了能够快速找到某个词,Elasticsearch使用了Term Dictionary。Term Dictionary将所有的词进行排序,并使用二分法查找词,类似于我们在学校时老师教我们使用字典的方式。这种查询方式类似于传统关系型数据库的B-Tree索引方式,但并不是Elasticsearch快速的原因。\[3\] 以上是elasticsearch快速入门介绍。 #### 引用[.reference_title] - *1* [Elasticsearch快速入门](https://blog.csdn.net/ks_1998/article/details/121237513)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [【ElasticSearchElasticSearch 快速入门(精讲)](https://blog.csdn.net/m0_45067620/article/details/120377816)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值