草庐IT

1.elasticsearch文档存储(保存|修改|删除)

PacosonSWJTU 2023-09-06 原文

【README】

0.本文部分内容(数据)总结自 es 开发文档, Document APIs | Elasticsearch Guide [7.2] | Elastic

1.本文的es版本是7.2.1;

2.elasticsearch 是一个数据存储,检索和分析引擎;本文介绍的是 es数据存储开发方式;

  • es是以文档为单位存储数据的,数据被序列化为json文档进行存储;

3.文档存储包括文档保存,修改,删除;(文档查询的开发方式比较复杂,单独新开一篇阐述)

  • 保存文档:使用 put 或 post请求;
  • 修改文档:使用put和post请求;
    1. put请求更新文档是全量替换;
    2. post请求路径不带 _update 更新文档是 全量替换
    3. post请求路径带 _update 更新文档是 部分更新;且 带了 _update 时,会比较新老数据是否相同,若相同则不执行更新,返回noop;
  • 删除文档:用delete请求(包括删除文档,删除索引);

【1】保存文档

保存文档可以用put请求或post请求;

  • Put 与 post请求保存文档的区别:put必须带文档id,post可以带 或者不带id;

【1.1】put请求保存文档

1) 在customer索引下的 external类型下保存2号文档,文档id设置为2

Put localhost:9200/customer/external/2

{
  "name":"zhangsan2"
}

{
    "_index": "customer",
    "_type": "external",
    "_id": "2",
    "_version": 1,
    "result": "created", // 这里表示创建
    "_shards": {
        "total": 2,
        "successful": 1,
        "failed": 0
    },
    "_seq_no": 2,
    "_primary_term": 1
} 

2)再执行一次,result就是更新 updated 的了;

{
    "_index": "customer",
    "_type": "external",
    "_id": "2",
    "_version": 2,
    "result": "updated", // 第2次执行就是更新 
    "_shards": {
        "total": 2,
        "successful": 1,
        "failed": 0
    },
    "_seq_no": 3,
    "_primary_term": 1
}

【1.2】post请求保存文档

1) 在customer索引下的 external类型下保存文档(不带文档id);

Post localhost:9200/customer/external 

{
  "name":"zhangsan_post_1"
}

{
    "_index": "customer",
    "_type": "external",
    "_id": "Qb1Gq4MBJc7j47GNcnTa", // 自动生成id,请求路径不需要设置id 
    "_version": 1,
    "result": "created",  // 新增数据
    "_shards": {
        "total": 2,
        "successful": 1,
        "failed": 0
    },
    "_seq_no": 4,
    "_primary_term": 1
}

【Post请求小结】

  • 不带id就是永远新增,带了id的规则是无则新增,有则更新

2)post请求保存文档,带文档id

Post  localhost:9200/customer/external/Qr1Jq4MBJc7j47GNp3RF 
{
  "name":"zhangsan_post_3"
}

{
    "_index": "customer",
    "_type": "external",
    "_id": "Qr1Jq4MBJc7j47GNp3RF",
    "_version": 5,  // 版本号递增 
    "result": "updated",  // 更新 
    "_shards": {
        "total": 2,
        "successful": 1,
        "failed": 0
    },
    "_seq_no": 9,
    "_primary_term": 1
}

【2】es文档简单查询

为了方便验证es文档保存,修改,删除的效果,本文介绍了一个简单查询。

【2.1】get请求带文档id查询文档

Get localhost:9200/customer/external/1
{}

{
    "_index": "customer", // 在哪个索引 
    "_type": "external", // 在哪个类型 
    "_id": "1",  // 记录id 
    "_version": 2,  // 表明数据被更新过,因为新建数据的版本号是1 
    "_seq_no": 1,  // 并发控制字段,每次更新就会+1;用来做乐观锁;
    "_primary_term": 1,  // 同上,主分片重新分配,如重启,就会变化 
    "found": true,  // 
    "_source": {  // 真正的内容 
        "name": "zhangsan"
    }
}

【2.2】seq_no 和 primary_term 做并发控制(乐观锁)

步骤1)查询id等于1的文档

{
    "_index": "customer",
    "_type": "external",
    "_id": "1",
    "_version": 4,
    "_seq_no": 11,
    "_primary_term": 1,
    "found": true,
    "_source": {
        "name": "zhangsan2_update_seq_11"
    }
}

步骤2)把 seq_no 和 primary_term 作为更新条件

客户端1:(修改成功

Post localhost:9200/customer/external/1?if_seq_no=11&if_primary_term=1
{
  "name":"zhangsan_post_update_c1"
}

{
    "_index": "customer",
    "_type": "external",
    "_id": "1",
    "_version": 5,
    "result": "updated",
    "_shards": {
        "total": 2,
        "successful": 1,
        "failed": 0
    },
    "_seq_no": 12,
    "_primary_term": 1
}

客户端2(修改失败),因为 seq_no 因客户端1修改文档的事件而递增了,即不等于11

Post  localhost:9200/customer/external/1?if_seq_no=11&if_primary_term=1 
{
  "name":"zhangsan_post_update_c2"
}

{
    "error": {
        "root_cause": [
            {
                "type": "version_conflict_engine_exception",
                "reason": "[1]: version conflict, required seqNo [11], primary term [1]. current document has seqNo [12] and primary term [1]",
                "index_uuid": "IIq46lyCQMisw9_iPDheiw",
                "shard": "0",
                "index": "customer"
            }
        ],
        ......
    },
    "status": 409
}

【3】修改文档

1)post 或 put请求都可以修改文档;

  • post请求修改文档又分为 请求路径带 _update 和 不带_update;(post不带_update更新文档是全量替换,带_update 是部分更新)
  • put请求修改文档 时的请求路径不能带 _update ;(put更新文档是全量替换)

【3.1】post请求路径带_update更新文档

1)更新文档id为1的文档

Post localhost:9200/customer/external/1/_update
{
    "doc":{ // 注意 post请求路径带update的更新的请求体不同
        "name":"post_update_202210061135"
    }
}

{
    "_index": "customer",
    "_type": "external",
    "_id": "1",
    "_version": 6,
    "result": "updated",
    "_shards": {
        "total": 2,
        "successful": 1,
        "failed": 0
    },
    "_seq_no": 13,
    "_primary_term": 1
}

2)再发送一次相同请求,且报文体也相同,则得到 noop ;

Post localhost:9200/customer/external/1/_update
{
    "doc":{
        "name":"post_update_202210061135"
    }
}

{
    "_index": "customer",
    "_type": "external",
    "_id": "1",
    "_version": 6,
    "result": "noop", // 没有做任何操作 
    "_shards": {
        "total": 0,
        "successful": 0,
        "failed": 0
    }
}

【3.2】post请求路径不带_update更新文档

1)更新id等于1的文档

Post localhost:9200/customer/external/1
{
  "name":"zhangsan_post_update_noupdate"
}

{
    "_index": "customer",
    "_type": "external",
    "_id": "1",
    "_version": 7,
    "result": "updated",
    "_shards": {
        "total": 2,
        "successful": 1,
        "failed": 0
    },
    "_seq_no": 14,
    "_primary_term": 1
}

2)再发一次相同请求,相同报文体,如下:

{
    "_index": "customer",
    "_type": "external",
    "_id": "1",
    "_version": 8,
    "result": "updated",
    "_shards": {
        "total": 2,
        "successful": 1,
        "failed": 0
    },
    "_seq_no": 15,
    "_primary_term": 1
}

【小结】

  • Post请求路径带update,会检查新老数据是否相同,若相同,则无需更新;即version, seq_no 都不会增加;
  • Post请求路径不带update,则不会检查新老数据是否相同,无论是否相同,都会更新;即 version 和 seq_no 都会增加;

【3.3】put请求路径带_update更新文档(API不存在

put请求更新文档时,其请求路径不能带 _update ;

【3.4】put请求路径不带_update更新文档 (全量替换)

0)初始数据:id为2的文档;

post localhost:9200/customer/external/2
{}
{
    "_index": "customer",
    "_type": "external",
    "_id": "2",
    "_version": 6,
    "_seq_no": 8,
    "_primary_term": 2,
    "found": true,
    "_source": {
        "name": "post_zhangsan_02",
        "addr": "post_addr_02"
    }
}

1)更新id为2的文档

Put localhost:9200/customer/external/2
{
    "doc":{
        "name":"put_update_202210071519"        
    }
}
// 更新后的结果 
{
    "_index": "customer",
    "_type": "external",
    "_id": "2",
    "_version": 7,
    "_seq_no": 9,
    "_primary_term": 2,
    "found": true,
    "_source": {
        "doc": {
            "name": "put_update_202210071519"
        }
    }
}

【小结】

  • put请求路径不带_update可以更新成功; 不会检查新老数据是否相同,都会更新
  • put请求更新文档是全量覆盖(虽然put请求仅更新了name字段,但结果是addr字段被删除了);

【3.5】post请求为索引新增字段

1)为id为1的文档新增 addr 字段;

Post localhost:9200/customer/external/1 
{
    "doc":{
        "name":"post_noupdate_202210061151"
        , "addr":"成都高新区01_post_新增属性"
    }
}

{
    "_index": "customer",
    "_type": "external",
    "_id": "1",
    "_version": 11,
    "result": "updated",
    "_shards": {
        "total": 2,
        "successful": 1,
        "failed": 0
    },
    "_seq_no": 18,
    "_primary_term": 1
}

【3.6】put请求为索引新增字段

1)为id为1的文档新增 addr 字段;

Put localhost:9200/customer/external/1  
{
    "doc":{
        "name":"post_noupdate_202210061154"
        , "addr":"成都高新区02_put_新增属性"
    }
}

{
    "_index": "customer",
    "_type": "external",
    "_id": "1",
    "_version": 12,
    "result": "updated",
    "_shards": {
        "total": 2,
        "successful": 1,
        "failed": 0
    },
    "_seq_no": 19,
    "_primary_term": 1
}

【3.7】post请求更新文档时带_update与不带_update的区别

1)post请求路径带_update,仅部分更新(我想大部分场景应该选择带 _update)

  • 如文档有字段1,字段2;
  • 通过post带update的更新,可以仅更新字段1 或 字段2; 

2)post请求路径不带update,是全量覆盖

  • 如文档有字段1,字段2;
  • 通过post不带update的更新,是全量覆盖;

3)例子(post请求带与不带_update 更新文档的区别):

3.0)初始数据

get localhost:9200/customer/external/2 
{}
{
    "_index": "customer",
    "_type": "external",
    "_id": "2",
    "_version": 6,
    "_seq_no": 24,
    "_primary_term": 1,
    "found": true,
    "_source": {
        "name": "zhangsan2_insert",
        "addr": "post_带update_成都04"
    }
}

3.1)Post请求路径带update的部分更新

Post localhost:9200/customer/external/2/_update 
{
    "doc":{
        "addr":"post_带update_成都05"
    }
}

// 更新后的结果(部分更新): 
{
    "_index": "customer",
    "_type": "external",
    "_id": "2",
    "_version": 7,
    "_seq_no": 25,
    "_primary_term": 1,
    "found": true,
    "_source": {
        "name": "zhangsan2_insert",
        "addr": "post_带update_成都05"
    }
}

3.2)post请求路径不带_update 的全量替换

Post localhost:9200/customer/external/2
{    
    "addr":"post_不带update_成都06"    
}

// 更新后的结果(全量替换):
{
    "_index": "customer",
    "_type": "external",
    "_id": "2",
    "_version": 8,
    "_seq_no": 26,
    "_primary_term": 1,
    "found": true,
    "_source": {
        "addr": "post_不带update_成都06" // (显然,这里是全量替换)
    }
}

【4】删除数据(删除文档和索引)

【4.1】删除文档

1)删除文档id为2的文档

Delete localhost:9200/customer/external/2

{
    "_index": "customer",
    "_type": "external",
    "_id": "2",
    "_version": 9,
    "result": "deleted", // 删除成功 
    "_shards": {
        "total": 2,
        "successful": 1,
        "failed": 0
    },
    "_seq_no": 27,
    "_primary_term": 1
}

2)删除完成后,再次查询id为2的文档,如下:

Get localhost:9200/customer/external/2 
{}

{
    "_index": "customer",
    "_type": "external",
    "_id": "2",
    "found": false  // 显然没有找到 
}

【4.2】删除索引

注意: es中没有提供删除类型的api  ;

1)删除customer索引;

Delete localhost:9200/customer


{
    "acknowledged": true
}

2)删除索引文档后,,再次查询(报索引不存在);

Get localhost:9200/customer/external/2
{}
{
    "error": {
        "root_cause": [
            {
                "type": "index_not_found_exception",
                "reason": "no such index [customer]",
                "resource.type": "index_expression",
                "resource.id": "customer",
                "index_uuid": "_na_",
                "index": "customer"
            }
        ],
       ...... 
    },
    "status": 404
}

有关1.elasticsearch文档存储(保存|修改|删除)的更多相关文章

  1. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  2. ruby-on-rails - 如何从 format.xml 中删除 <hash></hash> - 2

    我有一个对象has_many应呈现为xml的子对象。这不是问题。我的问题是我创建了一个Hash包含此数据,就像解析器需要它一样。但是rails自动将整个文件包含在.........我需要摆脱type="array"和我该如何处理?我没有在文档中找到任何内容。 最佳答案 我遇到了同样的问题;这是我的XML:我在用这个:entries.to_xml将散列数据转换为XML,但这会将条目的数据包装到中所以我修改了:entries.to_xml(root:"Contacts")但这仍然将转换后的XML包装在“联系人”中,将我的XML代码修改为

  3. ruby - 我可以使用 Ruby 从 CSV 中删除列吗? - 2

    查看Ruby的CSV库的文档,我非常确定这是可能且简单的。我只需要使用Ruby删除CSV文件的前三列,但我没有成功运行它。 最佳答案 csv_table=CSV.read(file_path_in,:headers=>true)csv_table.delete("header_name")csv_table.to_csv#=>ThenewCSVinstringformat检查CSV::Table文档:http://ruby-doc.org/stdlib-1.9.2/libdoc/csv/rdoc/CSV/Table.html

  4. ruby - 我可以使用 aws-sdk-ruby 在 AWS S3 上使用事务性文件删除/上传吗? - 2

    我发现ActiveRecord::Base.transaction在复杂方法中非常有效。我想知道是否可以在如下事务中从AWSS3上传/删除文件:S3Object.transactiondo#writeintofiles#raiseanexceptionend引发异常后,每个操作都应在S3上回滚。S3Object这可能吗?? 最佳答案 虽然S3API具有批量删除功能,但它不支持事务,因为每个删除操作都可以独立于其他操作成功/失败。该API不提供任何批量上传功能(通过PUT或POST),因此每个上传操作都是通过一个独立的API调用完成的

  5. ruby-on-rails - Ruby 检查日期时间是否为 iso8601 并保存 - 2

    我需要检查DateTime是否采用有效的ISO8601格式。喜欢:#iso8601?我检查了ruby​​是否有特定方法,但没有找到。目前我正在使用date.iso8601==date来检查这个。有什么好的方法吗?编辑解释我的环境,并改变问题的范围。因此,我的项目将使用jsapiFullCalendar,这就是我需要iso8601字符串格式的原因。我想知道更好或正确的方法是什么,以正确的格式将日期保存在数据库中,或者让ActiveRecord完成它们的工作并在我需要时间信息时对其进行操作。 最佳答案 我不太明白你的问题。我假设您想检查

  6. ruby - 如何安全地删除文件? - 2

    在Ruby中是否有Gem或安全删除文件的方法?我想避免系统上可能不存在的外部程序。“安全删除”指的是覆盖文件内容。 最佳答案 如果您使用的是*nix,一个很好的方法是使用exec/open3/open4调用shred:`shred-fxuz#{filename}`http://www.gnu.org/s/coreutils/manual/html_node/shred-invocation.html检查这个类似的帖子:Writingafileshredderinpythonorruby?

  7. ruby - Rack:如何将 URL 存储为变量? - 2

    我正在编写一个简单的静态Rack应用程序。查看下面的config.ru代码:useRack::Static,:urls=>["/elements","/img","/pages","/users","/css","/js"],:root=>"archive"map'/'dorunProc.new{|env|[200,{'Content-Type'=>'text/html','Cache-Control'=>'public,max-age=6400'},File.open('archive/splash.html',File::RDONLY)]}endmap'/pages/search.

  8. ruby-on-rails - 标准化文件名的字符串,删除重音和特殊字符 - 2

    我正在尝试找到一种方法来规范化字符串以将其作为文件名传递。到目前为止我有这个:my_string.mb_chars.normalize(:kd).gsub(/[^\x00-\x7F]/n,'').downcase.gsub(/[^a-z]/,'_')但第一个问题:-字符。我猜这个方法还有更多问题。我不控制名称,名称字符串可以有重音符、空格和特殊字符。我想删除所有这些,用相应的字母('é'=>'e')替换重音符号,并将其余的替换为'_'字符。名字是这样的:“Prélèvements-常规”“健康证”...我希望它们像一个没有空格/特殊字符的文件名:“prelevements_routin

  9. Matlab imread()读到了什么 (浅显 当复习文档了) - 2

    matlab打开matlab,用最简单的imread方法读取一个图像clcclearimg_h=imread('hua.jpg');返回一个数组(矩阵),往往是a*b*cunit8类型解释一下这个三维数组的意思,行数、数和层数,unit8:指数据类型,无符号八位整形,可理解为0~2^8的数三个层数分别代表RGB三个通道图像rgb最常用的是24-位实现方法,即RGB每个通道有256色阶(2^8)。基于这样的24-位RGB模型的色彩空间可以表现256×256×256≈1670万色当imshow传入了一个二维数组,它将以灰度方式绘制;可以把图像拆分为rgb三层,可以以灰度的方式观察它figure(1

  10. 安卓apk修改(Android反编译apk) - 2

    最近因为项目需要,需要将Android手机系统自带的某个系统软件反编译并更改里面某个资源,并重新打包,签名生成新的自定义的apk,下面我来介绍一下我的实现过程。APK修改,分为以下几步:反编译解包,修改,重打包,修改签名等步骤。安卓apk修改准备工作1.系统配置好JavaJDK环境变量2.需要root权限的手机(针对系统自带apk,其他软件免root)3.Auto-Sign签名工具4.apktool工具安卓apk修改开始反编译本文拿Android系统里面的Settings.apk做demo,具体如何将apk获取出来在此就不过多介绍了,直接进入主题:按键win+R输入cmd,打开命令窗口,并将路

随机推荐