016.Elasticsearch文档管理操作

2020-06-30  本文已影响0人  CoderJed

1.1 创建测试用index

curl -X PUT "node01:9200/nba"

curl -X PUT "node01:9200/nba" -H 'Content-Type:application/json' -d'
{
    "mappings": {
        "_doc": {
            "properties": {
                "jerse_no": {
                    "type": "keyword"
                },
                "name": {
                    "type": "text"
                },
                "play_year": {
                    "type": "keyword"
                },
                "position": {
                    "type": "keyword"
                },
                "team_name": {
                    "type": "text"
                },
                "country": {
                    "type": "keyword"
                }
            }
        }
    }
}
'

1.2 自动创建索引

当向一个不存在的index中添加document时,可以自动创建索引,也可以根据传入的数据自动创建mapping,ES也会自动对这些文档进行倒排索引

# 查看ES集群配置
curl -X GET "node01:9200/_cluster/settings"

{
    "persistent":{},
    "transient":{}
}

# 设置自动创建index功能
curl -X PUT "node01:9200/_cluster/settings" -H 'Content-Type:application/json' -d'
{
    "persistent": {
        "action.auto_create_index": "false"
    }
}
'

{   "acknowledged":true,
    "persistent":{
        "action":{
            "auto_create_index":"false"
        }
    },
    "transient":{}
}

当把action.auto_create_index设置成false后,就不可以向不存在的index插入数据了

1.2 添加document

# 手动指定id
curl -X PUT "node01:9200/nba/_doc/1" -H 'Content-Type:application/json' -d'
{
    "name":"哈登",
    "team_name":"火箭",
    "position":"得分后卫",
    "play_year":"10",
    "jerse_no":"13",
    "country": "美国"
}
'
# 也可以让ES自动生成id,不指定id要使用POST请求
curl -X POST "node01:9200/nba/_doc" -H 'Content-Type:application/json' -d'
{
    "name":"库里",
    "team_name":"勇士",
    "position":"控球后卫",
    "play_year":"10",
    "jerse_no":"13",
    "country": "美国"
}
'

# 可以手动指定操作类型
# 指定操作类型时,必须手动设置id
# 当不指定操作时,假如原来已经有id=2的document,那么执行以下操作就会把原来的覆盖掉
# 而指定操作为"create",那么当id=2的document已经存在时,就会报错
curl -X POST "node01:9200/nba/_doc/2?op_type=create" -H 'Content-Type:application/json' -d'
{
    "name":"姚明",
    "team_name":"火箭",
    "position":"中锋",
    "play_year":"9",
    "jerse_no":"11",
    "country": "中国"
}
'

自动设置id与手动设置id的比较:

一般来说,从其他外部系统导入数据到es时,会采取这种方式,使用外部系统中已有数据的唯一标识,作为document的id,例如数据从MySQL导入到ES中,就可以直接使用MySQL表中自己的id

自动生成的id,长度为20个字符,URL安全,base64编码,使用GUID算法可以保证在并行生成id时也不会发生冲突,在直接往ES中写数据的时候,可以使用这种方式

1.3 查看文档

查看单个文档

curl -X GET "node01:9200/nba/_doc/1"

{
    "_index":"nba",
    "_type":"_doc",
    "_id":"1",
    "_version":1,
    "_seq_no":0,
    "_primary_term":1,
    "found":true,
    "_source": {
        "name":"哈登",
        "team_name":"火箭",
        "position":"得分后卫",
        "play_year":"10",
        "jerse_no":"13",
        "country": "美国"
    }
}

文档元数据解析:

指定返回结果的字段:

curl -X GET "node01:9200/nba/_doc/1?_source=name,country"

{
    "_index":"nba",
    "_type":"_doc",
    "_id":"1",
    "_version":1,
    "_seq_no":0,
    "_primary_term":1,
    "found":true,
    "_source": {
        "name":"哈登",
        "country": "美国"
    }
}

查看多个文档

curl -X POST "node01:9200/_mget" -H 'Content-Type:application/json' -d'
{
    "docs": [
        {
            "_index": "nba",
            "_type": "_doc",
            "_id": "1"
        },
        {
            "_index": "nba",
            "_type": "_doc",
            "_id": "2"
        }
    ]
}
'

curl -X POST "node01:9200/nba/_mget" -H 'Content-Type:application/json' -d'
{
    "docs": [
        {
            "_type": "_doc",
            "_id": "1"
        },
        {
            "_type": "_doc",
            "_id": "2"
        }
    ]
}
'

curl -X POST "node01:9200/nba/_doc/_mget" -H 'Content-Type:application/json' -d'
{
    "docs": [
        {
            "_id": "1"
        },
        {
            "_id": "2"
        }
    ]
}
'

curl -X POST "node01:9200/nba/_doc/_mget" -H 'Content-Type:application/json' -d'
{
    "ids": ["1", "2"]
}
'

说明:

mget是很重要的,查询的时候,如果一次性要查询多条数据的话,那么一定要用mget,尽可能减少网络开销次数,这样可以大幅提升查询性能

1.4 修改文档

# 方法一:直接覆盖原文档
# 但是要列出所有的field,即使这个field不修改
# 否则新的文档就不包含你没有写的那个field了
# 当然,如果就是要删除这个字段,就不用写了
curl -X PUT "node01:9200/nba/_doc/1" -H 'Content-Type:application/json' -d'
{
    "name":"大胡子",
    "team_name":"火箭",
    "position":"得分后卫",
    "play_year":"9",
    "jerse_no":"13",
    "country": "美国"
}
'

# 方法二:修改指定的字段
curl -X POST "node01:9200/nba/_doc/1/_update" -H 'Content-Type:application/json' -d'
{
    "doc": {
        "name":"登哥"
    }
}
'
# ES7.x
curl -X POST "node01:9200/nba/_update/1" -H 'Content-Type:application/json' -d'
{
    "doc": {
        "name":"登哥"
    }
}
'

# 增加一个字段
curl -X POST "node01:9200/nba/_doc/1/_update" -H 'Content-Type:application/json' -d'
{
    "script": "ctx._source.age=18"
}
'
# ES7.x
curl -X POST "node01:9200/nba/_update/1" -H 'Content-Type:application/json' -d'
{
    "script": "ctx._source.age=18"
}
'

# 删除一个字段
curl -X POST "node01:9200/nba/_doc/1/_update" -H 'Content-Type:application/json' -d'
{
    "script": "ctx._source.remove(\"age\")"
}
'
# ES7.x
curl -X POST "node01:9200/nba/_update/1" -H 'Content-Type:application/json' -d'
{
    "script": "ctx._source.remove(\"age\")"
}
'

# 根据参数值,更新字段,要求文档存在并且修改的field存在
curl -X POST "node01:9200/nba/_doc/1/_update" -H 'Content-Type:application/json' -d'
{
    "script": "ctx._source.age+=params.age",
    "params": {
        "age": 4
    }
}
'
# 根据参数值,更新字段,如果文档不存在,新创建一个文档,并且将upsert中的数据插入到该文档中
curl -X POST "node01:9200/nba/_doc/3/_update" -H 'Content-Type:application/json' -d'
{
    "script": {
        "source": "ctx._source.age+=params.age",
        "params": {
            "age": 4
        }
    },
    "upsert": {
        "age": 10
    }
}
'

说明:

修改一个文档的某个字段,在ES的底层,其实也是全量替换,将原来的文档标记为delete状态,新插入一条数据,根据客户端传入的字段加上原数据的其他字段组成了一条新的文档,只不过,这些操作都在shard内部去做了,相比于让用户执行全量替换的操作,优化了网络传输开销,减少了查询和修改的时间开销,提升了性能。

这是Elasticsearch的一个重要特性,即数据是不可变的,更新和删除都是插入一条新的数据同时把旧数据标记为"delete"状态,这样就带来了以下好处:

1.5 删除文档

curl -X DELETE "node01:9200/nba/_doc/3"

1.6 批量增删改查

语法:

POST /_bulk
{"delete": {"_index": "index_name", "_type": "type_name", "_id": 1}}
{"create": {"_index": "index_name", "_type": "type_name", "_id": 4}}
{"doc": {"field": "value"}}
{"create": {"_index": "index_name", "_type": "type_name", "_id": 5}}
{"doc": {"field1": "value1", "field2": "value2"}}
{"update": {"_index": "index_name", "_type": "type_name", "_id": 1, "some_properties": "properties_value"}}
{"doc": {"field": "value"}}

# 例如:
POST /_bulk
{"delete": {"_index": "user", "_type": "_doc", "_id": 5}}
{"create": {"_index": "user", "_type": "_doc", "_id": 6}}
{"doc": {"uid": "1006", "uname": "Nancy"}}
{"index": {"_index": "shop", "_type": "product", "_id": 5}}
{"doc": {"name": "Gaolujie Toothpaste"}}
{"update": {"_index": "user", "_type": "_doc", "_id": 1, "retry_on_conflict": 3}}
{"doc": {"name": "Nancy"}}

bulk api对json的语法有严格的要求,每个json串不能换行,只能放一行,同时一个json串和一个json串之间,必须换行,除"delete"操作外,每个操作要两个json串,语法如下:

{"action": {"metadata"}}
{"data"}

# action包括:
delete:删除一个文档,只要1个json串就可以了
create:PUT /index/type/id/_create,强制创建
index:普通的put操作,可以是创建文档,也可以是全量替换文档
update:更新操作

任意一个操作失败,不会影响其他操作,但是在返回结果里,会告诉你哪个操作失败了及其错误信息

批量操作会将所有请求加载到内存中,一次请求过多的话,性能反而会下降,一般从5000-1W条数据开始测试,以得到一个最佳性能,同时,一般来说,将一次请求的大小在5-15MB之间

为什么批量操作对请求json字符串的要求这么严格呢?

bulk中的每个操作都可能要转发到不同的node的shard去执行,如果采用比较良好的json数组格式,允许任意的换行,整个可读性非常棒,读起来很爽,es拿到那种标准格式的json串以后,要按照下述流程去进行处理:

这样就耗费更多内存,造成更多的jvm gc开销,导致性能下降,而使用这种严格的json格式之后:

这样,减少了内存开销,减少了解析成本,提高了性能

上一篇 下一篇

猜你喜欢

热点阅读