Elasticsearch 索引及创建与修改及数据增删改

笔记源自 : Elastic 中国社区官方博客



Mapping的数据类型

Mapping的数据类型:

  • text:全文搜索字符串
  • keyword:用于精确字符串匹配和聚合
  • date 及 date_nanos:格式化为日期或数字日期的字符串
  • byte, short, integer, long:整数类型
  • boolean:布尔类型
  • float,double,half_float:浮点数类型
  • 分级的类型:object 及 nested。你可以参考文章 “Elasticsearch: nested 对象

核心数据类型

  • 字符串型:text、keyword(不会分词)
  • 数值型:long、integer、short、byte、double、float、half_float等
  • 日期类型:date
  • 布尔类型:boolean
  • 二进制类型:binary
  • 范围类型:integer_range、float_range、long_range、double_range、date_range

复杂数据类型

  • 数组类型:array
  • 对象类型:object
  • 嵌套类型:nested object
  • 地理位置数据类型:geo_point、geo_shape
  • 专用类型:ip(记录ip地址)、completion(实现自动补全)、token_count(记录分词数)、murmur3(记录字符串hash值)

关于 ‘scaling_factor’ 类型 :
price 的数据类型是一个 float 类型。对于大多数的情况来说,这个应该没有问题。但是在实际的应用中,我们可以把这个 float 数据类型转换为 scaled float 数据类型。Scaled float 由 long 数据类型来支持。long 数据类型在 Lucene 里可以被更加有效地压缩,从而节省存储的空间。在使用 scaled float 数据类型时,你必须使用scaling_factor 来配置它的精度:

{
  "my_index" : {
    "mappings" : {
      "properties" : {
        "price" : {
          "type" : "float"
        }
      }
    }
  }
}

同下  :
PUT my_index1/_doc/1
{
  "mappings": {
    "properties": {
      "price": {
        "type": "scaled_float",
        "scaling_factor": 100
      }
    }
  }
}

在上面我们定义 price 类型为 scaled_float 数据类型,并定义 scaling_factor 为
100。这样我们的数据,比如 1.99 刚好可以在乘以 100 变为 199,从而成为一个整型数。

创建索引:动态 Mapping

根据类型自动创建索引 :

PUT twitter/_doc/1
{
  "user": "GB",
  "uid": 1,
  "city": "Beijing",
  "province": "Beijing",
  "country": "China"
}

es是依靠json文档的字段类型来实现自动识别字段类型的:

在这里插入图片描述

日期自动识别

日期的自动识别可以自行配置日期的格式,默认情况下是:

["strict_date_opeional_time", "yyyy/MM/dd HH:mm:ss Z||yyyy/MM/dd Z"]

strict_date_opeional_time 是ISO 标准的日期格式,完整的格式如下:

YYYY-MM-DDhh:mm:ssTZD(eg:1997-07-16y19:20:30+01:00)

dynamic_date_formats:可以自定义日期类型
date_detection:可以关闭日期自动识别机制(默认为开启)

在创建索引的时候,加入 dynamic_date_formats 指定日期格式
例 :

PUT test_index
{
  "mappings": {
    "dynamic_date_formats": ["MM/dd/yyyy"],
    "properties" : {
      "name" : {
        "type": "text"
      }
    }
  }
}

后面该索引的所有的日期便按照指定格式识别为

PUT test_index/_doc/1
{
  "create_time": "05/21/2022"
}

查看 mapping  : 
"properties" : {
  "create_time" : {
      "type" : "date",
      "format" : "MM/dd/yyyy"
   }
}

闭日期自动识别机制 :

PUT test_index
{
  "mappings": {
    "date_detection" : false,
    "properties" : {
      "name" : {
        "type": "text"
      }
    }
  }
}

再执行插入 “2022-06-06” 时,则会被识别成 “type” : “text”

数字自动识别

字符串为数字的时候,默认不会自动识别为整型,因为字符串中出现数字是完全合理的。

numeric_detection 可以开启字符串中数字的自动识别。

使用 :

PUT test_index
{
  "mappings": {
    "numeric_detection" : true, 
    "properties" : {
      "name" : {
        "type": "text"
      }
    }
  }
}

创建索引:自定义 Mapping

Dynamic

借鉴博客
借鉴知乎博客

mapping中的字段类型一旦设置,禁止直接修改,因为 lucene实现的倒排索引生成后不允许修改,应该重新建立新的索引,然后做reindex操作。

但是可以新增字段,通过 dynamic 参数来控制字段的新增,这个参数的值如下:

  • true:默认值,表示允许选自动新增字段
  • false:不允许自动新增字段,但是文档可以正常写入,但无法对字段进行查询等操作
  • strict:严格模式,文档不能写入,报错
PUT my_index
{
  "mappings": {
      "dynamic": false,
      "properties": {
        "title": {
          "type": "text"
        },
        "name": {
          "type": "keyword"
        },
        "age": {
          "type": "integer"
        }
      }
  }
}

这里在mapping设置中,”dynamic”: false,表示在写入文档时,如果写入字段不存在也不会报错。

例如 :

PUT my_index/_doc/1
{
  "title": "hello world",
  "desc": "this is book"
}

这里的desc字段就是不存在的字段。但是查询的时候‘desc’也会被查出来

在这里插入图片描述
查看当前索引Mapping : 没有desc字段

{
  "my_indexx" : {
    "mappings" : {
      "dynamic" : "false",
      "properties" : {
        "age" : {
          "type" : "integer"
        },
        "name" : {
          "type" : "keyword"
        },
        "title" : {
          "type" : "text"
        }
      }
    }
  }
}

通过desc字段过滤查询,是查不到数据的 :

GET my_index/doc/_search
{
  "query": {
    "match": {
      "desc": "book"
    }
  }
}

Copy_to

copy_to 借鉴博客

作为一个聚合的虚拟参数,正常查询结果是不会返回该字段,主要作用与查询过滤

使用 :

PUT my_index4
{
  "mappings": {
      "properties": {
        "first_name": {
          "type": "text",
          "copy_to": "full_name"
        },
        "last_name": {
          "type": "text",
          "copy_to": "full_name"
        },
        "full_name" : {
          "type": "text"
        }
      }
  }
}

查询的时候可以通过指定查询’full_name’字段的值可以去匹配"last_name"和"first_name"的值 :

GET my_index4/_search
{
  "query": {
    "match": {
      "full_name": {
        "query": "john smith",
        "operator": "and"
      }
    }
  }
}

返回内容,是没有copy_to字段的 :

"hits" : [
   {
     "_index" : "my_index4",
     "_type" : "_doc",
     "_id" : "1",
     "_score" : 0.5753642,
     "_source" : {
       "first_name" : "john",
       "last_name" : "smith"
     }
   }
 .....
 ]

如果要查看copy_to的内容,需要在创建copy_to时加入 :“store”: true

  "full_name": {
    "type": "text",
    "store": true
  }
GET my_index4/_doc/1?stored_fields=full_name

返回 :

{
  "_index" : "my_index4",
  "_type" : "_doc",
  "_id" : "1",
  "_version" : 1,
  "_seq_no" : 0,
  "_primary_term" : 1,
  "found" : true,
  "fields" : {
    "full_name" : [
      "john",
      "smith"
    ]
  }
}

没加 “store”: true 时返回 :

{
  "_index" : "my_index4",
  "_type" : "_doc",
  "_id" : "1",
  "_version" : 1,
  "_seq_no" : 0,
  "_primary_term" : 1,
  "found" : true
}

Index

index参数作用是控制当前字段是否被索引,默认为true,false表示不记录,即不可被搜索。

例 :

PUT my_index5
{
  "mappings": {
      "properties": {
        "cookie": {
          "type": "text",
          "index": false
        },
        "content": {
          "type": "text",
          "index": true
        }
      }
  }
}

这个index有两个字段,其中cookie设定为不可被搜索

content 字段可以正常过滤 :

GET my_index5/_search
{
  "query": {
    "match": {
      "content": "hello"
    }
  }

cookie 字段会报错 :

GET my_index5/_search
{
  "query": {
    "match": {
      "cookie": "mike"
    }
  }
}

返回 :

在这里插入图片描述
当在es中存储了一些不想要被检索的字段如身份证、手机等,这是对于这些字段就可以使用index设置为false,这样有一定的安全性还可以节省空间

Index_options

index_options用于控制在建立倒排索引过程中,哪些内容会被添加到倒排索引中,例如,doc数量,词频,positions,offsets等信息,优化这些设置可以一定程度上降低索引过程中的计算任务

这个字段很迷糊,希望有大佬来解释一下。参考博客

index_options参数控制向倒排索引添加哪些信息,主要用于搜索和高亮。有下面四种参数:

  • docs: 只有文档编号被索引。能够回答的问题只有此 term(词条)是否存在于此字段。

  • freqs:文档编号和 term(词条)的频率会被索引。term(词条)频率用于给搜索评分,重复出现的 term(词条)评分将高于单个出现的 term(词条)。

  • positions:文档编号、term frequencies(词条频率)和 term(词条)位置(或顺序)将被索引。Position被用于 proximity queries (邻近查询)和 phrase queries(短语查询)。

  • offsets: 文档编号、term(词条)频率,位置,起始和结尾字符偏移量(用于映射该 term (词条)到原始字符串)将被索引。Offset用于postings highlighter。

text类型的默认配置为positions,其他默认为docs。记录的内容越多,占据的空间越大。

例 :

PUT my_indexx
{
  "mappings": {
      "dynamic": false,
      "properties": {
        "title": {
          "type": "text",
          "index_options": "docs"
        }
      }
  }
}

Null_value

这个参数的作用是当字段遇到null值的时候的处理策略,默认为null,即空值,此时es会忽略该值。可以通过这个参数设置某个字段的默认值。

例 :

PUT my_indexx
{
  "mappings": {
      "dynamic": false,
      "properties": {
        "title": {
          "type": "text",
          "null_value": "default value"
        },
        "name": {
          "type": "keyword"
        },
        "age": {
          "type": "integer"
        }
      }
  }
}

Analyzer

为属性指定分词器

PUT multifield
{
  "mappings": {
    "properties": {
      "content": {
        "type": "text",
        "analyzer": "standard", 
        "fields": {
          "english": {
            "type": "text",
            "analyzer": "english"
          }
        }
      }
    }
  }
}

自定义mapping的建议

可以先将文档写入临时的index中,然后获取临时文档mapping,将临时index的mapping复制过来进行修改,修改完成再手动创建设置一个index的名称就行了。

查看Mapping映射

GET twitter/_mapping

关闭自动映射创建

PUT _cluster/settings
{
    "persistent": {
        "action.auto_create_index": "false" 
    }
}

插入数据

PUT

PUT twitter/_doc/1?refresh=true
{
  "user": "GB",
  "uid": 1,
  "city": "Beijing",
  "province": "Beijing",
  "country": "China"
}

refresh 的操作。它可以使更改可见以进行搜索的操作。通常会有一个 refresh timer 来定时完成这个操作。这个周期为1秒。这也是我们通常所说的 Elasticsearch 可以实现秒级的搜索。当然这个 timer 的周期也可以在索引的设置中进行配置。如果我们想让我们的结果马上可以对搜索可见设置 refresh=true

频繁的进行这种操作,可以使我们的 Elasticsearch 变得非常慢。另外一种方式是通过设置 refresh=wait_for。这样相当于一个同步的操作,它等待下一个 refresh 周期发生完后,才返回。

返回数据 :

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

版本(_version)信息,它显示的是8。如果插入的 _id 在 document 之前没有被创建过的话,它会显示为 1。之后如果我们更改这个 document,它的版本会每次自动增加1

通过_create创建如果文档已经存在的话,我们会收到一个错误的信息 :

PUT twitter/_create/1
{
  "user": "GB",
  "uid": 1,
  "city": "Shenzhen",
  "province": "Guangdong",
  "country": "China"
}

同等  : 
PUT twitter/_doc/1?op_type=create
{
  "user": "GB",
  "uid": 1,
  "city": "Shenzhen",
  "province": "Guangdong",
  "country": "China"
}

op_type。它可以有两种值:index 及 create

POST

我们不写 id 的话,ES 会帮我们自动生产一个 id:

POST twitter/_doc/

结果ID

"_id" : "_CJpBIEB0Dam8lRCSpg1",

建议让系统自动帮我们生成一个 id,这样可以提高导入的速度。假如我们指定一个 id,通常 ES 会先查询这个 id 是否存在,然后在觉得是更新之前的文档还是创建一个新的文档。这里是分两步走。显然它比直接创建一个文档要慢!

Update 文档修改

我们修改一个文档时,我们通常会使用 PUT 来进行操作,并且,我们需要指定一个特定的 id 来进行修改:

PUT twitter/_doc/1
{
   "user": "GB",
   "uid": 1,
   "city": "北京",
   "province": "北京",
   "country": "中国",
   "location":{
     "lat":"29.084661",
     "lon":"111.335210"
   }
}

使用 PUT 的这个方法,每次修改一个文档时,我们需要把文档的每一项都要写出来。这对于有些情况来说,并不方便,我们可以使用如下的方法来进行修改:

POST twitter/_update/1
{
  "doc": {
    "city": "成都",
    "province": "四川"
  }
}

在不知道Id的情况下,可通过通过查询的方式来进行查询,然后进行修改 :

POST twitter/_update_by_query
{
  "query": {
    "match": {
      "user": "GB"
    }
  },
  "script": {
    "source": "ctx._source.city = params.city;ctx._source.province = params.province;ctx._source.country = params.country",
    "lang": "painless",
    "params": {
      "city": "上海",
      "province": "上海",
      "country": "中国"
    }
  }
}

对于属性名为中文的操作 :

POST edd/_update_by_query
{
  "query": {
    "match": {
      "姓名": "张彬"
    }
  },
  "script": {
    "source": "ctx._source[\"签到状态\"] = params[\"签到状态\"]",
    "lang": "painless",
    "params" : {
      "签到状态":"已签到"
    }
  }
}

使用 _update 接口使用 ctx[‘_op’] 来达到删除一个文档的目的,比如:

当检测文档的 uid 是否为 1,如果为 1 的话,那么该文档将被删除,否则将不做任何事情。

POST twitter/_update/1
{
  "script": {
    "source": """
    if(ctx._source.uid == 1) {
      ctx.op = 'delete'
    } else {
      ctx.op = "none"
    }
    """
  }
}

Upset 更新及插入

仅在文档事先存在的情况下,_update中看到的部分更新才有效。 如果具有给定 ID 的文档不存在,Elasticsearch 将返回一个错误,指出该文档丢失。 让我们了解如何使用更新 API 进行 upsert 操作。 术语 “upsert” 宽松地表示更新或插入,即更新文档(如果存在),否则,插入新文档。

下面的示例使用 doc_as_upsert 合并到 ID 为3的文档中,或者如果不存在则插入一个新文档: :

POST /catalog/_update/3
{
     "doc": {
       "author": "Albert Paro",
       "title": "Elasticsearch 5.0 Cookbook",
       "description": "Elasticsearch 5.0 Cookbook Third Edition",
       "price": "54.99"
      },
     "doc_as_upsert": true
}

HEAD 检查文档或索引是否存在

检查一个文档是否存在:

HEAD twitter/_doc/1

检查一个索引是否存在:

HEAD twitter

存在返回 :

200 - OK

不存在返回 :

{"statusCode":404,"error":"Not Found","message":"404 - Not Found"}

DELETE 删除文档或索引

删除一个索引 :

DELETE twitter

如果我们想删除一个文档的话,我们可以使用如下的命令:

DELETE twitter/_doc/1

不知道ID情况下,根据查询结果删除 :

POST twitter/_delete_by_query
{
  "query": {
    "match": {
      "city": "上海"
    }
  }
}

Bulk 批处理

新增

通过 index新增

POST _bulk
{ "index" : { "_index" : "twitter", "_id": 1} }
{"user":"双榆树-张三","message":"今儿天气不错啊,出去转转去","uid":2,"age":20,"city":"北京","province":"北京","country":"中国","address":"中国北京市海淀区","location":{"lat":"39.970718","lon":"116.325747"}}
{ "index" : { "_index" : "twitter", "_id": 2 }}
{"user":"东城区-老刘","message":"出发,下一站云南!","uid":3,"age":30,"city":"北京","province":"北京","country":"中国","address":"中国北京市东城区台基厂三条3号","location":{"lat":"39.904313","lon":"116.412754"}}
	.....

通过 create 新增

POST _bulk
{ "create" : { "_index" : "twitter", "_id": 1} }
{"user":"双榆树-张三","message":"今儿天气不错啊,出去转转去","uid":2,"age":20,"city":"北京","province":"北京","country":"中国","address":"中国北京市海淀区","location":{"lat":"39.970718","lon":"116.325747"}}
{ "index" : { "_index" : "twitter", "_id": 2 }}
{"user":"东城区-老刘","message":"出发,下一站云南!","uid":3,"age":30,"city":"北京","province":"北京","country":"中国","address":"中国北京市东城区台基厂三条3号","location":{"lat":"39.904313","lon":"116.412754"}}
    ....

index 总是可以成功,它可以覆盖之前的已经创建的文档 "result" : "updated" ,_version加一。但是 create 则不行,如果已经有以那个 id 为名义的文档,就不会成功。

{
  "took" : 1,
  "errors" : true,
  "items" : [
    {
      "create" : {
        "_index" : "twitter",
        "_type" : "_doc",
        "_id" : "1",
        "status" : 409,
        "error" : {
          "type" : "version_conflict_engine_exception",
          "reason" : "[1]: version conflict, document already exists (current version [9])",
          "index_uuid" : "H_7h5iGURnicnOZme9aeSA",
          "shard" : "0",
          "index" : "twitter"
        }
      }
    }
  ]
}

_bulk不要添加除了换行以外的空格,否则会导致错误。

删除

POST _bulk
{ "delete" : { "_index" : "twitter", "_id": 1 }}
	......

更新

使用 update 来进行更新一个文档。

POST _bulk
{ "update" : { "_index" : "twitter", "_id": 2 }}
{"doc": { "city": "长沙"}}

Open/Close 索引的在线/离线模式

Elasticsearch 支持索引的在线/离线模式。 使用脱机模式时,在群集上几乎没有任何开销地维护数据。 关闭索引后,将阻止读/写操作。 当你希望索引重新联机时,只需打开它即可。 但是,关闭索引会占用大量磁盘空间。 你可以通过将 cluster.indices.close.enable 的默认值从 true 更改为 false 来禁用关闭索引功能,以避免发生意外。

关闭索引 :

POST twitter/_close

返回结果 :

{
  "acknowledged" : true,
  "shards_acknowledged" : true,
  "indices" : {
    "twitter" : {
      "closed" : true
    }
  }
}

一旦 twitter 索引被关闭了,那么我们再访问时会出现如下的错误:

{
  "error" : {
    "root_cause" : [
      {
        "type" : "index_closed_exception",
        "reason" : "closed",
        "index_uuid" : "H_7h5iGURnicnOZme9aeSA",
        "index" : "twitter"
      }
    ],
    "type" : "index_closed_exception",
    "reason" : "closed",
    "index_uuid" : "H_7h5iGURnicnOZme9aeSA",
    "index" : "twitter"
  },
  "status" : 400
}

通过 _open 接口来重新打开这个 index :

POST twitter/_open

返回结果 :

{
  "acknowledged" : true,
  "shards_acknowledged" : true
}

Freeze/Unfreeze 索引冻结

冻结索引(freeze index)在群集上几乎没有开销(除了将其元数据保留在内存中),并且是只读的。

冻结索引受到限制,以限制每个节点的内存消耗。 每个节点的并发加载的冻结索引数受 search_throttled 线程池中的线程数限制,默认情况下为1。 默认情况下,即使已明确命名冻结索引,也不会针对冻结索引执行搜索请求。 这是为了防止由于误将冻结的索引作为目标而导致的意外减速。 如果要包含冻结索引做搜索,必须使用查询参数 ignore_throttled = false 来执行搜索请求。

我们可以使用如下的命令来对 twitter 索引来冻结:

POST twitter/_freeze

这个时候对该冻结索引搜索,将不会有返回结果 :

在这里插入图片描述
加上 ignore_throttled=false 参数来进行搜索:

在这里插入图片描述

通过如下的命令来对这个已经冻结的索引来进行解冻:

POST twitter/_unfreeze

一旦我们的索引被成功解冻,那么它就可以像我们正常的索引来进行操作了,而不用添加参数 ignore_throttled=false 来进行访问。


总结

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值