Elasticsearch 的存储与查询

news2024/12/26 19:24:55

Elasticsearch 的存储与查询

在搜索系统领域,数据的存储与查询是两个最基础且至关重要的环节。Elasticsearch(ES) 在这两方面进行了深度优化,使其在关系型数据库或非关系型数据库中脱颖而出,成为搜索系统的首选。

映射 (Mapping)

  • 映射 (Mapping)
    • 映射是 ES 中的一种元数据,用于描述文档中的数据结构和类型。映射可以在创建索引时自动推断,也可以手动定义。映射包括字段名、字段类型、是否可搜索、是否可分析等属性。映射可以在文档级别和索引级别定义。
    • ES 中是实现了动态映射的,在索引中写入下面的一个文档。
{
    "name":"jack",
    "age":18,
    "birthDate": "1991-10-05"
}
  • 在动态映射的作用下,name 会映射成 text 类型,age 会映射成 long 类型,birthDate 会被映射为 date 类型,自动判断的规则如下

    • JSON TypeField Type
      true, falseboolean
      123, 456, 876long
      123.43, 234.534double
      String, “2022-05-15”date
      String: “Hello Elasticsearch”string
      符合 IPv4 或 IPv6 地址格式ip
      字段的内容是 base64 编码的字符串binary
      字段的内容是一个数组,数组中的每个元素都将根据其内容被映射为相应的类型array
      字段的内容是一个 JSON 对象,那么它将被映射为 object 类型。对象中的每个属性都将根据其内容被映射为相应的类型object
      字段的内容是一个数组,且数组中的元素是对象,并且可以对内部对象进行精确查询nested
      字段的内容是经纬度对geo_point
      字段的内容是除点外的任意几何形状坐标geo_shape
  • Mapping 的字段类型

    • 字段类型是映射中的一种属性,用于描述文档中的字段数据类型。ES 支持多种字段类型,如文本、数值、日期、布尔值等。每种字段类型有其特点和限制,因此选择合适的字段类型对于优化查询性能和存储空间至关重要。
    • 一级分类二级分类具体类型
      核心类型字符串类型string,text,keyword
      整数类型integer,long,short,byte
      浮点类型double,float,half_float,scaled_float
      逻辑类型boolean
      日期类型date
      范围类型range(Integer_range,long_range,date_range…)
      二进制类型binary (BASE64 的二进制)
      复合类型数组类型array
      对象类型object
      嵌套类型nested
      地理类型地理坐标类型geo_point
      地理地图geo_shape
      特殊类型IP 类型ip
  • 字符串类型

    • text: ES 5x 后不再支持 string, 由 textkeyword 类型替代
      • 子类型
        • text: 类型适用于需要被全文检索的字段
        • match_only_text: 是 text 的空间优化变体,它禁用评分,它适合为日志消息建立索引
      • text 类型的 常用参数
        • analyzer: 指明该字段用于索引时和搜索时的分析字符串的分词器 (使用 search_analyzer 可覆盖它)。 默认为索引分析器或标准分词器
        • search_analyzer: 在搜索时,用于分析该字段的分析器,默认是 analyzer 参数的值
        • boost: 查询时字段匹配上时的权重级别,接受浮点数,默认为 1.0
        • fields: 它允许同一个字符串值以多种方式进行索引以满足不同的目的
        • index: 设置该字段是否可以用于搜索,默认为 true
        • eager_global_ordinals: 在刷新时急切地加载全局序数,对于经常用于 term 聚合的字段,启用此功能是个好主意 (但会影响写入速度)
        • fielddata: 指明该字段是否可以使用内存中的 fielddata 进行排序,聚合或脚本编写?该字段可能会消耗大量的内存,如果要用的话建议 keyword 类型的字段使用
        • similarity: 设置相关性排序公式,默认为 BM25
    • keyword
      • 子类型
        • keyword: 用于结构化过的内容,只能用于精准搜索,不会进行分词处理,常用户 ID、Email 等
        • constant_keyword: 某个字段为 constant_keyword 类型,则该索引中,所有文档的该字段的值必须一致,常用于版本号
        • wildcard: 这种类型主要用于非结构化的机器生成内容,对大数据量的字段做了优化,支持模糊匹配,常用于日志服务
      • keyword 类型的 常用参数
        • ignore_above: 当字段文本的长度大于指定值时,不会被索引,但是会存储
        • 其它参数: 同 text

## fields 字段示例
{
  "properties": {
    "title": {
      "type": "text",
      "analyzer": "ik_max_word",
      "search_analyzer": "ik_smart",
      "similarity": "custom_similarity",
      "doc_values": false,
      "fields": {
        "title_smart": {
          "type": "text",
          "analyzer": "ik_smart",
          "search_analyzer": "ik_smart",
          "similarity": "custom_similarity",
          "doc_values": false
        }
      }
    }
  }
}

# 自定义排序算法
"similarity": {
  "custom_similarity": {
    "type": "BM25",
    "b": 0.9,
    "k1": 1.2
  }
}
  • 数字类型

    • TypeDescription
      longA signed 64-bit integer with a minimum value of -263 and a maximum value of 263-1.
      integerA signed 32-bit integer with a minimum value of -231 and a maximum value of 231-1.
      shortA signed 16-bit integer with a minimum value of -32,768 and a maximum value of 32,767.
      byteA signed 8-bit integer with a minimum value of -128 and a maximum value of 127.
      doubleA double-precision 64-bit IEEE 754 floating point number, restricted to finite values.
      floatA single-precision 32-bit IEEE 754 floating point number, restricted to finite values.
      half_floatA half-precision 16-bit IEEE 754 floating point number, restricted to finite values.
      scaled_floatA floating point number that is backed by a long, scaled by a fixed double scaling factor.
      unsigned_longAn unsigned 64-bit integer with a minimum value of 0 and a maximum value of 264-1.
  • 范围类型

    • integer_rangeinteger 类型的区别在于,如果你的字段只包含一个整数值,你可以使用 integer 类型。如果你的字段包含一个整数范围,你可以使用 integer_range 类型
    • Range TypeDescription
      integer_rangeA range of signed 32-bit integers with a minimum value of -231 and maximum of 231-1.
      float_rangeA range of single-precision 32-bit IEEE 754 floating point values.
      long_rangeA range of signed 64-bit integers with a minimum value of -263 and maximum of 263-1.
      double_rangeA range of double-precision 64-bit IEEE 754 floating point values.
      date_rangeA range of date values. Date ranges support various date formats through the format mapping parameter. Regardless of the format used, date values are parsed into an unsigned 64-bit integer representing milliseconds since the Unix epoch in UTC. Values containing the now date math expression are not supported.
      ip_rangeA range of ip values supporting either IPv4 or IPv6 (or mixed) addresses.
# integer 存储例子
{
  "name": "John",
  "age": 25
}

# integer_range 存储例子
{
  "name": "John",
  "age": {
    "gte": 20,
    "lte": 30
  }
}

# 若用 keyword 类型定义 my_field, 则范围查询会变成"字符串比较"而非"数值比较"
GET /keyword_test/_search
{
  "query": {
    "range": {
      "my_field": {
        "gte": 21,
        "lt": 32
      }
    }
  }
}

"hits" : [
  {
    "_index" : "keyword_test",
    "_type" : "_doc",
    "_id" : "1",
    "_score" : 1.0,
    "_source" : {
      "my_field" : "3"
    }
  }
]
  • 对象类型
    • 对象类型即一个 JSON 对象,JSON 字符串允许嵌套对象,所以一个文档可以嵌套多个多层对象。但 Lucene 没有内部对象的概念,会将 JSON 文档扁平化
# 插入这个的一个文档
PUT my-index-000001/_doc/1
{
  "region": "US",
  "manager": {
    "age":     30,
    "name": {
      "first": "John",
      "last":  "Smith"
    }
  }
}

# 实际上该文档会被存储成 key-value 对的形式
{
  "region":             "US",
  "manager.age":        30,
  "manager.name.first": "John",
  "manager.name.last":  "Smith"
}

# 该文档会被动态的 mapping
{
  "mappings": {
    "properties": {
      "region": {
        "type": "keyword"
      },
      "manager": {
        "properties": {
          "age":  { "type": "integer" },
          "name": {
            "properties": {
              "first": { "type": "text" },
              "last":  { "type": "text" }
            }
          }
        }
      }
    }
  }
}

# 在搜索时
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "manager.name.first": "John"
          }
        }
      ]
    }
  }
}
  • 嵌套类型
    • nested 是一种特殊类型的 object 类型,它可以以数组对象的形式来进行索引,并且可以独立的查询其中的每一个对象

# ES 是没有内部对象的概念的,下述例子会动态的转化成一个"扁平化"的对象
{
  "group" : "fans",
  "user" : [
    {
      "first" : "John",
      "last" :  "Smith"
    },
    {
      "first" : "Alice",
      "last" :  "White"
    }
  ]
}

# 类似下述的方式存储
{
  "group" :        "fans",
  "user.first" : [ "alice", "john" ],
  "user.last" :  [ "smith", "white" ]
}

# 执行下述 query 会得到不正确的结果,因为对象失去了层级结构
{
  "query": {
    "bool": {
      "must": [
        { "match": { "user.first": "Alice" }},
        { "match": { "user.last":  "Smith" }}
      ]
    }
  }
}

# 以嵌套类型来定义字段
{
  "mappings": {
    "properties": {
      "user": {
        "type": "nested"
      }
    }
  }
}

# 插入相同的 doc
{
  "group" : "fans",
  "user" : [
    {
      "first" : "John",
      "last" :  "Smith"
    },
    {
      "first" : "Alice",
      "last" :  "White"
    }
  ]
}

# 以 nested 的方式进行检索,无结果返回
{
  "query": {
    "nested": {
      "path": "user",
      "query": {
        "bool": {
          "must": [
            { "match": { "user.first": "Alice" }},
            { "match": { "user.last":  "Smith" }}
          ]
        }
      }
    }
  }
}

# 在 ES 中,嵌套类型的字段会被转化成独立的文档,这些文档和主文档有相同的 id
  • 向量类型
    • 支持最大不超过 2048 维的向量,dense_vector 字段不支持查询、排序和聚合,只能接受 scripts 定义的函数
# 定义向量类型和维度
{
  "mappings": {
    "properties": {
      "my_vector": {
        "type": "dense_vector",
        "dims": 768
      }
    }
  }
}

# 定义相似度函数
{
"query": {
    "bool": {
        "must": {
            "function_score": {
                "functions": [
                {"script_score": {
                  "script": {
                  "source": "cosineSimilarity(params.queryVector, 'TitleVector') + 2.0",
                  "params": {
                      "queryVector": query_embedding
                  }}}}]}}}},
}

查询

  • 分析器
    • 被分析的字符串片段通过 analyzer 来传递,将字符串转换为一串 terms(词条) 用于索引及检索
    • 分析器 analyzer 和分词器 tokenizer 并不相同,分析器不等于分词器,分词器只是分析器的一部分
    • analyzer = [char_filter] + tokenizer + [token filter]
      • char filter: 对输入字符进行预处理,如去除 HTML 标签,ES 内置字符处理器
      • tokenizer: 对文本进行分词操作,如按照空格分词 (whitespace),标注分词器 (standard) 等,ES 内置分词器
        • standard: Elasticsearch 默认的分词器,它会根据空格和标点符号将文本拆分为 term, 会过滤掉标点符号,大写转小写
        • simple: 会根据非字母字符将文本拆分为 term, 过滤数字和标点符号,大写转小写
        • whitespace: 根据空格字符将文本拆分为 term, 不会进行过滤和大小写转换
        • keyword: 不会对文本进行拆分,常用于关键字字段或精确匹配字段
      • filter (token filter): 对 token 集合的元素做过滤和转换,如统一转小写、过滤停用词等,token 经过 filter 处理之后的结果被定义为:term, ES 内置 token filter
POST _analyze
{
  "analyzer": "simple",
  "text": ["HI 111 , 哈哈"]
}

# 分词结果
{
  "tokens" : [
    {
      "token" : "hi",
      "start_offset" : 0,
      "end_offset" : 2,
      "type" : "word",
      "position" : 0
    },
    {
      "token" : "哈哈",
      "start_offset" : 9,
      "end_offset" : 11,
      "type" : "word",
      "position" : 1
    }
  ]
}
  • match 查询
    • 支持全文搜索和精确查询,取决于字段是否支持全文检索
    • operator 默认情况下该操作符是 or, 我们可以将它修改成 and 让所有指定词项都必须匹配
    • minimum_should_match 最小匹配参数,可以指定必须匹配的词项数 (或者百分数) 来表示一个文档是否相关
# 全文搜索
GET job_item_profile/_search
{
  "query": {
    "match": {
      "job_name": "java 工程师"
    }
  }
}

# 精确查询
# 对于精确值的查询,可以使用 filter 语句来取代 query,因为 filter 将会被缓存
GET job_item_profile/_search
{
  "query": {
    "match": {
      "edu_level": "5000"
    }
  }
}

# operator
GET job_item_profile/_search
{
  "query": {
    "match": {
      "job_name": {
        "query": "java 工程师",
        "operator": "and"
      }
    }
  }
}

# minimum_should_match
GET job_item_profile/_search
{
  "query": {
    "match": {
      "job_name": {
        "query": "java 工程师",
        "minimum_should_match": "2"
      }
    }
  }
}
  • multi_match 查询
    • 多字段查询,可以给不同的字段指定不同的权重,返回匹配更高的结果
GET job_item_profile/_search
{
  "query": {
    "multi_match": {
      "query": "red",
      "fields": ["job_name^2.0", "company_name^1.0"]
    }
  }
}
  • range 查询
    • 范围查询操作符:gt (大于), gte(大于等于), lt(小于), lte(小于等于)
GET job_item_profile/_search
{
  "query": {
    "range": {
      "salary_max": {
        "gt": 4,
        "lt": 8
      }
    }
  }
}
  • term 查询

    • term 查询会去倒排索引中寻找确切的 term, 它并不会走分词器,只会去配倒排索引,若某个字段的 typetext, 若用 term 去查询有可能出现查询不到的情况
    • term 查询也不会处理大小写,typetext 的字段会调用分词器进行大小写转换
  • terms 查询

    • terms 查询与 term 查询一样,但它允许你指定多值进行匹配,如果这个字段包含了指定值中的任何一个值,那么这个文档就满足条件
GET job_item_profile/_search
{
  "query": {
    "terms": {
      "edu_level": [5000, 6000]
    }
  }
}
  • match_phrase
    • 短语查询/精确匹配,查询"java 专家"会匹配 job_name 字段包含"java 专家"短语的,而不会进行分词查询,也不会查询出"java 技术专家"这种词汇
GET job_item_profile/_search
{
  "query": {
    "match_phrase": {
      "job_name": "java 专家"
    }
  }
}
  • 复合查询
    • 使用 bool 语句实现复合查询,包括 must, must_not, should 和 filter
    • must: 表示文档一定要包含查询的内容
    • must_not: 表示文档一定不要包含查询的内容
    • should: 表示如果文档匹配上可以增加文档相关性得分
    • query DSL: 结构化查询,用于检查内容与条件是否匹配,内容查询中使用的 bool 和 match 语句,用于计算每个文档的匹配得分
    • filter DSL: 结构化过滤,只是简单的决定文档是否匹配,内容过滤中使用的 term 和 range 语句,会过滤掉不匹配的文档,并且不影响计算文档匹配得分,使用过滤查询会被 ES 自动缓存用来提高效率
    • 原则上来说,使用结构化查询语句做全文本搜索或其他需要进行相关性评分的情况,剩下的全部用过滤语句

实践

  • 列表字段如何处理
    • text
      • 纯中文 逗号分隔,simple
      • 纯英文,可能包含下划线,空格分隔,standard
      • 纯数字,空格分隔,standard
    • array, 通用方案,type=keyword, double. 注意,手动转小写。
  • IK 分析器的使用方式
    • 网上很多文章会建议,建立索引的时候使用 ik_max_word 模式;搜索的时候使用 ik_smart 模式。但在实际应用中,我们会发现 ik_smart 的结果并不完全是 ik_max_word 结果的子集,这样会出现搜不出的情况 参考: IK分词器实现原理剖析 —— 一个小问题引发的思考
    • 一种解决方法如下所示,对 title 字段分别以 ik_max_word 方式建立 title 字段,再以 ik_smart 方式建立 title_smart 子字段;在用户搜索时统一使用 ik_smart 方式进行搜索,这样能保证相关的 query 一定能命中索引
  {
  "properties": {
    "title": {
      "type": "text",
      "analyzer": "ik_max_word",
      "search_analyzer": "ik_smart",
      "similarity": "custom_similarity",
      "doc_values": false,
      "fields": {
        "title_smart": {
          "type": "text",
          "analyzer": "ik_smart",
          "search_analyzer": "ik_smart",
          "similarity": "custom_similarity",
          "doc_values": false
        }
      }
    }
  }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2252685.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

保护数据,构建信任:联邦学习与差分隐私在AI训练中的实践

文章目录 摘要引言什么是联邦学习?AI模型训练中的数据隐私挑战数据隐私面临的主要问题 联邦学习与差分隐私技术联邦学习的关键流程代码示例差分隐私技术联邦学习与差分隐私结合案例 QA环节总结参考资料 摘要 在人工智能快速发展的背景下,模型训练对数据…

【算法刷题指南】优先级队列

🌈个人主页: 南桥几晴秋 🌈C专栏: 南桥谈C 🌈C语言专栏: C语言学习系列 🌈Linux学习专栏: 南桥谈Linux 🌈数据结构学习专栏: 数据结构杂谈 🌈数据…

ThingsBoard规则链节点:Kafka 节点详解

引言 ThingsBoard 是一个开源的物联网平台,提供了设备管理、数据收集、处理和可视化等功能。规则链是 ThingsBoard 中的一个强大功能,允许用户定义复杂的业务逻辑来处理设备上报的数据。在规则链中,Kafka 节点用于将消息发送到 Apache Kafka …

基于Java Springboot个人财务APP且微信小程序

一、作品包含 源码数据库设计文档万字PPT全套环境和工具资源部署教程 二、项目技术 前端技术:Html、Css、Js、Vue、Element-ui 数据库:MySQL 后端技术:Java、Spring Boot、MyBatis 三、运行环境 开发工具:IDEA/eclipse 微信…

阿里云 Elastic Enterprise 正式上线!

在数据驱动的商业环境中,企业面临着日益复杂的数据管理与分析挑战。阿里云Elasticsearch服务不仅免费提供了 Elastic 原厂的 Enterprise 版本功能,更凭借其增强的数据管理能力、智能AI分析、先进的搜索技术以及全面的安全特性,致力于为企业提…

1201作业

思维导图 作业 头函数 #include <myhead.h> #include"linklist.h" int main(int argc, const char *argv[]) {//调用创建链表函数node_ptr L list_create();if(NULL L){return -1;}//调用头插函数list_insert_head(L,Q);list_insert_head(L,W);list_insert…

【Code First】.NET开源 ORM 框架 SqlSugar 系列

.NET开源 ORM 框架 SqlSugar 系列 【开篇】.NET开源 ORM 框架 SqlSugar 系列【入门必看】.NET开源 ORM 框架 SqlSugar 系列【实体配置】.NET开源 ORM 框架 SqlSugar 系列【Db First】.NET开源 ORM 框架 SqlSugar 系列【Code First】.NET开源 ORM 框架 SqlSugar 系列【数据事务…

大语言模型微调与 XTuner 微调实战

1 大语言模型微调 1.1 什么是微调 大语言模型微调&#xff08;Fine-tuning of Large Language Models&#xff09;是指在预训练的大型语言模型基础上&#xff0c;使用特定任务的数据进一步训练模型&#xff0c;以使其更好地适应和执行特定任务的过程&#xff0c;用于使LLM&am…

Vulnhub靶场 Matrix-Breakout: 2 Morpheus 练习

目录 0x00 准备0x01 主机信息收集0x02 站点信息收集0x03 漏洞查找与利用1. 文件上传2. 提权 0x04 总结 0x00 准备 下载连接&#xff1a;https://download.vulnhub.com/matrix-breakout/matrix-breakout-2-morpheus.ova 介绍&#xff1a; This is the second in the Matrix-Br…

基于hexo框架的博客搭建流程

这篇博文讲一讲hexo博客的搭建及文章管理&#xff0c;也算是我对于暑假的一个交代 &#xff01;&#xff01;&#xff01;注意&#xff1a;下面的操作是基于你已经安装了node.js和git的前提下进行的&#xff0c;并且拥有github账号 创建一个blog目录 在磁盘任意位置创建一个…

24.12.02 Element

import { createApp } from vue // 引入elementPlus js库 css库 import ElementPlus from element-plus import element-plus/dist/index.css //中文语言包 import zhCn from element-plus/es/locale/lang/zh-cn //图标库 import * as ElementPlusIconsVue from element-plus/i…

vxe-table 设置树表格斑马线条纹样式

vxe-table 设置斑马线条纹样式&#xff0c;通过设置 stripe 参数 官网&#xff1a;https://vxetable.cn 表格 斑马线条纹&#xff0c;通过设置 stripe 参数 <template><div><vxe-grid v-bind"gridOptions"></vxe-grid></div> </…

力扣3366.最小数组和

力扣3366.最小数组和 题目 题目解析及思路 题目要求对于数组进行两种操作&#xff0c;使最终数组和最小 注意&#xff1a;每个元素可以同时执行两种操作 考虑动归&#xff0c;暴力的遍历每种情况 代码 记忆化搜索 class Solution { public:// minArraySum 函数用于计算在…

缓存穿透,缓存雪崩,缓存击穿

缓存穿透&#xff1a; 客户端请求的数据在缓存中和数据库中都不存在&#xff0c;这样的缓存永远不会生效&#xff0c;这些请求会直接打到数据库中&#xff0c;造成数据库压力过大 解决方法&#xff1a;1.缓存空对象 //TODO 此方法中解决了缓存穿透问题&#xff08;使用了缓存…

【C++boost::asio网络编程】有关异步读写api的笔记

异步读写api 异步写操作async_write_someasync_send 异步读操作async_read_someasync_receive 定义一个Session类&#xff0c;主要是为了服务端专门为客户端服务创建的管理类 class Session { public:Session(std::shared_ptr<asio::ip::tcp::socket> socket);void Conn…

atcoder abc 382 lazy_tag线段树

A Daily Cookie 代码&#xff1a; #include <bits/stdc.h> using namespace std;typedef long long ll;int main() {int n, d;cin >> n >> d;string s;cin >> s;int cnt d;for(auto t: s) if(t .) cnt ;cout << min(n, cnt); } B Daily Co…

【NLP 8、normalization、sigmoid,softmax归一化函数】

"燃尽最后的本能&#xff0c;意志力会带你杀出重围" —— 24.12.2 1. Normalization&#xff08;归一化&#xff09; 归一化是将数据转换为具有统一尺度的形式&#xff0c;通常用于数据预处理阶段。常见的归一化方法包括 Min-Max归一化、Z-Score 归一化和 L…

深入学习指针(5)!!!!!!!!!!!!!!!

文章目录 1.回调函数是什么&#xff1f;2.qsort使用举例2.1使用qsort函数排序整形数据2.2使用sqort排序结构数据 3.qsort函数的模拟实现 1.回调函数是什么&#xff1f; 回调函数就是⼀个通过函数指针调⽤的函数。 如果你把函数的指针&#xff08;地址&#xff09;作为参数传递…

Matlab Simulink 电力电子仿真-单相电压型半桥逆变电路分析

目录 一、单相电压型半桥逆变电路仿真模型 1.电路模型 2.电路模型参数 二、仿真分析 三、总结 1.优缺点 2.应用场景 一、单相电压型半桥逆变电路仿真模型 1.电路模型 单相电压型半桥逆变电路是一种常见的逆变电路&#xff0c;主要用于将直流电源转换为交流电源。 &…

《Vue零基础入门教程》第十五课:样式绑定

往期内容 《Vue零基础入门教程》第六课&#xff1a;基本选项 《Vue零基础入门教程》第八课&#xff1a;模板语法 《Vue零基础入门教程》第九课&#xff1a;插值语法细节 《Vue零基础入门教程》第十课&#xff1a;属性绑定指令 《Vue零基础入门教程》第十一课&#xff1a;事…