3.Elasticsearch基础操作

2023-11-07

介绍ES的基本操作。如创建索引、mappings、doc的一些基本操作。在doc操作中将分别介绍查询单条数据和多条数据。通过DSL的方式和JAVA api的方式体现。

3.1 索引操作

索引操作是一种很危险的操作。索引就像相当于关系型数据库的表。在操作表索引的需要慎重慎重再慎重。不慎重操作就会导致数据的丢失。

3.1.1 创建索引

ES 操作数据的第一步就是创建索引。可以按照需求对进行主分片和副分片的设置。

DSL操作
PUT /${index_name} 
{   "settings":{} 
    "mappings":{} 
}
  1. 创建索引是通过PUT的形式。
  2. index_name:就是索引名称
  3. settings:可以设置主分片和副分片数
  4. mappings:可以设置JSON字段的映射

假如:需要设置主分片数为2(默认5)、副分片数为15(默认0)索引名称为hotel1的索引则可以DSL语句

PUT hoteld1
{
  "settings": {
    "number_of_shards": 2,
    "number_of_replicas": 15
  },
  "mappings": {
    "properties": {
      "title":{
        "type": "text"
      },
      "city":{
        "type": "text"
      },
      "price":{
        "type": "double"
      }
    }
  }
}

3.1.2 删除索引

删除索引 慎重操作

DSL操作
DELETE /${index_name}
  1. DELETE 请求方式
  2. index_name:为索引名称

假如:删除上一步创建的索引hotel1

DELETE hoteld1

// 相应结果
{
  "acknowledged" : true
}

3.1.3 关闭索引

有些时候暂时不想要某一索引了,但是过一段时间又想要这个索引。所以是不能直接删除这个索引的。这个时候就需要用到关闭索引了。索引关闭时期是不能够查询文档和修改文档的。

DSL
POST /${index_name}/_close
  1. 请求方式为POST
  2. index_name为索引名称

假如:关闭hotel1索引。查询该索引下的数据、修改数据。看返回结果。

  1. 关闭hotel1
POST /hotel1/_close

// 结果
{
  "acknowledged" : true,
  "shards_acknowledged" : true,
  "indices" : {
    "hoteld1" : {
      "closed" : true
    }
  }
}

  1. 操作索引中的数据
// 新增
POST hoteld1/_doc/002
{
  "title":"如家",
  "city":"145",
  "price":222.00
}
// 删除
DELETE hoteld1/_doc/001

// 都是下方结果
{
  "error" : {
    "root_cause" : [
      {
        "type" : "index_closed_exception",
        "reason" : "closed",
        "index_uuid" : "mbKcYEvyTeqvp_KL9cB4oQ",
        "index" : "hoteld1"
      }
    ],
    "type" : "index_closed_exception",
    "reason" : "closed",
    "index_uuid" : "mbKcYEvyTeqvp_KL9cB4oQ",
    "index" : "hoteld1"
  },
  "status" : 400
}

3.1.4 打开索引

打开索引后。该索引下面的数据都可以操作了。

DSL
POST /${index_name}/_open 
  1. 请求方式:POST
  2. index_name:将要打开的索引名称

3.1.5 索引别名

别名是指给一个或者多个索引定义另外一个名称,使索引别名和索引之间可以建立某种逻辑关系。可以用别名来标识索引别名和索引之间的关联关系。

假如:酒店日志是根据月来简历索引的,当我们想要根据一个索引去查询这些索引的数据时就需要用到了索引别名。
假如现在是4月份。那么就已经创建了三个索引日志了。january_log、february_log、march_log。创建索引别名last_three_month就可以根据别名查询数据了。

关系图
索引别名和索引包含关系图.png

示例
1. 创建 january_log、february_log、march_log三个索引 三个mappings都一样。
PUT january_log、february_log、march_log
{ 
    "mappings":{ 
        "properties":{ 
            "uid":{              
                "type":"keyword" 
            }, 
            "hotel_id":{        
                "type":"keyword" 
            }, 
            "check_in_date":{   
                "type":"keyword" 
            } 
        } 
    } 
}
2. 分别像三个索引插入一条数据

DSL

POST /march_log/_doc/001 
{                             
  "uid":"001", 
  "hotel_id":"33224", 
  "check_in_date":"2021-02-23" 
}

POST /january_log/_doc/001 
{                             
  "uid":"001", 
  "hotel_id":"33224", 
  "check_in_date":"2021-02-23" 
}


POST /february_log/_doc/001 
{                             
  "uid":"001", 
  "hotel_id":"33224", 
  "check_in_date":"2021-02-23" 
}


3. 创建索引别名

DSL

POST /_aliases
{ 
  "actions": [ 
    { 
      "add": {   //为索引january_log建立别名last_three_month 
        "index": "january_log", 
        "alias": "last_three_month" 
      } 
    }, 
    { 
      "add": {   //为索引february_log建立别名last_three_month 
        "index": "february_log", 
        "alias": "last_three_month" 
      } 
    }, 
    { 
      "add": {   //为索引march_log建立别名last_three_month 
        "index": "march_log", 
        "alias": "last_three_month" 
      } 
    } 
  ] 
}

// 相应结果
{
  "acknowledged" : true
}
  1. 请求方式:POST
  2. _aliases:路径
  3. actions
    1. add:标识添加索引和别名做关联
      1. index:索引名称
      2. alias:别名名称
4. 查询索引别名信息

DSL

GET /last_three_month/_search
{
  "query": {
    "match": {
      "uid": "001"
    }
  }
}

结果:

{
  "took" : 28,
  "timed_out" : false,
  "_shards" : {
    "total" : 3,
    "successful" : 3,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 3,
      "relation" : "eq"
    },
    "max_score" : 0.2876821,
    "hits" : [
      {
        "_index" : "february_log",  // 索引名
        "_type" : "_doc",
        "_id" : "001",
        "_score" : 0.2876821,
        "_source" : {
          "uid" : "001",
          "hotel_id" : "33224",
          "check_in_date" : "2021-02-23"
        }
      },
      {
        "_index" : "january_log",   // 索引名
        "_type" : "_doc",
        "_id" : "001",
        "_score" : 0.2876821,
        "_source" : {
          "uid" : "001",
          "hotel_id" : "33224",
          "check_in_date" : "2021-02-23"
        }
      },
      {
        "_index" : "march_log",   // 索引名
        "_type" : "_doc",
        "_id" : "001",
        "_score" : 0.2876821,
        "_source" : {
          "uid" : "001",
          "hotel_id" : "33224",
          "check_in_date" : "2021-02-23"
        }
      }
    ]
  }
}

查询索引别名会把这三个索引下面的符合的数据都查询出来。

注意:
当一个索引别名只包含一个索引的时候,新增数据或者修改数据时可以通过别名来新增。但是当一个别名对应多个索引的时候操作数据的时候就会报错。因为没有指定的情况下别名不知道分发到哪个索引进行数据操作。

验证下上面的想法。
DSL

POST /last_three_month/_doc/002
{                             
  "uid":"002", 
  "hotel_id":"33225", 
  "check_in_date":"2021-02-23" 
}

// 结果
{
  "error" : {
    "root_cause" : [
      {
        "type" : "illegal_argument_exception",
        "reason" : "no write index is defined for alias [last_three_month]. The write index may be explicitly disabled using is_write_index=false or the alias points to multiple indices without one being designated as a write index"
      }
    ],
    "type" : "illegal_argument_exception",
    "reason" : "no write index is defined for alias [last_three_month]. The write index may be explicitly disabled using is_write_index=false or the alias points to multiple indices without one being designated as a write index"
    //没有为别名[last_three_month]定义写索引。可以使用is_write_index=false显式禁用写索引,或者别名指向多个索引,而没有一个索引被指定为写索引
  },
  "status" : 400
}


上方索引关联别名的情况可以根据 is_write_index 参数来解决。

POST _aliases
{
  "actions": [
    {
      "add": {
        "index": "january_log",
        "alias": "last_three_month",
        "is_write_index":true
      }
    }
  ]
}

  1. is_write_index:将索引设置为可以文档可操作索引

在操作上述添加文档操作

POST /last_three_month/_doc/002
{                             
  "uid":"002", 
  "hotel_id":"33225", 
  "check_in_date":"2021-02-23" 
}

{
  "_index" : "january_log",
  "_type" : "_doc",
  "_id" : "002",
  "_version" : 1,
  "result" : "created",
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 1,
  "_primary_term" : 1
}


别名的用途

别名可以根据随着业务的增长需要扩充索引的分片时可以用到。因为主分片再创建索引的时候就不能够更改了。

  1. 创建索引别名
  2. 项目中的查询索引名称改为索引别名名称
  3. 老索引 关联 索引名称
  4. 创建新索引
  5. 新索引同步老索引数据
  6. 新索引关联索引别名,老索引删除索引
  7. 项目长时间稳定后就可以把老索引给删除掉了。

索引别名解决主分片新增问题.png
示例:

  1. 创建hoteld_1 && 和写入数据
PUT hoteld_1
{
  "settings": {
    "number_of_shards": 2,
    "number_of_replicas": 15
  },
  "mappings": {
    "properties": {
      "title":{
        "type": "text"
      },
      "city":{
        "type": "text"
      },
      "price":{
        "type": "double"
      }
    }
  }
}

POST /hotel_1/_doc/001 
{                                              
   "title":"好再来酒店", 
   "city":"青岛",  
   "price":578.23 
}

  1. 创建别名并关联
POST /_aliases
{
  "actions": [
    {
      "add": {
        "index": "hoteld_1",
        "alias": "hoteldAlias"
      }
    }
  ]
}
  1. 查询数据 进行验证
GET /hoteldAlias/_search
{
  "query": {
    "match": {
      "title": "再来"
    }
  }
}

{
  "took" : 4,
  "timed_out" : false,
  "_shards" : {
    "total" : 2,
    "successful" : 2,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 0.5753642,
    "hits" : [
      {
        "_index" : "hoteld_1",
        "_type" : "_doc",
        "_id" : "001",
        "_score" : 0.5753642,
        "_source" : {
          "title" : "好再来酒店",
          "city" : "青岛",
          "price" : 578.23
        }
      }
    ]
  }
}

  1. 创建新索引 并设置分片数 && 同步新索引的数据
PUT hoteld_2
{
  "settings": {
    "number_of_shards": 1,
    "number_of_replicas": 0
  },
  "mappings": {
    "properties": {
      "title":{
        "type": "text"
      },
      "city":{
        "type": "text"
      },
      "price":{
        "type": "double"
      }
    }
  }
}

POST /hotel_2/_doc/001 
{                                              
   "title":"好再来酒店", 
   "city":"青岛",  
   "price":578.23 
}

  1. 新索引绑定索引别名 老索引删除索引别名关联
POST /_aliases
{
  "actions": [
    {
      "add": {
        "index": "hoteld_2",
        "alias": "hoteldAlias"
      }
    },
    {
      "remove": {
        "index": "hoteld_1",
        "alias": "hoteldAlias"
      }
    }
  ]
}

  1. 查询数据
GET /hoteldAlias/_search
{
  "query": {
    "match": {
      "title": "再来"
    }
  }
}

结果
{
  "took" : 0,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 0.5753642,
    "hits" : [
      {
        "_index" : "hotel_2",
        "_type" : "_doc",
        "_id" : "001",
        "_score" : 0.5753642,
        "_source" : {
          "title" : "好再来酒店",
          "city" : "青岛",
          "price" : 578.23
        }
      }
    ]
  }
}


3.2 映射操作

映射操作就相当于关系型数据库中表字段的设置。作为无模式搜索引擎,Es可以在数据写入时猜测数据字段的类型。但是有可能猜的不对,这时候就需要我们在创建索引的时候来设置每个字段的类型了。
本节首先介绍映射的创建、查看和修改操作,然后详细介绍ES中的基本数据类型和复杂的数据类型,并且会对常用的类型用法进行示范,最后介绍映射的常用参数和动态映射的使用。

3.2.1查看映射

GET /${index_name}/_mapping


// 用例
GET /hoteld/_mapping

{
  "hoteld" : {
    "mappings" : {
      "properties" : {
        "city" : {
          "type" : "keyword"
        },
        "price" : {
          "type" : "double"
        },
        "title" : {
          "type" : "text"
        }
      }
    }
  }
}

  1. 请求方式:POST
  2. index_name:索引名称

3.2.2 扩展映射

映射中的类型是不能修改的。但是可以扩展索引中的映射字段。最常见的增加字段和为Object对象类型新增字段。

POST /${index_name}/_mapping 
{ 
  "properties": { 
    "tag": {                  //索引中新增字段tag,类型为keyword 
      "type": "keyword" 
    } 
  } 
}

这样就新增了一个字段

POST /hoteld/_mapping
{
  "properties":{
    "tag":{
      "type":"keyword"
    }
  }
}
  1. 请求方式:POST
  2. index_name:索引名称

3.2.3 基本数据类型

1. keyword 类型

keyword类型是不进行切分的字符串类型。这里的“不进行切分”指的是:在索引时,对keyword类型的数据不进行切分,直接构建倒排索引。在现实场景中,keyword经常用于描述姓名、产品类型、用户ID、URL和状态码等。keyword类型数据一般用于比较字符串是否相等,不对数据进行部分匹配,因此一般查询这种类型的数据时使用term查询。
示例:
创建一个人名索引,姓名设置为keyword

PUT /user
{
  "mappings": {
    "properties": {
      "name":{
        "type": "keyword"
      }
    }
  }
}

POST /user/_doc/001
{
  "name":"小白兔"
}

查询数据
GET /user/_search
{
  "query": {
    "term": {
        "name": "小白"
    }
  }
}

{
  "took" : 39,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 0,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  }
}
--------------------------------------------------------------------------------------------
GET /user/_search
{
  "query": {
    "term": {
        "name": "小白兔"
    }
  }
}

{
  "took" : 0,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 0.2876821,
    "hits" : [
      {
        "_index" : "user",
        "_type" : "_doc",
        "_id" : "001",
        "_score" : 0.2876821,
        "_source" : {
          "name" : "小白兔"
        }
      }
    ]
  }
}


keyword类型:是String类型,不会拆分进行倒排索引。所以在用trem查询的时候是精确匹配。

2. text类型

Text是可切分的字符串类型。可以按照相对应的切词算法对文本进行切分,然后创建倒排索引。对该类型会按照对应的切词算法进行切分。然后对切分后的部分匹配打分。

例如,一个酒店搜索项目,我们希望可以根据酒店名称即title字段进行模糊匹配,因此可以设定title字段为text字段,建立酒店索引的DSL如下:

PUT /hotel
{
  "mappings": {
    "properties": {
      "title":{
        "type": "text"
      }
    }
  }
}

写入一条数据
POST /hotel/_doc/001
{
  "title":"小白酒店"
}

使用trem查询。观察是否能搜索到刚刚添加的数据
GET /hotel/_search
{
  "query": {
    "term": {
      "title": {
        "value": "小白酒店"
      }
    }
  }
}

结果
{
  "took" : 460,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 0,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  }
}


根据结果可以看到trem是精确匹配。Text类型进行了切分所以当所以搜素精确查询时是获取不到数据的。一般情况下,搜索text类型的数据时应使用match搜索

GET /hotel/_search
{
  "query": {
    "match": {
      "title": "酒店"
    }
  }
}

结果

{
  "took" : 0,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 0.5753642,
    "hits" : [
      {
        "_index" : "hotel",
        "_type" : "_doc",
        "_id" : "001",
        "_score" : 0.5753642,
        "_source" : {
          "title" : "小白酒店"
        }
      }
    ]
  }
}

3.数值类型

数值类型可以分为:long、integer、short、byte、double、float、half_float、scaled_float和unsigned_long。提升存储空间和搜索索引的效率,在实际应用中,在满足需求的情况下应尽可能选择范围小的数据类型
取值范围:https://www.elastic.co/guide/en/elasticsearch/reference/current/number.html

image.png
示例:

PUT /hotel
{ 
    "mappings":{ 
        "properties":{ 
            "title":{ 
                "type":"text" 
            }, 
            "city":{ 
                "type":"keyword" 
            }, 
            "price":{             
                "type":"double" 
            }, 
            "star":{               
                "type":"byte" 
            }, 
            "comment_count":{       
                "type":"integer" 
            } 
        } 
    } 
}

// 插入数据
POST /hotel/_doc/001
{
  "title":"小白酒店",
  "price":"301"
}

// 查询price300到400的酒店

GET /hotel/_search
{
  "query": {
    "range": {
      "price": {
        "gte": 300,
        "lte": 400
      }
    }
  }
}

// 结果
{
  "took" : 281,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "hotel",
        "_type" : "_doc",
        "_id" : "001",
        "_score" : 1.0,
        "_source" : {
          "title" : "小白酒店",
          "price" : "301"
        }
      }
    ]
  }
}

4.Boolean类型

true false

判断酒店房间是否满房

// 新增满房字段 字段类型为Boolean
POST /hotel/_mapping
{
  "properties":{
    "full_room":{
      "type":"boolean"
    }
  }
}
// 添加数据
POST /hotel/_doc
{
  "title":"小周酒店",
  "full_room": true
}
// 查询满房的数据 使用trem
GET /hotel/_search
{
  "query": {
    "term": {
      "fool_room":true
    }
  }
}
// 结果
{
  "took" : 12,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 0.2876821,
    "hits" : [
      {
        "_index" : "hotel",
        "_type" : "_doc", 
        
        "_id" : "HL8EVYYBY_9l3N9bI2fM",
        "_score" : 0.2876821,
        "_source" : {
          "title" : "小周酒店",
          "fool_room" : true
        }
      }
    ]
  }
}

5.Date类型

在ES中,日期类型的名称为date。ES中存储的日期是标准的UTC格式。下面定义索引hotel,该索引有一个create_time字段,现在把它定义成date类型。

一般使用如下形式表示日期类型数据:

  1. 格式化的日期字符串。·
  2. 毫秒级的长整型,表示从1970年1月1日0点到现在的毫秒数。·
  3. 秒级别的整型,表示从1970年1月1日0点到现在的秒数。

日期类型的默认格式为strict_date_optional_time||epoch_millis。其中,strict_date_optional_time的含义是严格的时间类型,支持yyyy-MM-dd、yyyyMMdd、yyyyMMddHHmmss、yyyy-MM-ddTHH:mm:ss、yyyy-MM-ddTHH:mm:ss.SSS和yyyy-MM-ddTHH:mm:ss.SSSZ等格式,epoch_millis的含义是从1970年1月1日0点到现在的毫秒数
日期类型默认不支持yyyy-MM-dd HH:mm:ss格式,如果经常使用这种格式,可以在索引的mapping中设置日期字段的format属性为自定义格式。下面的示例将设置create_time字段的格式为yyyy-MM-dd HH:mm:ss:
用例

PUT /hotel 
{ 
    "mappings":{ 
        "properties":{ 
            "title":{ 
                "type":"text" 
            }, 
            "city":{ 
                "type":"keyword" 
            }, 
            "price":{ 
                "type":"double" 
            }, 
            "create_time":{           
                "type":"date" 
            } 
        } 
    } 
}

// 使用format字段
"createDate1":{
  "type":"date",
  "format":"yyyy-MM-dd hh:mm:ss"
}

3.2.4 复杂数据类型

1. 数组类型

ES数组没有定义方式。其方式是开箱即用的,及无需事先声明。在写入数据时使用[]括起来就行了。

POST /hotel/_doc
{
  "city":["1","145"]
}

但是如果存储了[]的方式。存储时如果不是按照数组方式则会报错。

2. 对象类型

ES对象没有定义方式。也是开箱即用的。无需声明。插入数据的时候直接插入就可以了。
但是也可以设置映射的方式来使用。
比如: 创建一个pojo对象 里面有name 和 agel两个字段。

POST /hotel/_mappings
{
  "properties":{
    "pojo1":{
      "properties":{
        "name":{
          "type":"keyword"
        },
        "age":{
          "type":"integer"
        }
      }
      
    }
  }
}

3.地理类型

可以存储地理位置

类型设置为:geo_point

POST /hotel/_mappings
{
  "properties":{
    "location":{
      "type":"geo_point" // 地理类型
    }
  }
}

3.2.5 动态映射

当字段没有定义的时候,存储数据的时候会根据存入的数据自动设置字段的数据类型。这样称为动态操作。但是可能自动生成的映射不符合我们的使用。所以最好还是自己设置字段类型。提前定义好数据类型并将索引创建语句纳入SVN或Git管理范围是良好的编程习惯,同时还能增强项目代码的连贯性和可读性。

image.png

3.2.6 多字段

针对同一个字段,有时需要不同的数据类型,这通常表现在为了不同的目的以不同的方式索引相同的字段。

比如name字段有时候需要分词搜索,有需要进行排序。这是name字段就需要两个类型了text 和 keyword

POST /hotel/_mappings
{
  "properties":{
    "name":{
      "type":"text",
      "fields":{
        "user_name":{
          "type":"keyword"
        }
      }
    }
  }
}

POST /hotel/_doc
{
  "name":"A B"
}
{
  "name":"B B"
}
{
  "name":"C B"
}
{
  "name":"D B"
}

// 查询分词后为包含B的并且通过name排序
GET /hotel/_search
{
  "query": {
    "match": {
      "name": "A B"
    }
  },
  "sort": [
    {
      "name.user_name": {
        "order": "desc"
      }
    }
  ]
}

3.3文档操作

使用ES构建搜索引擎时需要经常对文档进行操作。除了简单的单条文档操作,有时还需要进行批量操作。本节将介绍文档的各种日常操作。此外,在生产环境中,对文档的批量操作一般需要借助编程语言来完成,因此在介绍DSL的同时本节还将演示Java客户端的使

3.3.1 单条插入文档

DSL
POST /${index_name}/_doc/_id
{
  ...
}
  1. 请求方式:POST。
  2. index_name: 索引名称。
  3. _doc:文档路径。
  4. _id:自定义的id。不指定随机数。
JAVA API 分两种方式插入
1. spring-boot-starter-data-elasticsearch
@Data
@Document(indexName = "hoteld")
public class Hotel1 {

    @Id
    private String id;

    private String title;

    private String city;

    private Double price;
}
/**
 * @author liruiqing
 */
public interface EsRepository extends CrudRepository<Hotel1,String> {

    /**
     * 根据 title 查询符合的酒店
     * @param title
     * @return
     */
    List<Hotel1> findByTitleLike(String title);
}
public void singleIndexDoc(Hotel1 hotel1) {
        // 单条插入
        Hotel1 save = repository.save(hotel1);
        // 多条插入
        List<Hotel1> hotel1s = new ArrayList<>();
        repository.saveAll(hotel1s);
        System.out.println("id" + hotel1);
}

2. elasticsearch-rest-high-level-client
@Autowired
private RestHighLevelClient restHighLevelClient;

public void singleIndexDoc(Map<String,Object> hotel, String indexName, String indexId) throws IOException {
    IndexRequest indexRequest = new IndexRequest(indexName).id(indexId).source(hotel);
    IndexResponse indexResponse = restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);
    // 获取索引名称
    String index = indexResponse.getIndex();
    // 获取插入索引的id
    String id = indexResponse.getId();
    // 获取版本号
    long version = indexResponse.getVersion();
    System.out.println("index:"+index + "id" + id + "version" + version);
}

   @Test
    void contextLoads() {
        HashMap<String, Object> map = new HashMap<>();
        map.put("id","002");
        map.put("price",33.0);
        map.put("city","145");
        map.put("title","不好就不要再来");
        try {
            esUtils.singleIndexDoc(map,"hoteld","002");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

3.3.2 多条文档插入

DSL
POST /_bulk                           //批量请求 
{"index":{"_index":"${index_name}"}}  //指定批量写入的索引 
{}                                  //设定写入的文档内容 
{"index":{"_index":"${index_name}"}} 
{}                                  //设定写入的文档内容 

测试

POST /_bulk
{"index":{"_index":"hoteld"}}
{"city":145,"price":22.3,"title":"在也不来酒店"}
{"index":{"_index":"hoteld"}}
{"city":145,"price":22.3,"title":"在也不来酒店"}

  1. 请求方式:POST
  2. _bulk:批量插入path
  3. index_name:索引名称
  4. 后面跟要插入的数据。
  5. 上面测试是没有指定文档id的。也可以指定文档id。
    1. {“index”:{“_index”:“KaTeX parse error: Expected 'EOF', got '}' at position 14: {index_name}"}̲,"id":{"_id":"{doc_id}”}}
POST /_bulk
{"index":{"_index":"hoteld"},"id":{"_id":"008"}}
{"city":145,"price":22.3,"title":"在也不来酒店"}

JAVA API 分两种方式
1. spring-boot-starter-data-elasticsearch
public void singleIndexDoc(Hotel1 hotel1) {
        // 单条插入
        Hotel1 save = repository.save(hotel1);
        // 多条插入
        List<Hotel1> hotel1s = new ArrayList<>();
        repository.saveAll(hotel1s);
        System.out.println("id" + hotel1);
    }
2. elasticsearch-rest-high-level-client
/**
*
* @param hotels 需要批量插入的数据
* @param indexName 索引名称
* @throws IOException
*/
public void bulkIndexDoc(List<Map<String,Object>> hotels, String indexName){
    BulkRequest bulkRequest = new BulkRequest(indexName);
    for (Map<String, Object> map : hotels) {
        String docId = map.get("id").toString();
        IndexRequest indexRequest = new IndexRequest(indexName).id(docId).source(map);
        bulkRequest.add(indexRequest);
    }
    try {
        BulkResponse bulkResponse = bulkResponse = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
        if (bulkResponse.hasFailures()){
            System.out.println("bulk fail,message" + bulkResponse.buildFailureMessage());
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

3.3.3单条更新

DSL
POST /${index_name}/_update/${doc_id}
{
  "doc": {
    "city":222
  }
}

  1. 请求方式:POST
  2. index_name:索引名称
  3. doc_id:需要更新的文档id
  4. doc:里面是需要更新的字段。

演示:

POST /hoteld/_update/001
{
  "doc": {
    "city":222
  }
}

结果:

{
  "_index" : "hoteld",
  "_type" : "_doc",
  "_id" : "001",
  "_version" : 2,
  "_seq_no" : 2,
  "_primary_term" : 3,
  "found" : true,
  "_source" : {
    "city" : 222,
    "price" : 33.0,
    "id" : "001",
    "title" : "不好就不要再来"
  }
}


由结果可知:city变为了222。version变成了2.

JAVA API分两种形式
1. spring-boot-starter-data-elasticsearch
/**
* 单条更新数据
*/
public void updateSingleIndexDoc(Hotel1 hotel1){
    repository.save(hotel1);
}

@Test
    void updateSingleIndexDoc(){
        Hotel1 hotel1 = new Hotel1();
        hotel1.setId("001");
        hotel1.setCity("888");
        hotel1.setPrice(25.1);
        hotel1.setTitle("好再来酒店");
        esUtils.updateSingleIndexDoc(hotel1);
    }

save接口只要传了文档id 如果该id已经被占用则就更新数据。否则增加数据。

2. elasticsearch-rest-high-level-client
    /**
     * 单条更新数据
     * @param source 需要更新的数据
     * @param index 索引
     * @param docIdKey 文档id
     */
    public void updateSingleIndexDoc(Map<String,Object> source,String index,String docIdKey){
        UpdateRequest updateRequest = new UpdateRequest(index,docIdKey);
        updateRequest.doc(source);
        try {
            UpdateResponse update = restHighLevelClient.update(updateRequest, RequestOptions.DEFAULT);
            String index1 = update.getIndex();
            long version = update.getVersion();
            String id = update.getId();
            System.out.println("index:"+index1 + " version:" + version + "id : " + id);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

 @Test
    void updateSingleIndexDoc(){
        HashMap<String, Object> map = new HashMap<>();
        map.put("id","001");
        map.put("price",33.0);
        map.put("city","999");
        map.put("title","不好就不要再来");
        esUtils.updateSingleIndexDoc(map,"hoteld","001");
    }
通过创建UpdateRequest并设置索引、文档id。把需要更新的数据通过doc()放进去。

调用restHighLevelClient.update方法就可以了。

3.3.4 批量更新

DSL
POST _bulk
{"update":{"_index":"${index_name}","_id":"${doc_id}"}}
{"doc":{"city":"999","title":"你再来","name":"没有的字段"}}
  1. 请求方式:POST
  2. _bulk :请求路径
  3. update:代表是更新语句
  4. index_name:索引名称
  5. doc_id:文档id

注意:如果更新了一个从来没有过的字段。那么就会把这个字段存储到改文档中。

JAVA API分两种形式
1. spring-boot-starter-data-elasticsearch
  1. saveAll接口就可以了。
2.elasticsearch-rest-high-level-client
 /**
     * 批量更新
     * @param sourceList 需要批量更新的数据
     * @param index 索引名称
     */
    public void updateListDocIndex(List<Map<String,Object>> sourceList,String index){
        BulkRequest bulkRequest = new BulkRequest();

        for (Map<String, Object> stringObjectMap : sourceList) {
            UpdateRequest updateRequest = new UpdateRequest(index, stringObjectMap.get("id").toString());
            // 删除id字段 要不然文档数据中就会多一个id字段。
            updateRequest.doc(stringObjectMap);
            bulkRequest.add(updateRequest);
        }
        try {
            BulkResponse bulkResponse = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
            if (bulkResponse.hasFailures()){
                System.out.println("bulk fail,message" + bulkResponse.buildFailureMessage());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
  1. 创建BulkRequest()对象。然后把组装好的UpdateRequest添加进去。调用bulk方法即可。

3.3.5 根据条件更新

有的时候我们需要根据某些条件更新。就像关系型数据库中的update table set title = ‘’ where name = ‘小白’ 这种方式更新name为小白的数据。在ES中也有类型的场景。

DSL
POST hoteld/_update_by_query
{
  "query": {
    "term": {
      "price": {
        "value": 22
      }
    }
  },
  "script": {
    "source": "ctx._source['city']='22'",
    "lang": "painless"
  }
}
  1. 请求方式:POST
  2. query:是查询条件
  3. script:source就是需要更新的字段
  4. 如果不传query则是全量更新
JAVA API分两种形式
1. spring-boot-starter-data-elasticsearch
/**
     * 根据索引id更新数据
     * @param docId
     */
    public void updateSingleIndexDoc(String docId){
        Document document = Document.create();
        document.putIfAbsent("title","你是不是饿的慌");
        UpdateQuery build = UpdateQuery.builder(docId).withDocument(document).build();
        UpdateResponse updateResponse = elasticsearchRestTemplate.update(build, IndexCoordinates.of("hoteld"));
        System.out.println(updateResponse);
    }
  1. elasticsearchRestTemplate.update():根据docId为条件更新文档信息。相当于只更新一条
  2. Document:需要更新的字段
 /**
     * 根据条件批量更新字段
     */
    public void updateDoc(){
        NativeSearchQuery nativeSearchQuery = new NativeSearchQuery(QueryBuilders.matchQuery("title","不"));
        UpdateQuery updateQuery = UpdateQuery.builder(nativeSearchQuery).withScriptType(ScriptType.INLINE).withScript("ctx._source['city']='44'").withLang("painless").build();
        ByQueryResponse byQueryResponse = elasticsearchRestTemplate.updateByQuery(updateQuery, IndexCoordinates.of("hoteld"));
        List<ByQueryResponse.Failure> failures = byQueryResponse.getFailures();
        System.out.println(failures);
    }
  1. elasticsearchRestTemplate.updateByQuery():根据条件过滤 批量更新符合的数据。
  2. 需要用到script函数。
2. elasticsearch-rest-high-level-client
  /**
     * 根据条件批量更新
     * @param index 索引名称
     * @param name 根据名称条件更新城市
     */
    public void updateByQuery(String index,String name,String city){
        UpdateByQueryRequest updateByQueryRequest = new UpdateByQueryRequest(index);
        updateByQueryRequest
                .setQuery(QueryBuilders.matchQuery("name",name))
                .setScript(new Script("ctx._source['city']='"+city+"'"));
        try {
            BulkByScrollResponse bulkByScrollResponse = restHighLevelClient.updateByQuery(updateByQueryRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

3.3.6 删除单条文档

删除单条文档通常都是根据文档id删除的。

DSL
DELETE /${index_name}/_doc/${doc_id}
  1. 请求方式:DELETE
  2. index_name:索引名称
  3. doc_id:文档id
JAVA API分两种形式
1. spring-boot-starter-data-elasticsearch
 /**
     * 根据文档id删除文档数据
     * @param index 索引名称
     * @param docId 文档id
     */
    public void deleteByDocId(String index,String docId){
        String id = elasticsearchRestTemplate.delete(docId, IndexCoordinates.of(index));
        System.out.println(id);
    }
2. elasticsearch-rest-high-level-client
 /**
     * 根据文档id删除文档数据
     * @param index 索引名称
     * @param docId 文档id
     */
    public void deleteByDocId(String index,String docId){
        DeleteRequest deleteRequest = new DeleteRequest(index,docId);
        try {
            DeleteResponse delete = restHighLevelClient.delete(deleteRequest, RequestOptions.DEFAULT);
            System.out.println(delete.getId());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

3.3.7 批量删除数据

批量删除不需要提供JSON数据

DSL
PUT /_bulk
{"delete":{"_index":${index_name},"_id":${doc_id}}}
JAVA API分两种形式
1. spring-boot-starter-data-elasticsearch
/**
* 批量根据ids删除文档
* @param docIds 批量删除
*/
public void deleteByDocIds(Set<String> docIds){
    repository.deleteAllById(docIds);
}
2. elasticsearch-rest-high-level-client
 /**
     * 根据id列表批量删除
     * @param index 索引名称
     * @param docIds 文档id列表
     */
    public void deleteByDocIdList(String index,List<String> docIds){
        BulkRequest bulkRequest = new BulkRequest(index);
        for (String docId : docIds) {
            DeleteRequest deleteRequest = new DeleteRequest(index, docId);
            bulkRequest.add(deleteRequest);
        }
        try {
            BulkResponse bulk = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
            if (bulk.hasFailures()) {
                System.out.println(bulk.getIngestTookInMillis());
            }
            for (BulkItemResponse item : bulk.getItems()) {
                System.out.println(item.getId());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

3.3.8 根据条件删除数据

根据条件删除数据,跟更新一样只要,只是不需要写script字段。只需要query字段。

DSL
POST /${index_name}/_delete_by_query
{
  "query":{
    ....
  }
}
  1. 请求方式:POST
  2. index_name:索引名称
  3. _delete_by_query:路径名称
  4. query:需要删除的请求条件
JAVA API分两种形式
1 spring-boot-starter-data-elasticsearch
public void deleteByQuery(String index){
        NativeSearchQuery nativeSearchQuery = new NativeSearchQuery(QueryBuilders.termQuery("city", "22"));
        ByQueryResponse byQueryResponse = elasticsearchRestTemplate.delete(nativeSearchQuery, String.class, IndexCoordinates.of(index));
        System.out.println(byQueryResponse);
}
2. elasticsearch-rest-high-level-client
/**
     * 根据条件删除符合的的文档数据
     * @param index
     */
    public void deleteByQueryDoc(String index){
        DeleteByQueryRequest deleteByQueryRequest = new DeleteByQueryRequest(index);
        deleteByQueryRequest.setQuery(QueryBuilders.termQuery("city","145"));
        try {
            BulkByScrollResponse bulkByScrollResponse = restHighLevelClient.deleteByQuery(deleteByQueryRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

3.Elasticsearch基础操作 的相关文章

  • Elastic Beanstalk 添加多个 ssl 证书

    我有一个 Docker Django api 应用程序 可以从多个域 abc xyx com 或 def lmn com 调用 我已从 Elastic beanstalk 中的配置控制台成功添加了 abc xyz com 的 ssl 证书
  • Elasticsearch 在 Mac 上存储数据的位置

    类似的问题this one https stackoverflow com questions 24694201 where are data files of elasticsearch on a standard debian inst
  • Elasticsearch 通过 id 获取不起作用但文档存在

    我在 elasticsearch 1 2 0 最近从 1 0 1 升级 上看到 ids 的奇怪行为 搜索检索我的文档 显示 id 的正确值 终端 curl myServer 9200 global search q someField so
  • AWS ElasticSearch Service - 从 CF 模板设置加密选项

    我正在创建一个云形成模板来在AWS中配置elasticsearch服务域 我想将加密下的此属性设置为 true 域的所有流量都需要 HTTPS 但我无法在 AWS 文档中找到执行此操作的方法 用于设置加密属性的其他选项 例如 启用静态数据加
  • 聚合多个递归logstash

    我正在使用带有输入 jdbc 的 Logstash 并且希望通过聚合将一个对象嵌入到另一个对象中 如何使用添加递归 即在另一个对象中添加一个对象 这是一个例子 index my index type test id 1 version 1
  • Facet从elasticsearch中的对象获取所有键

    假设我有以下文档 title Some Title options key5 1 key3 0 key1 1 title Some Title options key2 0 key3 0 key5 1 我想从中获取所有钥匙options使用
  • Java ElasticSearch 配置的节点均不可用

    过去一小时刚刚下载并安装了elasticsearch 1 3 2 打开 IPtables 端口 9200 和 9300 9400 在 etc hosts 中设置我的计算机名称和 ip 头部模块和护理人员安装并运行顺利 本地主机上的curl
  • 连接所有 PostgreSQL 表并创建 Python 字典

    我需要加入allPostgreSQL 表并将它们转换为 Python 字典 数据库中有72张表 总列数大于1600 我编写了一个简单的 Python 脚本 该脚本连接多个表 但由于以下原因无法连接所有表内存错误 https gist git
  • 将 CSV 文件中的数字数据更改为文本

    下面的查询是抓取数据并创建一个 CSV 文件 我遇到的问题是名为 SPLE 的源在数据库中存储数字为 0 1 50 的数据 然而 在 CSV 中 这些数字被收集在 CSV 中 我希望在创建 CSV 时 这些数字能够代表诸如以下的单词 0 T
  • 如何将监听休眠事件的模块与实体本身解耦?

    我有一个由 spring jpa hibernate 驱动的分层 Web 应用程序 现在我正在尝试集成 elasticsearch 搜索引擎 我想要做的是捕获所有 postInsert postUpdate 事件并将这些实体发送到 elas
  • Elasticsearch:带有停用词消除功能的带状疱疹

    我正在尝试实现一个 Elasticsearch 映射来优化大量文本中的短语搜索 根据中的建议本文 http www elasticsearch org blog searching with shingles 我使用 shingle 过滤器
  • 如何修改 Elasticsearch 文档的 _source 字段

    问题 有没有办法从文档的 source 中清除 html html 的剥离可以是周期性的 触发的 或者理想情况下是在索引时即时进行的 我将数据输入到elasticsearch中 并针对分析器进行索引 该分析器在索引之前剥离不需要的htmls
  • 在elasticsearch中存储聊天消息的最佳方式

    我们目前正在实施一项即时通讯系统在我们的平台上 我们需要为我们的用户提供聊天记录并能够显示用户最近进行的 5 次对话 像 Facebook 上的预览一样 事实上 我们必须考虑如何才能存储所有这些数据 我们正在使用弹性搜索我们认为这可能是存储
  • Elasticsearch NodeBuilder 与 TransportClient

    对于其他 Elasticsearch 开发人员来说 这可能是一个非常简单 而且愚蠢 的问题 这两者之间有什么区别 我正在从 Java Web 应用程序连接到远程 Elasticsearch 服务器 到目前为止我一直在使用 Transport
  • ElasticSearch:从 Painless 脚本中的嵌套字段计算 arcDistance

    我需要计算 Painless 脚本内的弧距 但在这种情况下还没有找到访问 geo API 的方法 即 第一点作为参数传递给脚本 这意味着我只获得原始值 第二点是从嵌套文档中读取的 这意味着我无法使用doc myGeoField value
  • 在嵌套热门点击聚合中包含父 _source 字段

    我正在尝试聚合一个字段并使用top hits但我想在响应中包含未包含在嵌套属性映射中的其他字段 目前如果我指定 source include 我只能获取当前嵌套属性中的字段 这是我的映射 my cart mappings propertie
  • Spring Data elasticsearch @Query 注解嵌套对象

    我有两节课 Document public class PracticeQuestion private int userId private List
  • Elasticsearch如何支持涉及多个文档的事务

    我使用elasticsearch和非规范化数据 比如 PUT my index user 1 name John Smith email email protected cdn cgi l email protection dob 1970
  • 连接到 Elasticsearch Heroku 数据库

    我已经在 Heroku 上使用 Bonsai elasticsearch 插件设置了一个入门帐户 我正在尝试通过 Java 应用程序连接到它 但似乎无法通过 Transport Client 或 Elasticsearch 文档页面上解释的
  • Elasticsearch 中的组合非嵌套和嵌套查询

    我想使用 ES 进行书籍搜索 所以我决定将作者姓名和标题 作为嵌套文档 放入索引中 如下所示 curl XPUT localhost 9200 library search books 1 d author one books title

随机推荐

  • SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@xxx] was not registered for synchro

    目录 1 报错场景 2 问题原因及解决办法 1 报错场景 在搞SpringBoot项目的时候 把Mybatis打印日志的配置打开后 发现每条Sql打印的时候都会在前面打印如下的信息 强迫症受不了 得查查为什么 Creating a new
  • sql server数据库备份单个表的结构和数据生成脚本

    文章摘自 博客园随笔 https www cnblogs com wmqiang p 10437607 html 1 使用场景 sql server数据库备份单个表的结构和数据 在我们要修改正式系统的数据的一天或者多条某些数据时候 要执行u
  • 在yoloV5-6 中使用tensorboard

    使用 在train文件中加入 import torch from torch utils tensorboard import SummaryWriter writer SummaryWriter log dir project train
  • Ionic3开发教程 - 更新(5)

    Ionic3开发系列教程Ionic3开发教程 环境准备 1 Ionic3开发教程 开发 2 Ionic3开发教程 发布Android版本 3 Ionic3开发教程 发布IOS版本 4 Ionic3开发教程 更新 5 App新功能开发完成后
  • 示波器的使用总结

    任何好的示波器系统的关键点在于精确地重建波形的能力 称为信号完整性 不同的系统和不同性能的示波器 有不同的实现最高信号完整性的能力 探头也对测量系统的信号完整性有影响 数字示波器 DSO 基本结构 采样 gt A D转换 gt 信号分离器
  • 使用TypeScript重构Axios:让你的项目更加完善

    引言 如果你使用过或者了解过JavaScript 那么在使用其开发的过程中 势必会了解到Axios 我们都知道 它带来便捷与效率的同时 js本身也会伴随着一些不大不小的问题 当用JavaScript开发大型项目时 因为没有类型检查 所以很多
  • WebSocket的简单入门使用

    WebSocket WebSocket介绍 Java整合WebSocket SpringBoot整合WebSocket WebSocket介绍 1 什么是WebSocket WebSocket 是HTML5一种新的协议 它实现了浏览器与服务
  • C++面试题

    1 中高级C 工程师 2 空类占一个字节 含有虚函数的类占4字节 复制构造函数要传引用 3 为下面代码编写赋值运算符 class CMyString public CMyString char pData nullptr CMyString
  • 家用计算机 阵列,家用电脑如何建立RAID?

    组建RAID系统攻略 RAID全称为 Redundant Array of Inexpensive Disks 中文意思是 独立冗余磁盘阵列 简称磁盘阵列 简单地说 RAID是一种把多块独立的硬盘 物理硬盘 按不同方式组合起来形成一个硬盘组
  • 【Python】保姆级万字讲解:Python中的 pip 和 conda 的理解

    文章目录 一 pip的理解 1 1 安装 1 2 如何使用 1 3 升级 1 4 安装某个版本的包 1 5 卸载或者是更新包 1 6 查看某个包的信息 1 7 查看需要被升级的包 1 8 查看兼容问题 1 9 指定国内源来安装 1 10 下
  • 读懂Word2Vec之Skip-Gram

    本教程将介绍Word2Vec的skip gram神经网络体系结构 我这篇文章的目的是跳过对Word2Vec的一般的介绍和抽象见解 并深入了解其细节 具体来说 我正在深入skipgram神经网络模型 模型介绍 skip gram神经网络模型其
  • eclipse 安装后没有server 没有tomcat

    下载的是eclipse 4 7 M7 但是下载后要配置tomcat时 找不到tomcat 配置过程 1 window gt gt priferences gt gt server gt gt runtime environment gt g
  • JDBC连接数据库_增删改查

    JDBC基础操作 步骤 第一步 下载驱动 第二步 导入驱动 第三步 加载驱动 第四步 驱动管理器运行 获取链接Connection 第五步 通过链接Connection创建数据库操作对象Statement 第六步 通过数据库操作对象Stat
  • 学node的一点小笔记(十二) node+express上传文件,自定义路径

    upload js var express require express var app express var fs require fs 用于解析数据 var bodyParser require body parser 上传文件中间
  • online learning / continual learning / Incremental Learning / Lifelong learning相关论文列表

    2018 Knowledge Distillation by On the Fly Native Ensemble NIPS2018 Memory Replay GANs learning to generate images from n
  • Effective C++ 学习笔记 条款02 尽量以const、enum、inline替换#define

    宁可以编译器替换预处理器 因为或许 define不被视为语言的一部分 当你 define ASPECT RATIO 1 653 名字ASPECT RATIO从未被编译器看到 可能在编译器处理源码前它就被预处理器移走了 于是ASPECT RA
  • Window 对象

    解释 Window 对象表示浏览器中打开的窗口 如果文档包含框架 或 标签 浏览器会为 HTML 文档创建一个 window 对象 并为每个框架创建一个额外的 window 对象 Window 对象属性 属性 描述 closed 返回窗口是
  • 如何使用Aiseesoft Mac Video Enhancer让视频更加清晰

    Aiseesoft Mac它可以让视频更加清晰 并在Mac上旋转侧向视频以纠正角度 它还允许您使用提供的裁剪 剪裁和水印功能编辑视频 小编来教您如何使用Aiseesoft Mac Video Enhancer让视频更加清晰 1 在Mac上添
  • MySQL主从复制详解

    文章目录 1 简介 1 1 应用场景 1 2 复制形式 2 复制原理 3 复制类型 3 1 异步复制 3 2 同步复制 3 3 半同步复制 4 复制方式 4 1 语句复制 Statement格式 4 2 行数据复制 Row格式 4 3 混合
  • 3.Elasticsearch基础操作

    介绍ES的基本操作 如创建索引 mappings doc的一些基本操作 在doc操作中将分别介绍查询单条数据和多条数据 通过DSL的方式和JAVA api的方式体现 3 1 索引操作 索引操作是一种很危险的操作 索引就像相当于关系型数据库的