美文网首页
03-ES基础操作

03-ES基础操作

作者: wshsdm | 来源:发表于2023-04-01 14:58 被阅读0次

    1 索引操作

    1.1 创建索引

    使用ES构建搜索引擎的第一步是创建索引。在创建索引时,可以按照实际需求对索引进行主分片和副分片设置。ES创建索引的请求类型为PUT,其请求形式如下

    put /index_name
    {
       "settings":{
       },
       "mappings":{
       }
    }
    

    变量index_name就是创建的目标索引名称;可以在settings子句内部填写索引相关的设置项,如主分片个数和副分片个数等(主分片个数使用的是系统默认值(默认值为5),并且没有使用副分片个数(默认值为0));可以在mappings子句内部填写数据组织结构,即数据映射。

    1. 指定主分片和副分片个数
    PUT /hotel
    {
      "settings": {
        "number_of_shards": 2,//主分片
        "number_of_replicas": 1//副分片
      },
      "mappings": {
        "properties": {
          
        }
      }
    }
    
    1. 删除索引
    DELETE /hotel
    
    1. 关闭索引

    在有些场景下,某个索引暂时不使用,但是后期可能又会使用,这里的使用是指数据写入和数据搜索。这个索引在某一时间段内属于冷数据或者归档数据,这时可以使用索引的关闭功能。索引关闭时,只能通过ES的API或者监控工具看到索引的元数据信息,但是此时该索引不能写入和搜索数据,待该索引被打开后,才能写入和搜索数据。

    POST /hotel/_close
    
    1. 打开索引

    索引关闭后,需要开启读写服务时可以将其设置为打开状态。

    POST /hotel/_open
    

    1.2 索引别名

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

    1. 例如,我们建立了1月、2月、3月的用户入住酒店的日志索引,假设当前日期是4月1日,需要搜索过去的3个月的日志索引,如果分别去3个索引中进行搜索,这种编码方案比较低效。此时可以创建一个别名first_quarter,设置前面的3个索引的别名为first_quarter,然后在first_quarter中进行搜索即可
    • 首先依次建立january_log、february_log和march_log3个索引
    PUT /january_log
    {
      "mappings":{
        "properties":{
          "uid":{
            "type":"keyword"
          },
          "hotel_id":{
            "type":"keyword"
          },
          "check_in_date":{
            "type":"keyword"
          }
        }
      }
    }
    
    • 在3个索引中写入同一用户在不同月份的入住记录
    POST /january_log/_doc/001
    {
      "uid":"001",
      "hotel_id":"1000",
      "check_in_date":"2023-01-15"
    }
    
    • 建立别名last_three_month,设置上面3个索引的别名为first_quarter
    POST /_aliases
    {
      "actions": [
        {
          "add": {
            "index": "january_log",
            "alias": "first_quarter"
          }
        },{
          "add": {
            "index": "february_log",
            "alias": "first_quarter"
          }
        },{
          "add": {
            "index": "march_log",
            "alias": "first_quarter"
          }
        }
      ]
    }
    
    • 请求在索引first_quarter中搜索uid为001的用户的入住记录,搜索的DSL
    GET /first_quarter/_search
    {
      "query": {
        "term": {
          "uid": {
            "value": "001"
          }
        }
      }
    }
    

    由上面的结果可知,当请求搜索first_quarter的数据时,ES将请求转发到了january_log、february_log和march_log3个索引中;
    当一个别名只指向一个索引时,写入数据的请求可以指向这个别名,如果这个别名指向多个索引(就像上面的例子),则写入数据的请求是不可以指向这个别名的

    1. 别名中的is_write_index属性

    在默认情况下,ES不能确定向first_quarter写入数据时的转发对象。这种情况需要在别名设置时,将目标索引的is_write_index属性值设置为true来指定该索引可用于执行数据写入操作。

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

    将索引别名first_quarter的数据写入转发对象设置为索引january_log之后,再向first_quarter发起写入数据的请求时,ES会将该请求转发到索引january_log中

    1. 用别名表示索引之间的替代关系

    一般在某个索引被创建后,有些参数是不能更改的(如主分片的个数),但随着业务发展,索引中的数据增多,需要更改索引参数进行优化。我们需要平滑地解决该问题,既要更改索引的设置,又不能改变索引名称,这时就可以使用索引别名

    • 首先建立索引hotel_1,设置其主分片个数为5,副分片个数为2
    PUT /hotol_1
    {
      "settings":{
          "number_of_shards":5,
          "number_of_replicas":2
       },
      "mappings":{
        "properties":{
          "title":{
            "type":"text"
          },
          "city":{
            "type":"keyword"
          },
          "price":{
            "type":"double"
          }
        }
      }
    }
    
    • 在数据写入端向hotel_1写入搜索数据,请求的DSL
    POST /hotol_1/_doc/001
    {
      "title":"儒家酒店",
      "city":"沈阳",
      "price":380.00
    }
    
    • 建立别名hotel,请求的DSL
    POST /_aliases
    {
      "actions": [
        {
          "add": {
            "index": "hotol_1",
            "alias": "hotol"
          }
        }
      ]
    }
    
    • 假设过一段时间后酒店索引的分片需要扩展。通过变更索引的方式可以完成扩展。建立索引hotel_2,并设置主分片个数为10,设置副分片个数为2,请求的DSL
    PUT /hotol_2
    {
      "settings":{
          "number_of_shards":10,
          "number_of_replicas":2
       },
      "mappings":{
        "properties":{
          "title":{
            "type":"text"
          },
          "city":{
            "type":"keyword"
          },
          "price":{
            "type":"double"
          }
        }
      }
    }
    
    • 此时hotel_2中的数据已经准备完毕,现在变更别名设置,删除hotel_1的索引别名,设置索引hotel_2的别名为hotel2
    POST /_aliases
    {
      "actions": [
        {
          "remove": {
            "index": "hotol_1",
            "alias": "hotol"
          }
        },
        {
          "add": {
            "index": "hotol_2",
            "alias": "hotol"
          }
        }
      ]
    }
    

    2 映射操作

    2.1 查看映射

    在使用数据之前,需要构建数据的组织结构。这种组织结构在关系型数据库中叫作表结构,在ES中叫作映射。作为无模式搜索引擎,ES可以在数据写入时猜测数据类型,从而自动创建映射。但有时ES创建的映射中的数据类型和目标类型可能不一致。当需要严格控制数据类型时,还是需要用户手动创建映射。

    GET /hotol_1/_mapping
    # 返回结果
    {
      "hotol_1" : {
        "mappings" : {
          "properties" : {
            "city" : {
              "type" : "keyword"
            },
            "price" : {
              "type" : "double"
            },
            "title" : {
              "type" : "text"
            }
          }
        }
      }
    }
    

    2.2 扩展映射

    映射中的字段类型是不可以修改的,但是字段可以扩展。最常见的扩展方式是增加字段和为object(对象)类型的数据新增属性。下面的DSL示例为扩展hotel索引,并增加tag字段

    POST /hotol_1/_mapping
    {
      "properties":{
        "tag":{
          "type":"keyword"
        }
      }
    }
    

    2.3 基本的数据类型

    1. keyword类型

    keyword类型是不进行切分的字符串类型。这里的“不进行切分”指的是:在索引时,对keyword类型的数据不进行切分,直接构建倒排索引;在搜索时,对该类型的查询字符串不进行切分后的部分匹配。keyword类型数据一般用于对文档的过滤、排序和聚合。
    在现实场景中,keyword经常用于描述姓名、产品类型、用户ID、URL和状态码等。keyword类型数据一般用于比较字符串是否相等,不对数据进行部分匹配,因此一般查询这种类型的数据时使用term查询。
    注意:
    对keyword类型使用match搜索进行匹配是不会命中文档,而且返回400错误

    GET /hotol_1/_search
    {
      "query": {
        "term": {
          "city": {
            "value": "阳"
          }
        }
      }
    }
    # 查询不到任何信息
    
    GET /hotol_1/_search
    {
      "query": {
        "match": {
          "city": {
            "value": "阳"
          }
        }
      }
    }
    # 返回
    {
      "error" : {
        "root_cause" : [
          {
            "type" : "parsing_exception",
            "reason" : "[match] query does not support [value]",
            "line" : 5,
            "col" : 18
          }
        ],
        "type" : "parsing_exception",
        "reason" : "[match] query does not support [value]",
        "line" : 5,
        "col" : 18
      },
      "status" : 400
    }
    
    1. text类型

    text类型是可进行切分的字符串类型。这里的“可切分”指的是:在索引时,可按照相应的切词算法对文本内容进行切分,然后构建倒排索引;在搜索时,对该类型的查询字符串按照用户的切词算法进行切分,然后对切分后的部分匹配打分;

    • 模糊查询text字段
    GET /hotol_1/_search
    {
      "query": {
        "match": {
          "title": "酒"
        }
      }
    }
    
    1. 数值类型
      ES支持的数值类型有long、integer、short、byte、double、float、half_float、scaled_float和unsigned_long等。数值类型的数据也可用于对文档进行过滤、排序和聚合
    • 例如:价格范围查询
    GET /hotol_1/_search
    {
      "query": {
        "range": {
          "price": {
            "gte": 350,
            "lte": 400
          }
        }
      }
    }
    
    1. 布尔类型
      布尔类型使用boolean定义,写入或者查询该类型的数据时,其值可以使用true和false,或者使用字符串形式的"true"和"false"。
    2. 日期类型
      在ES中,日期类型的名称为date。ES中存储的日期是标准的UTC格式(世界协调时,Universal Time Coordinated的缩写,中国大陆、中国香港、中国澳门、中国台湾、蒙古国、新加坡、马来西亚、菲律宾、西澳大利亚州的时间与UTC的时差均为+8,也就是UTC+8)。

    一般使用如下形式表示日期类型数据:·格式化的日期字符串。·毫秒级的长整型,表示从1970年1月1日0点到现在的毫秒数。·秒级别的整型,表示从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 /hotol_1/_mapping
    {
      "properties":{
        "create_time":{
          "type":"date",
          "format":"yyyy-MM-dd HH:mm:ss"
        }
      }
    }
    
    • 插入记录
    POST /hotol_1/_doc/002
    {
      "title":"喜来登酒店",
      "city":"沈阳",
      "price":686.5,
      "create_time":"2023-03-01 18:56:18"
    }
    

    2.4 复杂类型

    1. 数组类型

    ES数组没有定义方式,其使用方式是开箱即用的,即无须事先声明,在写入时把数据用中括号[]括起来,由ES对该字段完成定义。

    • 扩展tag字段
    PUT /hotol_1/_mapping
    {
      "properties":{
        "tag":{
          "type":"keyword"
        }
      }
    }
    
    • 插入数据
    POST /hotol_1/_doc/003
    {
      "title":"玫瑰大酒店",
      "city":"沈阳",
      "price":700,
      "create_time":"2023-03-01 17:56:18",
      "tag":["提供免费早餐","有Wifi"]
    }
    
    • 对数组数据进行搜索
    GET /hotol_1/_search
    {
      "query": {
        "term": {
          "tag": {
            "value": "有Wifi"
          }
        }
      }
    }
    
    1. 对象类型

    对象类型也不用事先定义,在写入文档的时候ES会自动识别并转换为对象类型。

    POST /hotol_1/_doc/004
    {
      "title":"玫瑰大酒店",
      "city":"沈阳",
      "price":700,
      "create_time":"2023-03-01 17:56:18",
      "tag":["提供免费早餐","有Wifi"],
      "comment_info":{
        "fav_num": 18,
        "neg_num":20
      }
    }
    
    • 查询索引结构
    GET /hotol_1
    # 返回
    {
      "hotol_1" : {
        "aliases" : { },
        "mappings" : {
          "properties" : {
            "city" : {
              "type" : "keyword"
            },
            "comment_info" : { // 对插入的对象类型自动识别
              "properties" : {
                "fav_num" : {
                  "type" : "long"
                },
                "neg_num" : {
                  "type" : "long"
                }
              }
            },
            "create_time" : {
              "type" : "date",
              "format" : "yyyy-MM-dd HH:mm:ss"
            },
            "price" : {
              "type" : "double"
            },
            "tag" : {
              "type" : "keyword"
            },
            "title" : {
              "type" : "text"
            }
          }
        },
        "settings" : {
          "index" : {
            "routing" : {
              "allocation" : {
                "include" : {
                  "_tier_preference" : "data_content"
                }
              }
            },
            "number_of_shards" : "5",
            "provided_name" : "hotol_1",
            "creation_date" : "1680327849676",
            "number_of_replicas" : "2",
            "uuid" : "5owTZuhWQJOI9_rl71E2eg",
            "version" : {
              "created" : "7160399"
            }
          }
        }
      }
    }
    
    • 对对象类型属性进行查询
    GET /hotol_1/_search
    {
      "query": {
        "range": {
          "comment_info.neg_num": {
            "gte": 10
          }
        }
      }
    }
    
    1. 地理类型

    mapping中指定目标字段的数据类型为geo_point类型

    • 扩展属性location为地理类型
    PUT /hotol_1/_mapping
    {
      "properties":{
        "location":{
          "type":"geo_point"
        }
      }
    }
    
    • 插入数据
    POST /hotol_1/_doc/005
    {
      "title":"商贸饭店",
      "city":"沈阳",
      "price":720,
      "create_time":"2023-03-02 17:56:18",
      "tag":["提供免费早餐","有Wifi"],
      "comment_info":{
        "fav_num": 18,
        "neg_num":20
      },
      "location":{
        "lat":41.48,
        "lon":123.58
      }
    }
    

    2.5 动态映射

    当字段没有定义时,ES可以根据写入的数据自动定义该字段的类型,这种机制叫作动态映射

    2.6 多字段

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

    • 创建索引
    PUT /hotel_order
    {
      "mappings": {
        "properties": {
          "order_id":{
            "type": "keyword"
          },
          "user_name":{
            "type": "text",
            "fields": { //多字段定义
              "user_name_key":{
                "type":"keyword"
              }
            }
          }
        }
      }
    }
    
    • 批量插入多条记录
    POST /_bulk
    {"index":{"_index":"hotel_order","_id":"001"}}
    {"order_id":"a001","user_name":"刘琦"}
    {"index":{"_index":"hotel_order","_id":"002"}}
    {"order_id":"a002", "user_name":"刘邦"}
    {"index":{"_index":"hotel_order", "_id":"003"}}
    {"order_id":"a003","user_name":"刘少奇"}
    
    • 对多字段进行查询并排序
    GET /hotel_order/_search
    {
      "query": {
        "match": {
          "user_name": "刘"
        }
      },
      "sort": [
        {
          "user_name.user_name_key": {
            "order": "asc"
          }
        }
      ]
    }
    

    3 文档操作

    1. 单条数据写入

    在ES中写入文档请求的类型是POST,其请求形式如下

    # 创建索引名为mydata,创建映射
    PUT /mydata
    {
      "mappings": {
        "properties": {
          "mname":{
            "type": "text"
          }
        }
      }
    }
    
    • 使用post写入单体数据
    POST /mydata/_doc/001
    {
      "mname":"张三"
    }
    
    • 不指定id,插入数据id由ES系统生成
    POST /mydata/_doc
    {
      "mname":"李四"
    }
    
    1. 批量写入
    • 语法
    POST /_bulk
    {"index":{"_index","索引名"[,"_id":id值]}}
    {单条插入数据}
    {"index":{"_index","索引名"[,"_id":id值]}}
    {单条插入数据}
    
    • 批量插入多条数据
    POST /_bulk
    {"index":{"_index":"mydata"}}
    {"mname":"王五"}
    {"index":{"_index":"mydata"}}
    {"mname":"赵六"}
    
    1. 更新单条记录
    • 语法
    POST /索引名/_update/id值
    {
      需要更新的数据
    }
    
    • 根据id值更新单体记录
    POST /mydata/_update/-7-kQIcBX-mbhp5AZ5XW
    {
      "doc": {
        "mname":"巨无霸"
      }
    }
    
    • 除了普通的update功能,ES还提供了upsert。upsert即是update和insert的合体字,表示更新/插入数据。如果目标文档存在,则执行更新逻辑;否则执行插入逻辑。
    POST /mydata/_update/-7-kQIcBX-mbhp5AZ5XW
    {
      "doc": {
        "mname":"巨无霸"
      },
      "upsert": {
        "mname":"玩大锤"
      }
    }
    

    文档-7-kQIcBX-mbhp5AZ5XW存在,则执行更新逻辑,将doc内容更新到文档中;否则执行插入逻辑,将upsert的内容写入文档中

    1. 批量更新文档

    注意,与批量写入文档不同的是,批量更新文档必须在元数据中填写需要更新的文档_id

    POST /_bulk
    {"index":{"_index":"mydata","_id":"-b-gQIcBX-mbhp5AzZW8"}}
    {"mname":"张艺谋"}
    {"index":{"_index":"mydata","_id":"8"}}
    {"mname":"张一鸣"}
    
    1. 根据条件更新文档
    POST /mydata/_update_by_query
    {
      "query": {
        "match": {
          "mname": "王"
        }
      },
      "script": {
        "source": "ctx._source['mname']='西门'",
        "lang": "painless"
      }
    }
    
    1. 根据id值删除单条记录
    DELETE /mydata/_doc/-r-kQIcBX-mbhp5AZ5XW
    
    1. 批量删除文档
    POST /_bulk
    {"delete":{"_index":"mydata","_id":"-L-gQIcBX-mbhp5AzZW8"}}
    {"delete":{"_index":"mydata","_id":"8"}}
    
    1. 根据条件删除文档
    POST /mydata/_delete_by_query
    {
      "query":{
        "match":{
          "mname":"张"
        }
      }
    }
    

    相关文章

      网友评论

          本文标题:03-ES基础操作

          本文链接:https://www.haomeiwen.com/subject/pbjhddtx.html