ElasticSearch之Mapping

写在前面

本文看下es的mapping的设置。es支持两种mapping,一种式dynamic mapping,另外一种是显式的mapping设置。分别来看下。

在正式开始之前我们需要先看下es提供的字段数据类型:
ElasticSearch之Mapping_第1张图片

1:dynamic mapping

我们在使用关系型数据库的时候必须先建表,并指定有哪些字段,什么数据类型,否则将不能保存数据,但是在es中这个建表,并指定有哪些字段,什么数据类型的过程es可以自动的帮助我们完成,就叫做dynamic mapping,具体是这样子的:

当我们向一个不存在的index插入数据的时候,es会自动的根据我们所插入的数据信息,反推出字段信息,并通过dynamic mapping的机制,自动的给我们创建mapping信息,然后再将文档进行保存,自然,这种自动的动作,肯定不可能百分百符合我们的预期,所以在工作中,还是手动创建比较靠谱些,关于如何手动创建,我们在文章的后边也会一起来看下。

如下我们向一个不存在的index中插入数据:
ElasticSearch之Mapping_第2张图片
查看自动生成的mapping信息:
ElasticSearch之Mapping_第3张图片

1.1:更改 mapping

分新增字段和已有字段两种情况:

  • 新增字段
    看图吧!
    ElasticSearch之Mapping_第4张图片

ElasticSearch之Mapping_第5张图片

  • 已有字段
    不允许修改。
    我就非得要修改,咋办,可以使用reindex API,重建索引。

1.2:测试dynamic false和stric

此时新增的字段将无法被搜索,但是可以存储。
如下操作实验:

# 1:写入文档
PUT dynamic_mapping_test/_doc/1
{
  "newField": "someValue"
}
# 2:可以搜索到
POST dynamic_mapping_test/_search
{
  "query": {
    "match": {
      "newField": "someValue"
    }
  }
}

# 3:修改dynamic为false
PUT dynamic_mapping_test/_mapping
{
  "dynamic": false
}

# 4:在添加一个新字段,将不能被搜索,因为dynamic设置为false了
PUT dynamic_mapping_test/_doc/10
{
  "anotherField": "someValue"
}

# 5:就搜索不到了,因为字段并没有创建倒排,即没有被索引
POST dynamic_mapping_test/_search
{
  "query": {
    "match": {
      "anotherField": "someValue"
    }
  }
}

# 6:查看mapping信息并没有anotherField
GET dynamic_mapping_test/_mapping

# 7:再将dynamic修改为strict
PUT dynamic_mapping_test/_mapping
{
  "dynamic": "strict"
}

# 8:就报错了,不让添加新字段
# mapping set to strict, dynamic introduction of [anotherField1] within [_doc] is not allowed
PUT dynamic_mapping_test/_doc/10
{
  "anotherField1": "someValue"
}

2:显式定义mapping信息

格式:
ElasticSearch之Mapping_第6张图片
咋写?
ElasticSearch之Mapping_第7张图片
建议第二种写法,稍微改吧改吧就行了,不易出错,效率高。简答来说就是因为es自动mapping也能生成个八九不离十,我们只需要在再对其中不正确的部分,做小改动就可以了。

3:字段的常用配置

3.1:index

通过该选项的true和false,来控制字段是否可以被搜索,如果某个字段不需要或者是不希望被搜索,则可以再mapping中将该字段设置为false。如:
在这里插入图片描述
查询没有被索引的字段将会报错(但search uri的方式不报错,只是查不到),测试一下:

# 1:创建索引users,并指定mobile不索引
PUT users
{
    "mappings": {
        "properties": {
            "firstName": {
                "type": "text"
            },
            "lastName": {
                "type": "text"
            },
            "mobile": {
                "type": "text",
                "index": false
            }
        }
    }
}
# 2:查看创建的索引users,确定mobile的index就是false,如果不是就回过头检查一下
GET users/_mapping

# 3:插入一条数据
PUT users/_create/1
{
    "firstName": "jack",
    "lastName": "james",
    "mobile": "13652525252"
}
# 4:查询mobile,会报错Cannot search on field [mobile] since it is not indexed 
POST users/_search
{
  "query": {
    "match": {
      "mobile": "13652525252"
    }
  }
}
# 5:但search uri的方式是可以查询的,不报错,只是查询不到
GET users/_search?q=mobile:13652525252

3.2:index_option

用来设置索引记录的内容,默认是docs,只记录doc_id,具体如下:
ElasticSearch之Mapping_第8张图片

3.3:null_value

如果某些场景下希望搜索出值为null的文档,则可以使用null_value来给null一个特殊的值,搜索时,搜索这个特质就可以了,如下:

# 1:先删除索引,因为前面创建过了
DELETE users
# 2:创建索引,并指定firstName的null_value
PUT users
{
    "mappings": {
        "properties": {
            "firstName": {
                "type": "text"
            },
            "lastName": {
                "type": "text"
            },
            "mobile": {
                "type": "keyword",
                "null_value": "imnull"
            }
        }
    }
}
# 3:创建新数据
POST users/_create/1
{
    "firstName": "jack",
    "lastName": "james",
    "mobile": null
}
# 4:通过mobile的null值搜索,可以搜索到,并且mobile的值是 "mobile" : null
GET users/_search?q=mobile:"imnull"

3.4:copy_to

如果是希望将多个字段汇总到一个字段中,并搜索,可以使用copy_to,如下:
ElasticSearch之Mapping_第9张图片
测试:

# 1:先删除索引,因为前面创建过了
DELETE users
# 2:创建索引,并指定firstName的null_value
PUT users
{
    "mappings": {
        "properties": {
            "firstName": {
                "type": "text",
                "copy_to": "fullName"
            },
            "lastName": {
                "type": "text",
                "copy_to": "fullName"
            }
        }
    }
}
# 3:创建新数据
POST users/_create/1
{
    "firstName": "jack",
    "lastName": "james"
}
# 4:搜索在fulleName中包含jack或者是包含james的,可以正常搜索到
GET users/_search?q=fullName:(jack james)
{
  "profile": "true"
}

3.5:多字段类型

考虑这样的场景,对于文档的某个字段,有时候我们需要对其进行模糊查询,有时候需要对其进行精确查询,此时,就可以考虑使用多字段类型,即给字段设置一个子字段,当然,在当前假设的场景下,子字段的类型需要设置为keyword,来满足精确查找的需求,如下:

# 1:先删除索引,因为前面创建过了
DELETE users
# 2:创建索引,并指定firstName的null_value
PUT users
{
    "mappings": {
        "properties": {
            "firstName": {
                "type": "text",
                "fields": {
                  "my_keyword": {
                    "type": "keyword"
                  }
                }
            },
            "lastName": {
                "type": "text"
            }
        }
    }
}

# 3:插入数据
POST users/_create/1
{
  "firstName": "AA BB CC",
  "lastName": "james"
}

# 4:使用firstName查询“AA BB”可以查询到,此时是模糊匹配
GET users/_search?q=firstName:"AA BB"
{
  "profile": "true"
}

# 5:使用firstName的子字段my_keyword查询“AA BB”查询不到,因为是精准匹配
GET users/_search?q=firstName.my_keyword:"AA BB"
{
  "profile": "true"
}

# 6:使用firstName的子字段my_keyword查询“AA BB CC"可以查询到
GET users/_search?q=firstName.my_keyword:"AA BB CC"
{
  "profile": "true"
}

注意keyword和text的关键区别就是,keyword是精确匹配,text是模糊匹配。当然text当给定的是完全匹配的值时也是可以查询到的,但本质上还是通过模糊查询的方式匹配到的,这点要注意。

当然我们也可以设置一个指定了自定义分词器的子字段,如下:
ElasticSearch之Mapping_第10张图片

具体的可以根据业务场景来灵活定义。

3.6:Exact Values 和 Full text

Exact values就是精确值,需要进行精确匹配,比如一个身份证号,下载地址等,Full text就是模糊匹配,比如一段描述性的文本,对于Exact Value需要设置type:"keyword",对于Full Text需要设置type:"text",如下图:
ElasticSearch之Mapping_第11张图片

ElasticSearch之Mapping_第12张图片

4:自定义分词器

我们在前面 看过分词器由三部分组成:

charanter Filters:无
Tokennizer:按词切分,就是按照空格切分吧
Token Filters:小写处理

本部分我们继续来看下自定义分词器的相关内容。

4.1:Character Filters有哪些

ElasticSearch之Mapping_第13张图片

4.2:Tokennizer有哪些

ElasticSearch之Mapping_第14张图片

4.3:Token Filters有哪些

ElasticSearch之Mapping_第15张图片

4.4:自定义一些分词器

4.4.1:Character Filter使用html_strip,tokennizer使用keyword

# 1:hello world character filter处理后变为hello world
# 2:hello world tokenizer处理后变为hello world
# 3:没有token filter,所以结果就是hello world
POST _analyze
{
  "tokenizer": "keyword",
  "char_filter": ["html_strip"],
  "text": "hello world"
}

4.4.2:Character Filter使用mapping,tokennizer使用standard(按词切分)

# 1:"123-456, I-test! test-990 650-550-1234" 经过character filter变为"123_456, I_test! test_990 650_550_1234"
# 2:"123_456, I_test! test_990 650_550_1234" 经过tokenizer,按照单词切分变为 ["123_456", "I_test", "test_990", "650_550_1234" ]
# 3:因为没有token filters,所以结果就是 ["123_456", "I_test", "test_990", "650_550_1234" ]
POST _analyze
{
  "tokenizer": "standard",
  "char_filter": [
    {
      "type": "mapping",
      "mappings": [ "- => _" ]
    }
  ],
  "text": "123-456, I-test! test-990 650-550-1234"
}

4.4.3:Character Filter使用正则,tokennizer使用standard(按词切分)

ElasticSearch之Mapping_第16张图片

4.4.4:tokennizer使用path_hiarrarchy,切分路径

ElasticSearch之Mapping_第17张图片

4.4.5:tokennizer使用whitespace(按照空格切分),token filter使用stop删除the,am,a等

# 结果中The还在,因为stop过滤的是小写的the,因此如果想要过滤掉大The的话,只需要修改"filter": ["stop"] 为 "filter": ["lowercase", "stop"],即The先变为the
POST _analyze
{
  "tokenizer": "whitespace",
  "filter": ["stop"],
  "text": "The rain in Spain falls mianly on the plain"
}

写在后面

参考文章列表

你可能感兴趣的:(ElasticSearch,mapping,精确匹配,keyword)