Elasticsearch Mapping操作

在Elasticsearch中,Mapping是一个非常重要的概念,他定义了es搜索引擎如何处理文档。搜索引擎重要做2个操作:

  • indexing 主要是获取一个文档,然后存储/索引/处理
  • searching 主要是从index中查询文档

indexing和searching是严格连接和相互影响的2个操作。 索引步骤中的错误导致搜索结果不是想要的或搜索结果的丢失。Elasticsearch在索引/类型级别上具有显式映射。 如果在索引文档时,没有提供映射,那么es就会从组成文档的数据字段中猜测结构,创建默认映射; 那么这个新映射将自动传播到所有集群节点。默认类型映射具有合理的默认值,但是当您想要更改其行为或要自定义索引(存储,忽略,完成等)的其他方面时,需要提供一个新的映射定义。

使用映射自动创建

在这一小节的例子中,我们会创建一个索引,然后索引一个文档,然后获取这个文档的映射,这个映射是由es自动创建的

curl -u elastic:changeme -XPUT http://127.0.0.1:9200/test
curl -u elastic:changeme -XPUT http://127.0.0.1:9200/test/mytype/1 -d '{"name":"Paul", "age":35}'
curl -u elastic:changeme -XGET http://127.0.0.1:9200/test/mytype/_mapping? pretty=true

获取的映射为:

{
    "test":{
        "mappings":{
            "mytype":{
                "properties":{
                    "age":{
                        "type":"long"
                    },
                    "name":{
                        "type":"text",
                        "fields":{
                            "keyword":{
                                "type":"keyword",
                                "ignore_above":256
                            }
                        }
                    }
                }
            }
        }
    }
}

在文档的索引阶段,es会检查指定的类型是否存在,在这个例子中是mytype,如果不存在这个类型的话,es会自动创建这个类型。同时es也会读取这个类型映射的所有的默认属性然后开始处理:

  • 如果字段已经存在于映射中,并且字段的值有效(它与正确的类型匹配),则Elasticsearch不需要更改当前的映射。
  • 如果字段已经存在于映射中,但字段的值为不同类型,则会尝试升级字段类型(即,从整数到长整型)。 如果类型不兼容,它会引发异常,并且索引文档失败。
  • 如果该字段不存在,它会尝试自动检测字段的类型。 它使用新的字段映射来更新映射。

基本类型映射对应关系

在之前版本的es中,string的标准映射为string,但是在5.x版本中,string的标准映射为keyword。其他的类型对应关系,可以参见下面的图

除过上面的一些类型之前,在创建映射的时候,也有一些比较常用的选项,下面简单的列举了一些比较常用的选项:

  • store 默认为false,这标志着要存储在单独的索引片段中的字段以便快速检索。 存储一个字段会占用磁盘空间,但如果需要从文档(即脚本和聚合)中提取它,则会减少计算。 此选项的可能值为false和true。标记有store的字段比聚合中的其他字段快。
  • index 这个选项用来标记某个字段是否需要被索引,可选的值为true和false。默认为true。如果设置为false的话,那么这个字段就不能够被搜索
  • null_value 这个选项用来当字段wei为null的时候给默认值的
  • boost 这个选项用来修改字段的权重,默认权重为1.0。boost仅仅工作在term级别,所以他主要和term、terms以及match查询一起使用。
  • search_analyzer 这个选项定义了在搜索阶段使用的分析器,如果没有定义的话,那么parent对象的搜索分析器就会被使用。默认为null
  • analyzer 这个选项设置了默认使用的分析器,默认为null
  • include_in_all 这个选项表示当前的字段是否被索引到_all_字段中,默认为true
  • copy_to 这允许您将字段的内容复制到另一个字段,以实现类似于_all字段的功能
  • ignore_above 这允许您跳过大于其值的索引字符串。 对于精确过滤,聚合和排序的处理领域很有用。 它也可以防止单个术语令牌太大,并防止由于Lucene term字节长度限制为32766(缺省值为2147483647)而导致的错误。

映射中数组的处理

数组或多值字段在数据模型(例如多个电话号码,地址,名称,别名等)中非常常见,但在传统的SQL解决方案中不是本地支持的。
在SQL中,多值字段需要创建必须连接的关联表,以收集所有值,导致记录基数很大时的性能不佳。 在JSON中原生的支持多值域。
假设有下面的一个映射:

{
    "document":{
        "properties":{
            "name":{
                "type":"keyword"
            },
            "tag":{
                "type":"keyword",
                "store":"yes"
            }
        }
    }
}

这个映射可以对下面2个文档同样试用,说明在es中,不太明确区分多值字段和单值字段。

{"name": "document1", "tag": "awesome"}
{"name": "document2", "tag": ["cool", "awesome", "amazing"] }

Mapping an object

es支持内嵌对象,比如下面的这种的这种映射定义,就是内嵌的形式:

{
    "order":{
        "properties":{
            "id":{
                "type":"keyword"
            },
            "date":{
                "type":"date"
            },
            "customer_id":{
                "type":"keyword",
                "store":"yes"
            },
            "sent":{
                "type":"boolean"
            },
            "item":{
                "type":"object",
                "properties":{
                    "name":{
                        "type":"text"
                    },
                    "quantity":{
                        "type":"integer"
                    },
                    "vat":{
                        "type":"double"
                    }
                }
            }
        }
    }
}

有几个比较重要的属性:
properties 这是一个字段或者对象的集合
enabled 它用来标记一个object是否需要被处理,如果设置为false,那么对象包含的数据就不会被索引,因此也就不能搜索。默认为true
dynamic 这允许Elasticsearch使用对插入数据的值的反射来向对象添加新的字段名称。如果它设置为false,当您尝试索引一个包含新字段类型的对象时,它将被静默地拒绝。如果将其设置为strict,则当对象中存在新的字段类型时,将抛出错误,跳过索引进程。控制动态参数允许对文档结构的更改安全(默认为true
include_in_all 将对象值添加到特殊_all字段(用于聚合所有文档字段的文本)(默认为true)

Adding a field with multiple mapping

通常情况下,一个字段会有不同的处理方式,比如对于字符串来说,为了搜索我们需要对它进行tokenize,为了排序,我们又需要一个not-tokenized字符串。这一小节就
介绍通过fields在一个字段上同时支持搜索和排序这两种要求
比如对于下面的结构:

"name": {
    "type": "keyword",
    "fields": {
        "name": {
            "type": "keyword"
        },
        "tk": {
            "type": "text"
        },
        "code": {
            "type": "text",
            "analyzer": "code_analyzer"
        }
    }
}

在Elasticsearch处理fields属性的索引期间,它会为映射中定义的每个子字段重新处理相同的字段。要访问多字段的子字段,我们在基础字段上加上一个新的路径加上子字段名称。 比如对于上面的例子:

  • name 指向默认的子字段,也就是keyword类型的那个
  • name.tk 指向的是standard analyzed (tokenized) field
  • name.code 指向使用code_analyzer分析器的那个字段

用更实际一点的例子,比如当索引字符串:Good Item to buy – ABC1234的时候,上面的3个子字段的值会为:

  • name = Good Item to buy – ABC1234 可以用来做排序
  • name.tk = [“good”, “item”, “to”, “buy”, “abc1234”] 可以用来做搜索
  • name.code = [“ABC1234”] 也可以用来做搜索

Mapping an IP field

为了改善有IP地址情况下的搜索, Elasticsearch提供了ip类型,可用于以优化的方式存储IP地址。为了存储ip,可以参考下面的例子:

"customer_ip": { "type": "ip", "store": "yes" }

这个ip必须是标准形式:"customer_ip":"19.18.200.201"

Mapping an attachment field

Elasticsearch允许通过插件扩展其核心类型来覆盖新的需求。 最常用的自定义字段类型是附件。可以用来索引和搜索常见文档文件的内容,即Microsoft Office格式,PDF,ePub等等。
需要安装一个插件:

bin/elasticsearch-plugin install ingest-attachment

为了将一个字段映射为附件,需要把这个字段的type设置为attachment。在es内部,这个字段将会被处理为fields,保存二进制数据(base64编码)和其他的一些有用的信息,比如作者,内容,标题等等的。
比如我们想给邮件存储加一个附件:

{
    "email": {
        "properties": {
            "sender": {
                "type": "keyword"
            },
            "date": {
                "type": "date"
            },
            "document": {
                "type": "attachment",
                "fields": {
                    "file": {
                        "store": "yes",
                        "index": "analyzed"
                    },
                    "date": {
                        "store": "yes"
                    },
                    "author": {
                        "store": "yes"
                    },
                    "keywords": {
                        "store": "yes"
                    },
                    "content_type": {
                        "store": "yes"
                    },
                    "title": {
                        "store": "yes"
                    }
                }
            }
        }
    }
}

附件插件内部使用Apache Tika,这是一个专门从文档中提取文本的库。 支持的文档类型列表可以在Apache Tika网站http://tika.apache.org/1.9/formats.html中找到,但它涵盖了所有常见的文件类型。附件类型字段接收由Tika元数据和文本提取器处理的base64二进制流。 该字段可以看作是在其子字段中存储不同内容的多字段.

Adding metadata to a mapping

es容许我们在mapping中使用_meta存储一些json格式的元信息
比如:

{
    "order": {
        "_meta": {
            "attr1": [
                "value1",
                "value2"
            ],
            "attr2": {
                "attr3": "value3"
            }
        }
    }
}

当Elasticsearch处理新映射并发现_meta字段时,就会将其存储在全局映射状态中,然后将信息传播到所有集群节点。
_meta仅用于存储目的; 它不会被索引也不会被搜索。它可以用于包括但不限于下面的场景:

  • 存储类型元数据
  • 存储对象关系映射(ORM)相关信息
  • 存储类型许可信息

Specifying a different analyzer

es提供了很多的分析器,我们可以使用它们来提示搜索质量。每个核心类型字段允许您指定自定义分析器进行索引和搜索。
例如,如果我们希望对name字段使用standard analyzer 进行索引,并使用simple analyzer 进行搜索,则映射将如下所示:

{
    "name": {
        "type": "string",
        "index_analyzer": "standard",
        "search_analyzer": "simple"
    }
}

在indexing结算,当es处理一个文档的时候,会选择一个analyzer,他首先会检查是否在index_analyzer字段中定义,如果没找到的话然后会在文档中查找,还没找到的话最后会在index中查找。

Mapping a completion field

为了为用户提供搜索功能,最常见的要求之一是为我们的查询提供文字建议。Elasticsearch提供了一个帮助器,通过一个称为completion的特殊类型映射来实现此功能。
比如为了给别名提供建议,我们可以编写一个类似的映射:

{
    "name": {
        "type": "string",
        "copy_to": [
            "suggest"
        ]
    },
    "alias": {
        "type": "string",
        "copy_to": [
            "suggest"
        ]
    },
    "suggest": {
        "type": "completion",
        "payloads": true,
        "analyzer": "simple",
        "search_analyzer": "simple"
    }
}

弹性搜索有几种提供建议的方法。 比如你可以使用具有通配符或前缀的某些查询,但是completion字段更快因为es做了内部优化。
在es内部,es建立了一个Finite State Transducer (FST)结构,具体可以查看: http://en.wikipedia.org/wiki/Finite_state_transducer
completion字段有几个比较重要的选项:

  • analyzer 定义了索引文档时使用的analyzer,默认是simple analyzer
  • search_analyzer 定义了搜索文档时使用的analyzer,默认是simple analyzer
  • preserve_separators 这个选项控制token如何处理,如果禁用,空格就会在suggestion被trim。默认为true
  • max_input_length 此属性减少输入字符串中的字符以减少建议大小。 一般不建议太长(默认50)。
  • payloads 默认为false,这个字段可以用来存储其他的信息,将会在suggestion被返回。比如你搜索一本书,你不但希望他返回书名,也希望返回ISBN,那么就可以使用下面的例子:
    curl -X PUT 'http://localhost:9200/myindex/mytype/1' -d '
    {
        "name":"Elasticsearch Cookbook",
        "suggest":{
            "input":[
                "ES",
                "Elasticsearch",
                "Elastic Search",
                "ElasticSearch Cookbook"
            ],
            "output":"Elasticsearch Cookbook",
            "payload":{
                "isbn":"1782166629"
            },
            "weight":34
        }
    }
    '
    

    在这个例子中,我们可以看到在索引阶段,suggest可以有其他的一些选项:

  • input 这将管理提供的可用于建议的值的列表。 如果你能够丰富您的数据,这可以提高您的建议的质量。
  • output 这是希望的结果(可选)。
  • payload 这包括一些要返回的额外数据(可选)。
  • weight 设置权重(可选)
本文版权归作者所有,禁止一切形式的转载,复制等操作
赞赏

微信赞赏支付宝赞赏

发表评论

电子邮件地址不会被公开。 必填项已用*标注