「这是我参与11月更文挑战的第7天,活动详情查看:2021最后一次更文挑战」
新增文档
文档,即索引库中某个类型下的数据,会根据规则创建索引,将来用来搜索。可以类比做数据库中的每一行数据。
新增并随机生成id
通过POST请求,可以向一个已经存在的索引库中添加文档数据。
语法:
POST /索引库名/类型名
{
"key":"value"
}
示例:
POST /lagou/goods/
{
"title":"小米手机",
"images":"http://image.lagou.com/12479122.jpg",
"price":2699.00
}
响应:
{
"_index": "lagou",
"_type": "goods",
"_id": "tURGznQB29tVfg_iWHfl",
"_version": 1,
"result": "created",
"_shards": {
"total": 3,
"successful": 1,
"failed": 0
},
"_seq_no": 0,
"_primary_term": 2
}
可以看到结果显示为:created,应该是创建成功了。
另外,需要注意的是,在响应结果中有个_id字段,这个就是这条文档数据的唯一标示,以后的增删改查都依赖这个id作为唯一标示。
可以看到id的值为:tURGznQB29tVfg_iWHfl ,这里我们新增时没有指定id,所以是ES帮我们随机生成的id。
查看文档
根据rest风格,新增是post,查询应该是get,不过查询一般都需要条件,这里我们把刚刚生成数据的id带上。
通过kibana查看数据:
GET /lagou/goods/tURGznQB29tVfg_iWHfl
查看结果:
{
"_index": "lagou",
"_type": "goods",
"_id": "tURGznQB29tVfg_iWHfl",
"_version": 1,
"found": true,
"_source": {
"title": "小米手机",
"images": "http://image.lagou.com/12479122.jpg",
"price": 2699
}
}
- _source:源文档信息,所有的数据都在里面。
- _id:这条文档的唯一标示
- 自动生成的id,长度为20个字符,URL安全,base64编码,GUID(全局唯一标识符),分布式系统并行生成时不可能会发生冲突
- 在实际开发中不建议使用ES生成的ID,太长且为字符串类型,检索时效率低。建议:将数据表中唯一的ID,作为ES的文档ID
新增文档并自定义id
如果我们想要自己新增的时候指定id,可以这么做:
POST /索引库名/类型/id值
{
...
}
示例:
POST /lagou/goods/2
{
"title":"大米手机",
"images":"http://image.lagou.com/12479122.jpg",
"price":2899.00
}
得到的数据:
{
"_index": "lagou",
"_type": "goods",
"_id": "2",
"_score": 1,
"_source": {
"title": "大米手机",
"images": "http://image.lagou.com/12479122.jpg",
"price": 2899
}
}
修改数据
PUT:修改文档
POST:新增文档
把刚才新增的请求方式改为PUT,就是修改了。不过修改必须指定id,
- id对应文档存在,则修改
- id对应文档不存在,则新增
比如,我们把使用id为3,不存在,则应该是新增:
PUT /lagou/goods/3
{
"title":"超米手机",
"images":"http://image.lagou.com/12479122.jpg",
"price":3899.00,
"stock": 100,
"saleable":true
}
结果:
{
"_index": "lagou",
"_type": "goods",
"_id": "3",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 1,
"_primary_term": 1
}
可以看到是created,是新增。
我们再次执行刚才的请求,不过把数据改一下:
PUT /lagou/goods/3
{
"title":"超大米手机",
"images":"http://image.lagou.com/12479122.jpg",
"price":3299.00,
"stock": 100,
"saleable":true
}
查看结果:
{
"_index": "lagou",
"_type": "goods",
"_id": "3",
"_version": 2,
"result": "updated",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 2,
"_primary_term": 1
}
可以看到结果是:updated,显然是更新数据
删除数据
删除使用DELETE请求,同样,需要根据id进行删除:
语法
DELETE /索引库名/类型名/id值
示例:
智能判断
刚刚我们在新增数据时,添加的字段都是提前在类型中定义过的,如果我们添加的字段并没有提前定义过,能够成功吗?
事实上Elasticsearch非常智能,你不需要给索引库设置任何mapping映射,它也可以根据你输入的数据来判断类型,动态添加数据映射。
测试一下:
POST /lagou/goods/3
{
"title":"超大米手机",
"images":"http://image.lagou.com/12479122.jpg",
"price":3299.00,
"stock": 200,
"saleable":true,
"subTitle":"大米"
}
我们额外添加了stock库存,saleable是否上架,subtitle副标题、3个字段。
来看结果:
{
"_index": "lagou",
"_type": "goods",
"_id": "3",
"_version": 3,
"result": "updated",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 3,
"_primary_term": 1
}
成功了!在看下索引库的映射关系:
stock、saleable、subtitle都被成功映射了。
subtitle是String类型数据,ES无法智能判断,它就会存入两个字段。例如:
- subtitle:text类型
- subtitle.keyword:keyword类型
这种智能映射,底层原理是动态模板映射,如果我们想修改这种智能映射的规则,其实只要修改动态模板即可!
动态映射模板
动态模板的语法:
- 模板名称,随便起
- 匹配条件,凡是符合条件的未定义字段,都会按照这个规则来映射
- 映射规则,匹配成功后的映射规则
举例,我们可以把所有未映射的string类型数据自动映射为keyword类型:
PUT lagou3
{
"mappings": {
"goods": {
"properties": {
"title": {
"type": "text",
"analyzer": "ik_max_word"
}
},
"dynamic_templates": [
{
"strings": {
"match_mapping_type": "string",
"mapping": {
"type": "keyword",
"index":false,
"store":true
}
}
}
]
}
}
}
在这个案例中,我们把做了两个映射配置:
- title字段:统一映射为text类型,并制定分词器
- 其它字段:只要是string类型,统一都处理为keyword类型。
这样,未知的string类型数据就不会被映射为text和keyword并存,而是统一以keyword来处理!
我们试试看新增一个数据:
POST /lagou3/goods/1
{
"title":"超大米手机",
"images":"http://image.lagou.com/12479122.jpg",
"price":3299.00
}
我们只对title做了配置,现在来看看images和price会被映射为什么类型呢:
GET /lagou3/_mapping
结果:
{
"lagou3": {
"mappings": {
"goods": {
"dynamic_templates": [
{
"strings": {
"match_mapping_type": "string",
"mapping": {
"type": "keyword"
}
}
}
],
"properties": {
"images": {
"type": "keyword"
},
"price": {
"type": "float"
},
"title": {
"type": "text",
"analyzer": "ik_max_word"
}
}
}
}
}
}
可以看到images被映射成了keyword,而非之前的text和keyword并存,说明我们的动态模板生效了!