美文网首页
Elasticsearch 7.x 深入【1】索引【二】创建

Elasticsearch 7.x 深入【1】索引【二】创建

作者: 孙瑞锴 | 来源:发表于2020-04-03 19:30 被阅读0次

    1. 借鉴

    极客时间 阮一鸣老师的Elasticsearch核心技术与实战
    官方文档 creating_an_index
    官方文档 mapping
    官方文档 multi-fields

    2. 开始

    创建索引

    在前面,我们知道了什么是es中的索引,接下来我们就来创建一个索引

    方式1:通过索引一篇文档创建一个新索引

    • 比如:一开始并没有酒店的索引,我想创建一个有关酒店的索引
    PUT /hotel/_doc/1
    {
      "name": "测试酒店1",
      "grade": 2.5,
      "address": "北京市"
    }
    
    • 上面这个语句创建了id为1包含三个属性(name,grade,address)的酒店

    突然我想加为这篇文档添加/删除/修改一个属性怎么办呢?好的,多问几个为什么,我们会在后续讲,我会把连接粘贴到这里 // TODO

    • 太草率了吧,这样就创建了索引了么。是的-_-,那如果我要将文档2添加到hotel索引中该如何呢?
    PUT /hotel/_doc/2
    {
      "name": "测试酒店2",
      "grade": 3,
      "address": "上海市"
    }
    
    • 可以看到,当你索引第一篇新文档时会自动创建索引(es会自动根据数据格式识别它的类型),我们可以查看一下这篇索引的结构
    • 在kibana中键入以下语句,查看索引的结构

    GET /hotel/_mapping

    • 可以看到kibana控制台返回以下信息
    {
      "hotel" : {
        "mappings" : {
          "properties" : {
            "address" : {
              "type" : "text",
              "fields" : {
                "keyword" : {
                  "type" : "keyword",
                  "ignore_above" : 256
                }
              }
            },
            "grade" : {
              "type" : "float"
            },
            "name" : {
              "type" : "text",
              "fields" : {
                "keyword" : {
                  "type" : "keyword",
                  "ignore_above" : 256
                }
              }
            }
          }
        }
      }
    }
    
    • 额,那这些都是些什么呢,第二语言是英语的看官能猜出来个大概,我们标记一下


      属性解析
    • 可能有疑问的就是fields属性了,我在文章开头贴上了官方文档[multi-fields],这里再简单解释一下,什么叫”为不同的目的以不同的方式索引相同的字段“。最常用的同一个字段指定不同的分词器,比如说都是name字段,我使用两个分词器,一个是简体中文分词器,另外一个是拼音分词器,那么我们就可以使用fields定义两个分词器,一个是用于简体中文分词器,另外一个是拼音分词器,类似于下面这种,(如果运行下面这个语句报错,先下载ik和pinyin分词器 // TODO es插件下载),搜索的时候指定同一个字段的不同属性进行查询,比如我们有以下索引:
    PUT /hotel_multi_fields
    {
      "mappings": {
        "properties": {
          "name": {
            "type": "text",
            "analyzer": "ik_smart",
            "fields": {
              "pinyin": {
                "type": "text",
                "analyzer": "pinyin"
              }
            }
          }
        }
      }
    }
    
    • 那我们根据两个属性来进行查询
    # 添加文档
    # googledjd
    PUT /hotel_multi_fields/_doc/1
    {
      "name": "google大酒店"
    }
    
    PUT /hotel_multi_fields/_doc/2
    {
      "name": "微软大酒店"
    }
    
    # 查询
    # 使用name属性查询
    GET /hotel_multi_fields/_search
    {
      "query": {
        "term": {
          "name": {
            "value": "google"
          }
        }
      }
    }
    
    # 使用name.pinyin属性来查询
    GET /hotel_multi_fields/_search
    {
      "query": {
        "term": {
          "name.pinyin": {
            "value": "wrdjd"
          }
        }
      }
    }
    

    全字段的解析会在后面的章节有详解。额,好像走远了。。。

    • 当然这种方式有一定限制,但是读到这里的看官一般不会遇到,我会在后续章节详细叙述一些属性对于此种方式的限制。(// TODO)

    方式2:通过指定mappings来创建一个新索引

    • 方式1是基于es的动态索引类型识别,但是这种动态识别,有时候识别的并不是我们想要的结果。那我们就来举个栗子:我要索引hotel,name为文本类型,gradle为double类型,adress为文本类型,distance为double类型;但是我在创建索引文档的时候不小心类型输入错误了,输入了字符串类型,我们基于以上做测试。
    # 先删除已有索引
    DELETE /hotel
    
    # 创建hotel索引,并索引id为1的文档[这种就是方式1,一气呵成对吧]
    PUT /hotel/_doc/1
    {
      "name": "测试酒店1",
      "grade": 2.5,
      "address": "北京市",
      "distance": "25.0"
    }
    
    # 我们来看看它的索引结构
    GET /hotel/_mapping
    
    • 返回结果如下
    {
      "hotel" : {
        "mappings" : {
          "properties" : {
            "address" : {
              "type" : "text",
              "fields" : {
                "keyword" : {
                  "type" : "keyword",
                  "ignore_above" : 256
                }
              }
            },
            "distance" : {
              "type" : "text",
              "fields" : {
                "keyword" : {
                  "type" : "keyword",
                  "ignore_above" : 256
                }
              }
            },
            "grade" : {
              "type" : "float"
            },
            "name" : {
              "type" : "text",
              "fields" : {
                "keyword" : {
                  "type" : "keyword",
                  "ignore_above" : 256
                }
              }
            }
          }
        }
      }
    }
    
    • 我们不小心设置错了类型它就将错就错,得到了我们不想要的结果,当然责任主要在我们。那接下来,我们精确的设置一下类型呢?
    # 先删除已有索引
    DELETE /hotel
    
    # 指定索引结构
    PUT /hotel
    {
      "mappings": {
        "properties": {
          "name": {
            "type": "text"
          },
          "grade": {
            "type": "double"
          },
          "address": {
            "type": "text"
          },
          "distance": {
            "type": "double"
          }
        }
      }
    }
    
    # 再次插入相同的数据
    PUT /hotel/_doc/1
    {
      "name": "测试酒店1",
      "grade": 2.5,
      "address": "北京市",
      "distance": "25.0"
    }
    
    # 看看它的索引结构
    GET /hotel/_mapping
    
    {
      "hotel" : {
        "mappings" : {
          "properties" : {
            "address" : {
              "type" : "text"
            },
            "distance" : {
              "type" : "double"
            },
            "grade" : {
              "type" : "double"
            },
            "name" : {
              "type" : "text"
            }
          }
        }
      }
    }
    
    # 看下数据
    GET /hotel/_search
    
    {
      "took" : 0,
      "timed_out" : false,
      "_shards" : {
        "total" : 1,
        "successful" : 1,
        "skipped" : 0,
        "failed" : 0
      },
      "hits" : {
        "total" : {
          "value" : 1,
          "relation" : "eq"
        },
        "max_score" : 1.0,
        "hits" : [
          {
            "_index" : "hotel",
            "_type" : "_doc",
            "_id" : "1",
            "_score" : 1.0,
            "_source" : {
              "name" : "测试酒店1",
              "grade" : 2.5,
              "address" : "北京市",
              "distance" : "25.0"
            }
          }
        ]
      }
    }
    
    • 可以看到,数据虽然是文本类型,但是索引本身并没有更改,如果我们这时新增一篇文档,把distance设置为非数字的文本呢?
    PUT /hotel/_doc/2
    {
      "name": "测试酒店1",
      "grade": 2.5,
      "address": "北京市",
      "distance": "啊哈哈"
    }
    
    • 结果会报错
    {
      "error": {
        "root_cause": [
          {
            "type": "mapper_parsing_exception",
            "reason": "failed to parse field [distance] of type [double] in document with id '2'. Preview of field's value: '啊哈哈'"
          }
        ],
        "type": "mapper_parsing_exception",
        "reason": "failed to parse field [distance] of type [double] in document with id '2'. Preview of field's value: '啊哈哈'",
        "caused_by": {
          "type": "number_format_exception",
          "reason": "For input string: \"啊哈哈\""
        }
      },
      "status": 400
    }
    
    • 由此我们会猜测它内部会调用Double.valueOf()方法,如果报错就抛出来,如果是文本数字 的话,还能使用。

    更多的时候,我们需要确定索引的结构,而非让es自动匹配,同时以便在我们设置错误的类型时es也能给我提示。

    • 所以创建用此方式创建索引的最简模板就是
    PUT /索引的名字
    {
      "mappings": {
        "properties": {
          "xxx1属性": {
            "type": "该属性的类型"
          },
         "xxx2属性": {
            "type": "该属性的类型"
          }
        }
      }
    }
    

    比如我们创建一个person的索引

    PUT /person
    {
      "mappings": {
        "properties": {
          "name": {
            "type": "text"
          },
          "age": {
            "type": "integer"
          },
          "sex": {
            "type": "boolean"
          }
        }
      }
    }
    

    除了以上简单的属性,我们还可参看官方文档有关mapping的更多属性(连接参看借鉴部分 [官方文档 mapping])

    3. 大功告成

    相关文章

      网友评论

          本文标题:Elasticsearch 7.x 深入【1】索引【二】创建

          本文链接:https://www.haomeiwen.com/subject/ywwzuhtx.html