zoukankan      html  css  js  c++  java
  • 【原创】《从0开始学Elasticsearch》—document的单/批量crud

    内容目录

    1.新建文档2.查询文档3.修改文档4.删除文档

    1.新建文档

    1). 语法1,手动指定document 的id:

    PUT /index_name/type_name/id
    {
        "Json format data"
    }

    举例:插入一条商品信息

    PUT /goods/books/1
    {
      "name":"effective java",
      "purchasePrice":7800,
      "salesPrice":12000,
      "currencyUnit":"cent",
      "desc":"Joshua Bloch",
      "onlineStock":999
    }

    运行结果:

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

    可以看到,商品已经插入成功,ES自动为我们创建了index和type,若想禁止ES自动创建,我们可以修改config/elasticsearch.yml文件。

    其中,输出中的 _index 元数据表明document 所在的index,index名称必须为小写字母,可以包含下划线、中划线,但只能以小写字母开头。在ES 6.6版本中,index的概念类似于mysql中的table,而非database。

    同理,_type元数据表明document 所在的type,type是对document 的一个逻辑分类。

    _id元数据表明document 的id,可以在创建document 时手动指定,也可以由ES自动生成,若由ES自动生成,我们应该用POST方法而非PUT方法,即下文的语法2。

    _version表明当前document 的版本,_version元数据非常有效,从结果中我们可以看到,第一次创建document ,_version的值为1,其实以后我们对该document 进行修改或删除操作,_version的值都会加1,后续操作时,我们可以留意观察一下;另外,_version还被ES用于解决并发冲突的问题,当有并发请求时,ES内部实现了基于_version的乐观锁并发控制:当要修改document 数据时,带上数据的version版本号,只有version版本号相同时,ES才会更新数据,否则你需要先获取一下最新的数据,然后再带上最新的version去更新数据。

    2). 语法2,document 的id由ES自动生成:

    POST /index_name/type_name
    {
        "Json format data"
    }

    举例:

    POST /goods/books
    {
      "name":"effective c++",
      "purchasePrice":4500,
      "salesPrice":5900,
      "currencyUnit":"cent",
      "desc":"Scott Meyers",
      "onlineStock":888
    }

    运行结果:

    {
      "_index" : "goods",
      "_type" : "books",
      "_id" : "bEYCL2kB8EI9vT4zSMMW",
      "_version" : 1,
      "result" : "created",
      "_shards" : {
        "total" : 2,
        "successful" : 1,
        "failed" : 0
      },
      "_seq_no" : 0,
      "_primary_term" : 1
    }

    可以看到ES为我们自动生成了id,长度20字符,是一种GUID,不会重复。

    3). 语法3,利用 bulk API 的create 操作批量创建document :
    bulk API 可以总结为:

    { action: { metadata }}
    
    request body        }
    { action: { metadata }}
    request body        }
    ......

    批量创建document 则为:

    POST /_bulk
    {"create":{"_index":"index_name1","_type":"type_name1","_id":"id1"}}
    {"field1":"field_data1","field2":"field_data2","field3":"field_data3"...}
    {"create":{"_index":"index_name2","_type":"type_name2","_id":"id2"}}
    {"field1":"field_data1","field2":"field_data2","field3":"field_data3"...}
    ...

    若批量创建的document 在同一个index,则上述写法可以简写为

    POST /index_name/_bulk
    {"create":{"_type":"type_name1","_id":"id1"}}
    {"field1":"field_data1","field2":"field_data2","field3":"field_data3"...}
    {"create":{"_type":"type_name2","_id":"id2"}}
    {"field1":"field_data1","field2":"field_data2","field3":"field_data3"...}
    ...

    若批量创建的document 既在同一个index,又在同一个type中,则可以继续简写为

    POST /index_name/type_name/_bulk
    {"create":{"_id":"id1"}}
    {"field1":"field_data1","field2":"field_data2","field3":"field_data3"}
    {"create":{"_id":"id2"}}
    {"field1":"field_data1","field2":"field_data2","field3":"field_data3"}
    ...

    例如,批量创建ID为 8 和ID为 9 的商品,下面三种写法都可以:

    POST /_bulk
    {"create":{"_index":"goods","_type":"books","_id":"8"}}
    {"name":"more Basic","salesPrice":1900,"onlineStock":134}
    {"create":{"_index":"goods","_type":"books","_id":"9"}}
    {"name":"more Pascal","salesPrice":1200,"onlineStock":234}

    POST /goods/_bulk
    {"create":{"_type":"books","_id":"8"}}
    {"name":"more Basic","salesPrice":1900,"onlineStock":134}
    {"create":{"_type":"books","_id":"9"}}
    {"name":"more Pascal","salesPrice":1200,"onlineStock":234}

    POST /goods/books/_bulk
    {"create":{"_id":"8"}}
    {"name":"more Basic","salesPrice":1900,"onlineStock":134}
    {"create":{"_id":"9"}}
    {"name":"more Pascal","salesPrice":1200,"onlineStock":234}

    需要注意的是,利用bulk API 进行批量操作的时候,若其中一个操作失败,只会在操作结果中告诉我们,并不会影响到其他的操作,例如,现在 ES 中存在商品ID 为10的商品,不存在商品ID 为11的商品,此时运行

    POST /goods/books/_bulk
    {"create":{"_id":"10"}}
    {"name":"more Basic","salesPrice":1900,"onlineStock":134}
    {"create":{"_id":"11"}}
    {"name":"more Pascal 11","salesPrice":1200,"onlineStock":234}

    运行结果为

    {
      "took" : 13,
      "errors" : true,
      "items" : [
        {
          "create" : {
            "_index" : "goods",
            "_type" : "books",
            "_id" : "10",
            "status" : 409,
            "error" : {
              "type" : "version_conflict_engine_exception",
              "reason" : "[books][10]: version conflict, document already exists (current version [1])",
              "index_uuid" : "UE-4WzIDTHqd7RpGX2QbMQ",
              "shard" : "1",
              "index" : "goods"
            }
          }
        },
        {
          "create" : {
            "_index" : "goods",
            "_type" : "books",
            "_id" : "11",
            "_version" : 1,
            "result" : "created",
            "_shards" : {
              "total" : 2,
              "successful" : 1,
              "failed" : 0
            },
            "_seq_no" : 4,
            "_primary_term" : 3,
            "status" : 201
          }
        }
      ]
    }

    "errors" : true 表明此次 bulk 操作发生了error,相应位置的 item指出了具体的错误信息。

    4). 语法4,利用 bulk API 的index 操作批量创建document
    语法同bulk API 的create 操作,这里不再细说,直接举例子

    例如,批量创建ID为 8 和ID为 9 的商品:

    POST /goods/books/_bulk
    {"index":{"_id":"8"}}
    {"name":"more Basic","salesPrice":1900,"onlineStock":134}
    {"index":{"_id":"9"}}
    {"name":"more Pascal","salesPrice":1200,"onlineStock":234}

    2.查询文档

    1). 语法1,查询特定ID的document 信息:

    GET /index_name/type_name/id

    若只想查询商品的某个字段,可在id后拼接“?_source=field _name”,否则默认 _source 会返回所有的字段。

    例如,查询ID为1的商品的名称:

    GET /goods/books/1?_source=name

    2). 语法2,批量查询:

    GET /_mget
    {
      "docs": [
          {
            "_index""index_name1",
            "_type""type_name1",
            "_id""id1"
          },
          {
            "_index""index_name2",
            "_type""type_name2",
            "_id""id2"
          }
        ......
        ]
    }

    若index_name 相同,则可以简写为

    GET /index_name/_mget
    {
      "docs": [
          {
            "_type""type_name1",
            "_id""id1"
          },
          {
            "_type""type_name2",
            "_id""id2"
          }
        ......
        ]
    }

    若index_name 和 type_name 均相同,则可以进一步简写为

    GET /index_name/type_name/_mget
    {
      "ids": ["id1""id2"]
    }

    例如,查询ID为1 和 2的商品信息,下面三种写法都可以:

    GET /_mget
    {
      "docs": [
          {
            "_index""goods",
            "_type""books",
            "_id""1"
          },
          {
            "_index""goods",
            "_type""books",
            "_id""2"
          }
        ]
    }

    GET /goods/_mget
    {
      "docs": [
          {
            "_type""books",
            "_id""1"
          },
          {
            "_type""books",
            "_id""2"
          }
        ]
    }

    GET /goods/books/_mget
    {
      "ids": ["1""2"]
    }

    3). 语法3,利用search API进行查询,后面会有单独一篇文章进行讲解。

    3.修改文档

    1). 语法1,PUT 方法,修改时所携带的field 会将document 已有的field 全部替换掉,即document 会进行全量替换,语法同创建文档:

    PUT /index_name/type_name/id
    {
        "Json format data"
    }

    举例:
    先新增一条商品信息:

    PUT /goods/books/1
    {
      "name":"effective java",
      "purchasePrice":7800,
      "salesPrice":12000,
      "currencyUnit":"cent",
      "desc":"Joshua Bloch",
      "onlineStock":999
    }

    然后修改商品:

    PUT /goods/books/1
    {
      "name":"More Effective Java",
      "salesPrice":13000,
      "currencyUnit":"cent"
    }

    运行结果:

    {
      "_index" : "goods",
      "_type" : "books",
      "_id" : "1",
      "_version" : 2,
      "result" : "updated",
      "_shards" : {
        "total" : 2,
        "successful" : 1,
        "failed" : 0
      },
      "_seq_no" : 1,
      "_primary_term" : 1
    }

    从结果中可以看到version版本号更新为2,执行的操作是updated。此时执行查询操作,你会发现此document 仅剩下修改后的3个field 了。

    其实document 是不可变的,这种方式修改 document 时,会对 document 建立一个新的索引,然后在新的索引中赋值所有的内容,老的document 会被标记为deleted,等待后续 ES 对其进行真正的物理删除。

    既然全量替换的语法和创建文档的语法是相同的,那么如果我此刻就是想创建文档,而非全量替换文档,那我应该怎么做呢?别慌,问题不大,ES 提供了这个功能。

    PUT /index_name/type_name/id?op_type=create
    {
        "Json format data"
    }

    或者

    PUT /index_name/type_name/id/_create
    {
        "Json format data"
    }

    即可实现强制创建文档的功能。

    2). 语法2,修改时携带哪个field,仅替换文档中相同的field

    POST /index_name/type_name/id/_update
    {
        "doc": {
            "Json format data"
        }
    }

    举例:
    先新增一条商品信息:

    PUT /goods/books/2
    {
      "name":"effective python",
      "purchasePrice":5000,
      "salesPrice":6000,
      "currencyUnit":"cent",
      "desc":"Brett Slatkin",
      "onlineStock":666
    }

    然后修改商品:

    POST /goods/books/2/_update
    {
      "doc": {
        "name":"more effective python3",
        "salesPrice":8000,
        "desc":"handsome Brett Slatkin"
      }
    }

    运行结果:

    {
      "_index" : "goods",
      "_type" : "books",
      "_id" : "2",
      "_version" : 2,
      "result" : "updated",
      "_shards" : {
        "total" : 2,
        "successful" : 1,
        "failed" : 0
      },
      "_seq_no" : 1,
      "_primary_term" : 1
    }

    从结果中可以看到version版本号更新为2,执行的操作也是updated。此时执行查询操作,你会发现此document中其他field 保持不变,只有POST方法中携带的那三个field 发生了改变。这是与语法1很大的一个区别。

    其实POST 这种方式的部分替换其内部执行过程和语法1的全量替换很像,ES会创建一个新的document,使用旧document的信息,然后ES 会将POST传递过来的json 更新到新的document 中,不过仅更新key 匹配的json 串,然后ES 会将旧的document 标记为deleted,将更新后的新的document 存入ES 中,这些操作都发生在一个shard中。

    3). 语法3,利用bulk API 的index 操作,index 操作既可以批量创建文档,也可以全量替换文档,这里不再举例。

    4). 语法4,利用bulk API 的update 操作,效果同 POST 操作,仅修改携带的field 域
    例如,修改商品ID为8 和 9的商品的商品名称和在线库存

    POST /goods/books/_bulk
    {"update":{"_id":"8"}}
    {"doc":{"name":"more Basic update","salesPrice":2300}}
    {"update":{"_id":"9"}}
    {"doc":{"name":"more Pascal update","onlineStock":12}}

    4.删除文档

    1). 语法1

    DELETE /index_name/type_name/id

    当执行delete 操作的时候,ES 并不会立刻将document 进行物理删除,而是先将document 标记为deleted,待后续ES 中数据越来越多时才会对标记为deleted的document 进行物理删除。

    有时你会发现先将document 进行delete操作,然后又新建该document 时,新建的document 其实是基于已删的document 信息的,新建document 的_version是基于已删document 的 _version然后又加了1。

    举例:新建ID为5的商品:

    PUT /goods/books/5
    {
      "name""test book"
    }

    结果:

    {
      "_index" : "goods",
      "_type" : "books",
      "_id" : "5",
      "_version" : 1,
      "result" : "created",
      "_shards" : {
        "total" : 2,
        "successful" : 1,
        "failed" : 0
      },
      "_seq_no" : 1,
      "_primary_term" : 1
    }

    删除该商品:

    DELETE /goods/books/5

    结果:

    {
      "_index" : "goods",
      "_type" : "books",
      "_id" : "5",
      "_version" : 2,
      "result" : "deleted",
      "_shards" : {
        "total" : 2,
        "successful" : 1,
        "failed" : 0
      },
      "_seq_no" : 2,
      "_primary_term" : 1
    }

    可以看到delete操作的结果中,_version 为2,此时再新建该商品:

    PUT /goods/books/5
    {
      "name""test book"
    }

    结果:

    {
      "_index" : "goods",
      "_type" : "books",
      "_id" : "5",
      "_version" : 3,
      "result" : "created",
      "_shards" : {
        "total" : 2,
        "successful" : 1,
        "failed" : 0
      },
      "_seq_no" : 9,
      "_primary_term" : 1
    }

    可以看到新建document 的 _version为3,即验证了上述我们所说的情况。

    2). 语法2,利用bulk API 的delete操作

    action: { metadata }}n

    举例,删除商品ID为8和9的商品

    POST /_bulk
    {"delete":{"_index":"goods","_type":"books","_id":"8"}}
    {"delete":{"_index":"goods","_type":"books","_id":"9"}}

    POST /goods/_bulk
    {"delete":{"_type":"books","_id":"8"}}
    {"delete":{"_type":"books","_id":"9"}}

    POST /goods/books/_bulk
    {"delete":{"_id":"8"}}
    {"delete":{"_id":"9"}}

    当然bulk API的create、index、update、delete操作可以一起使用,同样任意一个操作失败是不会影响到其他操作的,只是会在返回日志中说明。

    如果这篇文章对你有帮助或启发,欢迎关注和转发,你的关注和转发是对我最大的支持。
    如果你有什么疑问想要免费vip服务,欢迎扫描下方二维码,关注即可获得1v1免费vip服务。

    ![](https://img2018.cnblogs.com/blog/1046121/201905/1046121-20190526115340560-435847651.jpg)
  • 相关阅读:
    c# 在WebBrowser中用SendMessage模拟鼠标点击
    R 脚本读取汇总 Excel 表格数据
    lsyncd —— 多机器实时同步文件神器
    gops —— Go 程序诊断分析工具
    【读书】《跟任何人都聊得来》
    Monkeyrunner自动化测试由浅入深(第一节)
    【读书】《优秀到不能被忽视》
    【管理提升】360管理沟通的学习收获总结
    【读书】《不懂说话你怎么带团队》
    软件测试行业现状 2018年度报告
  • 原文地址:https://www.cnblogs.com/mengyi/p/10925571.html
Copyright © 2011-2022 走看看