之前我们了解了动态的Mapping设置,我们知道ES提供了mapping的字段类型的一个推算,会根据你第一次写入文档的字段的值去推算设置mapping的字段类型。但是我们又说这个推算是不准确的,可能和你的预想出现偏差,之前我们也验证过了。
因为不准确,所以我们在实际开发的时候一般不会完全去依赖他的推算,更多的是我们按照业务要求,显式的指定字段的类型,所以这次我们就来处理手动指定类型mapping的操作。
一、如何显式定义一个Mapping
1、简介
显式定义的语法很简单,但是我们先明确一点,我们定义的是Index索引的mapping,所以这个mapping是我们第一次添加index索引的时候指定的。
其简单语法为:
PUT indexName
{
"mappings":{
// 在这里定义你的mapping结构
}
}
2、实际操作的方法
2.1、参考官网
可以参考官网纯手写,这个没说的,多写写就熟练了。
2.2、建立临时索引,再修改
我们可以利用前面说的动态mapping,先设置进去一个,让ES帮我们推断,然后我们查出这个mapping结构,在上面做一些修改,把他推断错的改过来就行,然后删掉那个临时的。再使用修改好的,创建出你要的最终版就行了。
3、控制当前字段是否被索引
有时候我们创建一个索引,建立mapping的时候,有些字段我们不希望可以被用户检索到。这样我们可以在显示创建mapping的时候。在某些字段上指定是否可以被索引。
如果你设置成false,则该字段不可以被搜索。如果你不设置,默认就是true。
比如下面:
PUT users 创建一个users索引,显式的设置其mapping
{
"mappings": {
"properties": {
"firstName":{
"type": "text"
},
"lastName":{
"type": "text"
},
"mobile":{
"type": "text",
"index": false 指定这个字段不可以被索引,也就是无法被搜索,他的倒排索引就不会被创建
}
}
}
}
举个例子:
1、先建立一个索引并且指定其中字段为index:false
#设置 index 为 false
DELETE users
PUT users
{
"mappings" : {
"properties" : {
"firstName" : {
"type" : "text"
},
"lastName" : {
"type" : "text"
},
"mobile" : {
"type" : "text",
"index": false 把电话设置为不可索引
}
}
}
}
2、在这个索引中插入一个文档
PUT users/_doc/1
{
"firstName":"Ruan",
"lastName": "Yiming",
"mobile": "12345678"
}
3、尝试检索一下mobile这个字段
POST /users/_search
{
"query": {
"match": {
"mobile":"12345678"
}
}
}
查询报错,
"caused_by": {
"type": "illegal_argument_exception",
"reason": "Cannot search on field [mobile] since it is not indexed." 不能被索引的字段mobile
}
所以验证了我们上面的理论。
4、Index Options
这里简单说明一下,docs级别只记录doc id就是在创建倒排索引的时候,倒排记录只有docId,别的没有,类似mysql中的二级索引存的不是全记录一样。
5、null_value
有的时候我们在文档中希望存入一些null值,而且我们也希望这些null值也被索引到,这时候我们就可以指定null_value属性。
同时也要知道,只有keyword类型才支持null_value。具体语法如下。
PUT users
{
"mappings": {
"properties": {
"firstName":{
"type": "text"
},
"lastName":{
"type": "text"
},
"mobile":{
"type": "text",
"index": false
},
"sex":{
"type": "keyword",
"null_value": "NULL" 以后你插入文档的时候sex就能存为Null,而且还支持查询
}
}
}
}
支持查询,GET users/_search?q=sex:NULL这样也能搜出来对应的文档。
举个例子看下:
#设定Null_value
DELETE users
PUT users
{
"mappings" : {
"properties" : {
"firstName" : {
"type" : "text"
},
"lastName" : {
"type" : "text"
},
"mobile" : {
"type" : "keyword",
"null_value": "NULL"
}
}
}
}
PUT users/_doc/1
{
"firstName":"Ruan",
"lastName": "Yiming",
"mobile": null
}
PUT users/_doc/2
{
"firstName":"Ruan2",
"lastName": "Yiming2"
}
GET users/_search 可以搜到第一个数据,第二个搜不到,因为他搜的是真的null,你写的那个Null
{
"query": {
"match": {
"mobile":"NULL"
}
}
}
6、copy_to 设置
不常使用,用到了再说吧。
测试一下:
1、创建一个索引指定mapping
PUT users
{
"mappings": {
"properties": {
"firstName":{
"type": "text",
"copy_to": "fullName"
},
"lastName":{
"type": "text",
"copy_to": "fullName"
}
}
}
}
我们指定了firstName 和 lastName,并且copy_to到了fullName这里面去,注意这个fullName不是真的存在的。
2、插入一个文档
PUT users/_doc/1
{
"firstName":"Ruan",
"lastName": "Yiming"
}
3、我们去检索一下
注意此时我们检索的是fullName条件。
GET users/_search?q=fullName:(Ruan Yiming)
POST users/_search
{
"query": {
"match": {
"fullName":{
"query": "Ruan Yiming",
"operator": "and"
}
}
}
}
我们用的fullName查询是能查到的,但是_source里面没这个字段。
"_source" : {
"firstName" : "Ruan",
"lastName" : "Yiming"
}
我们只是把这个firstName和lastName映射到了fullName里面,这个属性是不存在的。
具体可以理解为Mysql中的虚拟列。
二、ES的数据类型
1、数组类型
ES中是不支持专门的数组类型的,但是对于任何字段,都可以包含多个相同类型的数值,起到和数组一样的效果。类似效果如下。
PUT users/_doc/1
{
"name":"test1",
"hobby":"redis"
}
PUT users/_doc/2
{
"name":"test2",
"hobby":["redis,mysql"] 存入了一个类似数组结构的数据
}
具体例子如下:
#数组类型
PUT users/_doc/1
{
"name":"onebird",
"interests":"reading"
}
PUT users/_doc/1
{
"name":"twobirds",
"interests":["reading","music"]
}
POST users/_search
{
"query": {
"match_all": {}
}
}
GET users/_mapping
三、总结
ES其实常用的还是显式的mapping,具体的一些语法在使用的时候注意随机应变。