【Elasticsearch系列十六】Mapping 映射

💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。
img

非常期待和您一起在这个小小的网络世界里共同探索、学习和成长。💝💝💝 ✨✨ 欢迎订阅本专栏 ✨✨

1.Mapping 映射

概念:自动或手动为 index 中的_doc 建立的一种数据结构和相关配置,简称为 mapping 映射。

插入几条数据,让 es 自动为我们建立一个索引

PUT /website/_doc/1
{
  "post_date": "2019-01-01",
  "title": "my first article",
  "content": "this is my first article in this website",
  "author_id": 11400
}

PUT /website/_doc/2
{
  "post_date": "2019-01-02",
  "title": "my second article",
  "content": "this is my second article in this website",
  "author_id": 11400
}

PUT /website/_doc/3
{
  "post_date": "2019-01-03",
  "title": "my third article",
  "content": "this is my third article in this website",
  "author_id": 11400
}

对比数据库建表语句

create table website(
     post_date date,
     title varchar(50),
     content varchar(100),
     author_id int(11)
 );

动态映射:dynamic mapping,自动为我们建立 index,以及对应的 mapping,mapping 中包含了每个 field 对应的数据类型,以及如何分词等设置。

重点:我们当然,也可以手动在创建数据之前,先创建 index,以及对应的 mapping

GET  /website/_mapping/
{
  "website" : {
    "mappings" : {
      "properties" : {
        "author_id" : {
          "type" : "long"
        },
        "content" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "post_date" : {
          "type" : "date"
        },
        "title" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        }
      }
    }
  }
}

尝试各种搜索

GET /website/_search?q=2019        0条结果
GET /website/_search?q=2019-01-01           1条结果
GET /website/_search?q=post_date:2019-01-01     1条结果
GET /website/_search?q=post_date:2019          0 条结果

搜索结果为什么不一致,因为 es 自动建立 mapping 的时候,设置了不同的 field 不同的 data type。不同的 data type 的分词、搜索等行为是不一样的。

2.精确匹配与全文搜索

exact value 精确匹配:

2019-01-01,exact value,搜索的时候,必须输入 2019-01-01,才能搜索出来

如果你输入一个 01,是搜索不出来的 select * from book where name= ‘java’

full text 全文检索:

搜“笔记电脑”,笔记本电脑词条也要搜索出来,是如何做到的呢?

select * from book where name like ‘%java%’

  1. 缩写 vs. 全称:cn vs. china

  2. 格式转化:like liked likes

  3. 大小写:Tom vs tom

  4. 同义词:like vs love

不是单纯的只是匹配完整的一个值,而是可以对值进行拆分词语后(分词)进行匹配,也可以通过缩写、时态、大小写、同义词等进行匹配。

3.倒排索引核心原理

计算机索引程序通过扫描文章中的每一个词,对每一个词建立一个索引,指明该词在文章中出现的次数和位置,当用户查询时,检索程序就根据事先建立的索引进行查找,并将查找的结果反馈给用户的检索方式。这种建立索引的方式叫倒排索引。
当数据写入 ES 时,数据将会通过分词被切分为不同的 term,ES 将 term 与其对应的文档列表建立一种映射关系,这种结构就是倒排索引。如下图所示

image-20230514010652308

为了进一步提升索引的效率,ES term 的基础上利用 term 的前缀或者后缀构建了 term index, 用于对 term 本身进行索引,ES 实际的索引结构如下图所示:

image-20230514010727013

这样当我们去搜索某个关键词时,ES 首先根据它的前缀或者后缀迅速缩小关键词的在 term dictionary 中的范围,大大减少了磁盘IO的次数

举例

doc1:I really liked my small dogs, and I think my mom also liked them.

doc2:He never liked any dogs, so I hope that my mom will not expect me to liked him.

分词,初步的倒排索引的建立

termdoc1doc2
I**
really*
liked**
my**
small*
dogs*
and*
think*
mom**
also*
them*
He*
never*
any*
so*
hope*
that*
will*
not*
expect*
me*
to*
him*

演示了一下倒排索引最简单的建立的一个过程

mother like little dog,不可能有任何结果

这不是我们想要的结果。同义词 mom\mother 在我们人类看来是一样。想进行标准化操作。

重建倒排索引:

normalization 正规化,建立倒排索引的时候,会执行一个操作,也就是说对拆分出的各个单词进行相应的处理,以提升后面搜索的时候能够搜索到相关联的文档的概率

时态的转换,单复数的转换,同义词的转换,大小写的转换

  • mom ―> mother

  • liked ―> like

  • small ―> little

  • dogs ―> dog

重新建立倒排索引,加入 normalization,再次用 mother liked little dog 搜索,就可以搜索到了

worddoc1doc2normalization
I**
really*
like**liked ―> like
my**
little*small ―> little
dog*dogs ―> dog
and*
think*
mother**mom ―> mother
also*
them*
He*
never*
any*
so*
hope*
that*
will*
not*
expect*
me*
to*
him*

重新搜索

搜索:mother liked little dog

对搜索条件经行分词 normalization

mother

liked -》like

little

dog

doc1 和 doc2 都会搜索出来

4.分词器 analyzer

作用:

  • 切分词语
  • normalization
  • 提升 recall 召回率

analyzer:给你一段句子,然后将这段句子拆分成一个一个的单个的单词,同时对每个单词进行 normalization(时态转换,单复数转换)

recall召回率:搜索的时候,增加能够搜索到的结果的数量

analyzer 组成部分:

  • character filter:在一段文本进行分词之前,先进行预处理,比如说最常见的就是,过滤 html 标签
  • tokenizer:分词,hello you and me --> hello, you, and, me
  • token filter:
    • lowercase
    • stop word: a/the/an --> 干掉
    • synonymom
      • dogs --> dog 单复数
      • liked --> like 时态
      • Tom --> tom 大小写
      • mother --> mom 近义词
      • small --> little 近义词

一个分词器,将一段文本进行各种处理,最后处理好的结果才会拿去建立倒排索引。

5.内置分词器

例句:Set the shape to semi-transparent by calling set_trans(5)

  • standard analyzer 标准分词器:set, the, shape, to, semi, transparent, by, calling, set_trans, 5(默认的是 standard)

  • simple analyzer 简单分词器:set, the, shape, to, semi, transparent, by, calling, set, trans

  • whitespace analyzer:Set, the, shape, to, semi-transparent, by, calling, set_trans(5)

  • language analyzer(特定的语言的分词器,比如说,english,英语分词器):set, shape, semi, transpar, call, set_tran, 5

内置分词器官方文档

image-20230511114715378

6.根据字段分词策略

query string 必须以和 index 建立时相同的 analyzer 进行分词

query string 对 exact value 和 full text 的区别对待

  • date:exact value 精确匹配

  • text: full text 全文检索

#测试分词器
GET /_analyze
{
  "analyzer": "standard",
  "text": "Text to analyze 80"
}

返回值:

{
  "tokens": [
    {
      "token": "text",
      "start_offset": 0,
      "end_offset": 4,
      "type": "<ALPHANUM>",
      "position": 0
    },
    {
      "token": "to",
      "start_offset": 5,
      "end_offset": 7,
      "type": "<ALPHANUM>",
      "position": 1
    },
    {
      "token": "analyze",
      "start_offset": 8,
      "end_offset": 15,
      "type": "<ALPHANUM>",
      "position": 2
    },
    {
      "token": "80",
      "start_offset": 16,
      "end_offset": 18,
      "type": "<NUM>",
      "position": 3
    }
  ]
}
  • token 实际存储的 term 关键字

  • position 在此词条在原文本中的位置

  • start_offset/end_offset 字符在原始字符串中的位置

7.mapping 总结

  1. 往 es 里面直接插入数据,es 会自动建立索引,同时建立对应的 mapping。(dynamic mapping)

  2. mapping 中就自动定义了每个 field 的数据类型

  3. 不同的数据类型(比如说 text 和 date),可能有的是 exact value,有的是 full text

  4. exact value,在建立倒排索引的时候,分词的时候,是将整个值一起作为一个关键词建立到倒排索引中的;full text,会经历各种各样的处理,分词,normaliztion(时态转换,同义词转换,大小写转换),才会建立到倒排索引中。

  5. 同时呢,exact value 和 full text 类型的 field 就决定了,在一个搜索过来的时候,对 exact value field 或者是 full text field 进行搜索的行为也是不一样的,会跟建立倒排索引的行为保持一致;比如说 exact value 搜索的时候,就是直接按照整个值进行匹配,full text query string,也会进行分词和 normalization 再去倒排索引中去搜索

  6. 可以用 es 的 dynamic mapping,让其自动建立 mapping,包括自动设置数据类型;也可以提前手动创建 index 和 tmapping,自己对各个 field 进行设置,包括数据类型,包括索引行为,包括分词器,等。

8.核心的数据类型

官网数据类型

类型说明
stringtext and keyword
Numericlong, integer, short, byte, double, float, half_float, scaled_float
Datedate
Date nanosecondsdate_nanos
Booleanboolean
Binarybinary
Rangeinteger_range, float_range, long_range, double_range, date_range

image-20230515150721751

dynamic mapping 推测规则:

  • true or false --> boolean

  • 123 --> long

  • 123.45 --> double

  • 2019-01-01 --> date

  • “hello world” --> text/keywod

查看 mapping:

GET /index/_mapping/

9.手动管理 mapping

查询所有索引的映射:

GET /_mapping

创建映射:

创建索引后,应该立即手动创建映射

PUT book/_mapping
{
	"properties": {
           "name": {
                  "type": "text"
            },
           "description": {
              "type": "text",
              "analyzer":"english",
              "search_analyzer":"english"
           },
           "pic":{
             "type":"text",
             "index":false
           },
           "studymodel":{
             "type":"text"
           }
    }
}

10.Text 文本类型

analyzer:

通过 analyzer 属性指定分词器。

上边指定了 analyzer 是指在创建索引和搜索时都使用 english,如果单独想定义搜索时使用的分词器则可以通过 search_analyzer 属性。

index:

index 属性指定是否索引。默认为 index=true,即要进行索引,只有进行索引才可以从索引库搜索到。

但是也有一些内容不需要索引,比如:商品图片地址只被用来展示图片,不进行搜索图片,此时可以将 index 设置为 false。

删除索引,重新创建映射,将 pic 的 index 设置为 false,尝试根据 pic 去搜索,结果搜索不到数据。

store:

是否在 source 之外存储,每个文档索引后会在 ES 中保存一份原始文档,存放在"_source"中,一般情况下不需要设置 store 为 true,因为在_source 中已经有一份原始文档了。

测试

PUT book/_mapping
{
		"properties": {
           "name": {
                  "type": "text"
            },
           "description": {
              "type": "text",
              "analyzer":"english",
              "search_analyzer":"english"
           },
           "pic":{
             "type":"text",
             "index":false
           },
           "studymodel":{
             "type":"text"
           }
    }
}

插入文档:

PUT /book/_doc/1
{
  "name":"Bootstrap开发框架",
  "description":"Bootstrap是由Twitter推出的一个前台页面开发框架,在行业之中使用较为广泛。此开发框架包含了大量的CSS、JS程序代码,可以帮助开发者(尤其是不擅长页面开发的程序人员)轻松的实现一个不受浏览器限制的精美界面效果。",
  "pic":"group1/M00/00/01/wKhlQFqO4MmAOP53AAAcwDwm6SU490.jpg",
  "studymodel":"201002"
}

Get /book/_search?q=name:开发

Get /book/_search?q=description:开发

Get /book/_search?q=pic:group1/M00/00/01/wKhlQFqO4MmAOP53AAAcwDwm6SU490.jpg

Get /book/_search?q=studymodel:201002

通过测试发现:name 和 description 都支持全文检索,pic 不可作为查询条件。

11.keyword 关键字

目前已经取代了"index": false。

上边介绍的 text 文本字段在映射时要设置分词器,keyword 字段为关键字字段,通常搜索 keyword 是按照整体搜索,所以创建 keyword 字段的索引时是不进行分词的,比如:邮政编码、手机号码、身份证等。

keyword 字段通常用于过虑、排序、聚合等。

12.date 日期类型

日期类型不用设置分词器。通常日期类型的字段用于排序。

format:通过 format 设置日期格式

下边的设置允许 date 字段存储年月日时分秒、年月日格式。

{
  "properties": {
    "timestamp": {
      "type": "date",
      "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd"
    }
  }
}

插入文档:

Post book/doc/3
{
  "name": "spring 开发基础",
  "description": "spring 在 java 领域非常流行,java 程序员都在用。",
  "studymodel": "201001",
  "pic": "group1/M00/00/01/wKhlQFqO4MmAOP53AAAcwDwm6SU490.jpg",
  "timestamp": "2018-07-04 18:28:58"
}

13.数值类型

1、尽量选择范围小的类型,提高搜索效率

2、对于浮点数尽量用比例因子,比如一个价格字段,单位为元,我们将比例因子设置为 100 这在 ES 中会按分 存储,映射如下:

"price": {
        "type": "scaled_float",
        "scaling_factor": 100
  },

由于比例因子为 100,如果我们输入的价格是 23.45 则 ES 中会将 23.45 乘以 100 存储在 ES 中。

如果输入的价格是 23.456,ES 会将 23.456 乘以 100 再取一个接近原始值的数,得出 2346。

使用比例因子的好处是整型比浮点型更易压缩,节省磁盘空间。

更新已有映射,并插入文档:

PUT book/doc/3
{
"name": "spring开发基础",
"description": "spring 在java领域非常流行,java程序员都在用。",
"studymodel": "201001",
 "pic":"group1/M00/00/01/wKhlQFqO4MmAOP53AAAcwDwm6SU490.jpg",
 "timestamp":"2018-07-04 18:28:58",
 "price":38.6
}

14.修改映射

只能创建 index 时手动建立 mapping,或者新增 field mapping,但是不能 update field mapping。

因为已有数据按照映射早已分词存储好。如果修改,那这些存量数据怎么办。

删除映射:通过删除索引来删除映射。

新增一个字段 mapping

PUT /book/_mapping/
{
  "properties": {
    "new_field": {
      "type": "text",
      "index": "false"
    }
  }
}

如果修改 mapping,会报错

PUT /book/_mapping/
{
  "properties": {
    "studymodel": {
      "type": "keyword"
    }
  }
}

返回:

{
  "error": {
    "root_cause": [
      {
        "type": "illegal_argument_exception",
        "reason": "mapper [studymodel] of different type, current_type [text], merged_type [keyword]"
      }
    ],
    "type": "illegal_argument_exception",
    "reason": "mapper [studymodel] of different type, current_type [text], merged_type [keyword]"
  },
  "status": 400
}

15.复杂数据类型

multivalue field:

{
  "tags": ["tag1", "tag2"]
}

建立索引时与 string 是一样的,数据类型不能混

empty field:

null,[],[null]

object field:

PUT /company/_doc/1
{
  "address": {
    "country": "china",
    "province": "guangdong",
    "city": "guangzhou"
  },
  "name": "jack",
  "age": 27,
  "join_date": "2019-01-01"
}

address:object 类型

查询映射

GET /company/_mapping
{
  "company" : {
    "mappings" : {
      "properties" : {
        "address" : {
          "properties" : {
            "city" : {
              "type" : "text",
              "fields" : {
                "keyword" : {
                  "type" : "keyword",
                  "ignore_above" : 256
                }
              }
            },
            "country" : {
              "type" : "text",
              "fields" : {
                "keyword" : {
                  "type" : "keyword",
                  "ignore_above" : 256
                }
              }
            },
            "province" : {
              "type" : "text",
              "fields" : {
                "keyword" : {
                  "type" : "keyword",
                  "ignore_above" : 256
                }
              }
            }
          }
        },
        "age" : {
          "type" : "long"
        },
        "join_date" : {
          "type" : "date"
        },
        "name" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        }
      }
    }
  }
}

object

{
  "address": {
    "country": "china",
    "province": "guangdong",
    "city": "guangzhou"
  },
  "name": "jack",
  "age": 27,
  "join_date": "2017-01-01"
}

底层存储格式

{
    "name":            [jack],
    "age":          [27],
    "join_date":      [2017-01-01],
    "address.country":         [china],
    "address.province":   [guangdong],
    "address.city":  [guangzhou]
}

对象数组:

{
  "authors": [
    { "age": 26, "name": "Jack White" },
    { "age": 55, "name": "Tom Jones" },
    { "age": 39, "name": "Kitty Smith" }
  ]
}

存储格式:

{
    "authors.age":    [26, 55, 39],
    "authors.name":   [jack, white, tom, jones, kitty, smith]
}

觉得有用的话点个赞 👍🏻 呗。
❤️❤️❤️本人水平有限,如有纰漏,欢迎各位大佬评论批评指正!😄😄😄

💘💘💘如果觉得这篇文对你有帮助的话,也请给个点赞、收藏下吧,非常感谢!👍 👍 👍

🔥🔥🔥Stay Hungry Stay Foolish 道阻且长,行则将至,让我们一起加油吧!🌙🌙🌙

img

<think>嗯,用户想了解Excel中的VLOOKUP函数的用法和参数含义。首先,我需要回忆一下VLOOKUP的基本结构。VLOOKUP是垂直查找函数,用于在表格的首列查找指定的值,然后返回该行中指定列的数据。它的四个参数分别是查找值、表格范围、列索引号和匹配模式。 接下来,我得确认每个参数的具体作用。第一个参数是lookup_value,也就是用户要查找的值,比如产品ID或者姓名。第二个参数是table_array,即查找的范围,这里要注意的是,查找值必须位于这个范围的第一列,否则函数无法正确工作。第三个参数是col_index_num,也就是用户想要返回的数据在表格范围中的第几列,这个列数是从表格范围的第一列开始算起的,不是整个工作表的列。第四个参数是range_lookup,决定是精确匹配还是近似匹配,通常用FALSE或0来指定精确匹配,避免错误。 然后,用户可能需要一个具体的例子来理解如何使用。比如,假设有一个产品价格表,用户想根据产品ID查找对应的价格。这时候,VLOOKUP就可以在ID列查找,然后返回价格列的数据。同时,要提醒用户注意表格范围最好使用绝对引用,比如$A$2:$C$100,这样在拖动公式时范围不会变化。 可能遇到的问题也需要考虑。比如,如果查找值不在表格的第一列,或者列索引号超过了表格的列数,函数会返回错误。此外,数据格式不一致也可能导致问题,比如查找值是数字,而表格中是文本格式的数字,这时候需要统一格式。还有,当出现#N/A错误时,可能是查找值不存在,或者匹配模式设置不正确,需要检查参数是否正确。 用户可能还会问到如何避免常见的错误,比如部分数据匹配出错的情况。这时候需要检查是否有多余的空格,或者数据格式不一致,或者表格范围没有锁定导致拖动时偏移。此外,XLOOKUP作为VLOOKUP的升级版,可能在某些情况下更方便,比如可以向左查找或者返回多列数据,这也是可以提及的内容。 最后,整理步骤,从基础语法到参数说明,再到具体案例,逐步引导用户理解如何使用VLOOKUP函数。同时,提供常见错误和解决方法,帮助用户在实际应用中避免问题。如果有必要,还可以比较VLOOKUP和其他查找函数的区别,比如HLOOKUP或XLOOKUP,但根据用户的问题,主要集中在VLOOKUP本身即可。</think>### Excel VLOOKUP函数详解 #### 一、基础语法与参数说明 VLOOKUP函数的语法为: $$=VLOOKUP(lookup\_value, table\_array, col\_index\_num, [range\_lookup])$$ 包含4个参数: 1. **lookup_value**(必填):要查找的值(如单元格引用或具体值) 2. **table_array**(必填):包含数据的表格范围(必须包含查找列和返回列) 3. **col_index_num**(必填):返回值所在列的序号(从table_array第一列开始计数) 4. **range_lookup**(可选):匹配类型 - `TRUE`/`1`:近似匹配(默认值,需数据升序排列) - `FALSE`/`0`:精确匹配(常用选项) [^1][^2] #### 二、使用步骤演示(工资表查询案例) 假设需要根据员工编号查询工资: 1. 建立查询单元格(如`B12`) 2. 输入公式: ```excel =VLOOKUP(A12, $A$2:$D$100, 4, 0) ``` - `A12`:待查询的员工编号 - `$A$2:$D$100`:锁定数据区域(绝对引用) - `4`:返回第4列(工资列) - `0`:精确匹配 [^2][^3] #### 三、常见错误与解决方法 | 错误现象 | 原因 | 解决方案 | |---------|------|---------| | #N/A | 查找值不存在 | 检查数据源或改用`IFERROR`容错 | | #REF! | 列序号超出范围 | 确认col_index_num ≤ 表格列数 | | 部分匹配失败 | 数据格式不一致 | 统一数值/文本格式 | | 结果错位 | 表格未锁定 | 使用`$`符号固定区域引用 | [^3][^4] #### 四、进阶技巧 1. **多条件查询**: 使用辅助列合并多个条件字段 ```excel =VLOOKUP(A2&B2, $D$2:$F$100, 3, 0) ``` 2. **通配符匹配**: `"*"`匹配任意字符,`"?"`匹配单个字符 ```excel =VLOOKUP("张*", $A$2:$C$100, 3, 0) ``` 3. **跨表查询**: 引用其他工作表数据 ```excel =VLOOKUP(A2, Sheet2!$A$2:$D$100, 4, 0) ``` [^1][^4]
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

檀越@新空间

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值