ElasticSearch系列二(索引操作、文档操作、查询、深度分页、排序、DSL、检索原理)

张开发
2026/4/13 6:00:23 15 分钟阅读

分享文章

ElasticSearch系列二(索引操作、文档操作、查询、深度分页、排序、DSL、检索原理)
文章目录索引操作创建索引查看索引删除索引更新索引获取索引的统计信息文档创建、修改、删除创建文档修改文档删除文档批量操作_bulk文档查询简单KV对查询ES高级查询Query DSL批量查询_mget和_msearch查询所有match_all分页from、to、排序 sort关键字查询/精确查询term范围查询range多id查询ids模糊查询fuzzy高亮查询highlight深度分页什么是深度分页为什么深度分页会造成问题如何解决深度分页问题Scroll API和Search_afterES检索原理索引操作在Elasticsearch中你可以使用以下的REST API来创建、查看和删除索引。创建索引创建索引你可以使用PUT请求来创建一个新的索引。例如以下的请求将创建一个名为my_index的新索引PUT/my_index你也可以在请求的主体中指定索引的设置和映射PUT/my_index{settings:{number_of_shards:1,number_of_replicas:1},mappings:{properties:{field1:{type:text}}}}查看索引查看索引你可以使用GET请求来查看一个或多个索引的信息。例如以下的请求将返回my_index索引的信息GET/my_indexGET /indexName获取名为indexName的索引的信息。settings这部分包含了索引的设置信息如分片数量、副本数量、索引创建时间等。mappings这部分包含了索引的映射信息即索引中每个字段的名称、类型、是否被索引等。aliases这部分包含了索引的别名信息。别名是索引的一个或多个替代名称可以用于方便地引用索引。{ indexName: { aliases: {}, mappings: { properties: { field1: { type: text }, field2: { type: integer } } }, settings: { index: { creation_date: 1630934097874, number_of_shards: 5, number_of_replicas: 1, uuid: c3NgT_XxT2aDfpn0bD4v2g, version: { created: 7080099 }, provided_name: indexName } } } }你也可以使用_catAPI来查看所有索引的列表GET/_cat/indices?v在Elasticsearch中_mapping是一个API用于获取或更新索引的mapping信息。Mapping是定义如何存储和索引文档及其字段的过程。你可以把它看作是Elasticsearch中的schema它定义了字段的类型如字符串、整数、日期等、是否被索引、是否存储原始值、分词器的设置等。你可以使用GET /index/_mapping命令来获取指定索引的mapping信息。例如GET/my_index/_mapping这个命令将返回my_index索引的mapping信息。你也可以使用PUT /index/_mapping命令来更新指定索引的mapping信息。但请注意一旦一个字段的mapping被定义它就不能被修改。如果你需要改变一个字段的mapping你必须创建一个新的索引然后将数据重新索引到新的索引中。删除索引删除索引你可以使用DELETE请求来删除一个索引。例如以下的请求将删除my_index索引DELETE/my_index更新索引获取索引的统计信息GET /_stats在Elasticsearch中_stats是一个API用于获取索引的统计信息。你可以使用GET /index/_stats命令来获取指定索引的统计信息。例如GET/my_index/_stats这个命令将返回my_index索引的统计信息包括文档数量、存储大小、索引操作的数量和时间等。你也可以使用GET /_stats命令来获取所有索引的统计信息GET/_stats此外你还可以在_stats命令后添加特定的指标如docs、store、indexing、search等来获取特定的统计信息。例如以下命令将返回所有索引的文档数量和存储大小GET/_stats/docs,store请注意你需要有查看统计信息的权限否则这个请求将返回一个错误。删除一个索引是不可逆的操作所以在执行这个操作之前请确保你不再需要这个索引中的任何数据。文档创建、修改、删除在Elasticsearch中你可以使用PUT或POST请求来创建文档使用POST请求刷新已有的文档进行修改或者使用DELETE请求来删除文档。创建文档创建文档你可以使用PUT或POST请求向指定索引添加新的文档。如果你想要指定文档ID应该使用PUT请求。如果你要Elasticsearch自动生成文档ID则应该使用POST请求。创建新的文档示例PUT /index_name/_doc/1 { field1: value1, field2: value2 }# 创建文档指定id # 如果id不存在创建新的文档否则先删除现有文档再创建新的文档版本会增加 # 使用PUT时必须有id PUT /es_db/_doc/1 { name: 张三, age: 25, sex: 1 } # 创建文档ES生成idPOST可以没有id # POST携带id时也是更新底层删除旧数据重新索引新文档 POST /es_db/_doc { name: 张三, age: 25, sex: 1 } # _create时如果id已存在会报错。 POST /es_db/_create/1 { name: 张三, age: 25, sex: 1 }注意POST和PUT都能起到创建和更新的作用PUT在对某一个具体的文档进行操作时需要指定id才能更新/创建而POST可以针对整个文档集合进行操作如果不写id就由ES生成一个唯一id创建新文档如果填了id那就针对这个id的文档进行创建/更新。修改文档修改文档为了修改一个已存在的文档你需要使用POST请求和_updateAPI。修改已存在的文档示例POST/index_name/_doc/1/_update{doc:{field1:new_value}}在这个示例中名为index_name的索引中ID为1的文档的field1字段被更新为new_value。删除文档删除文档你可以使用DELETE请求来删除一个文档。删除文档的示例DELETE/index_name/_doc/1在这个示例中名为index_name的索引中ID为1的文档被删除。批量操作_bulk批量对文档进行写操作是通过_bulk的API来实现的请求方式POST请求地址_bulk请求参数通过_bulk操作文档一般至少有两行参数或偶数行参数第一行参数是指定操作的类型create创建index索引、delete删除、update更新和操作的对象index、type、id第二行参数是操作的数据文档查询简单KV对查询# 通过URL搜索使用“q”指定查询字符串“query string syntax” KV键值对 # 条件查询例如要查询age28的_search?qage:28 GET /es_db/_doc/_search?qage:28 # 范围查询例如要查询年龄在25岁至26岁之间的_search?qage[25 TO 26]注意TO必须是大写 GET /es_db/_doc/_search?qage:[25 TO 26] # 查询年龄小于等于26岁的 GET /es_db/_doc/_search?qage:26 # 查询年龄大于等于26岁的 GET /es_db/_doc/_search?qage:26 # 分页查询fromXXsizeXX GET /es_db/_doc/_search?qage:[25 TO 26]from0size1 # 对查询结果只输出某些字段_source字段1,字段2 GET /es_db/_doc/_search?_sourcename,age # 对查询结果进行排序sort字段:desc/asc GET /es_db/_doc/_search?sortage:descES高级查询Query DSLES提供了一种强大的检索数据方式这种检索方式称之为Query DSLDomain Specified LanguageDSL是使用RESR API传递JSON格式的请求体RequestBody数据与ES进行交互这种方式的丰富语法让ES检索变得更加强大、简洁。语法GET /es_db/_doc/_search {JSON请求体数据} 简化版 GET /es_db/_search {JSON请求体数据}以下是一些DSL的主要功能全文搜索DSL可以用于执行全文搜索查询包括模糊匹配、短语匹配、多字段匹配等。结构化搜索DSL可以用于执行结构化搜索查询包括范围查询、日期查询、地理位置查询等。复合查询DSL可以用于执行复合查询可以将多个查询条件组合起来包括布尔查询、嵌套查询、函数得分查询等。数据聚合DSL可以用于执行数据聚合操作包括统计聚合、范围聚合、日期聚合、地理位置聚合等。排序和分页DSL可以用于执行排序和分页操作可以根据一个或多个字段进行排序也可以进行深度分页。高亮和建议DSL可以用于执行高亮和建议操作可以高亮显示搜索结果中的关键词也可以提供自动完成和拼写检查等建议。脚本计算DSL支持使用脚本进行复杂的计算可以在查询和聚合中使用脚本。实时获取DSL可以用于实时获取文档可以根据文档的ID直接获取文档的内容。以上只是DSL的一部分功能实际上DSL还提供了更多的查询类型和选项可以满足各种复杂的搜索需求。具体的使用方法可以参考Elasticsearch的官方文档。以下是一些Elasticsearch DSL的使用示例全文搜索使用match查询进行全文搜索。GET/my_index/_search{query:{match:{message:this is a test}}}结构化搜索使用range查询进行范围搜索。GET/my_index/_search{query:{range:{age:{gte:10,lte:20}}}}复合查询使用bool查询进行复合搜索。GET/my_index/_search{query:{bool:{must:[{match:{message:this is a test}},{range:{age:{gte:10,lte:20}}}]}}}数据聚合使用terms聚合进行分组统计。GET/my_index/_search{aggs:{group_by_state:{terms:{field:state.keyword}}}}排序和分页使用sort和size进行排序和分页。GET/my_index/_search{query:{match:{message:this is a test}},sort:[{date:desc}],size:10}高亮使用highlight进行高亮显示。GET/my_index/_search{query:{match:{message:this is a test}},highlight:{fields:{message:{}}}}以上只是Elasticsearch DSL的一部分使用示例具体的使用方法可以参考Elasticsearch的官方文档。批量查询_mget和_msearchES的批量查询可以使用mget和msearch两种其中mget是需要知道他的id可以指定不同的index也可以指定返回值source。msearch可以通过字段查询来进行一个批量的查找。_mget# 可以通过ID批量获取不同index和type的数据 GET _mget { docs: [ { _index: es_db, _id: 1 }, { _index: article, _id: 4 } ] } # 可以通过ID批量获取es_db的数据 GET /es_db/_mget { docs: [ { _id: 1 }, { _id: 4 } ] } # 简化后 GET /es_db/_mget { ids: [ 1, 2 ] }_msearch在_msearch中请求格式和_bulk类似查询一条数据需要两个对象第一个设置index和type第二个设置查询语句。查询语句和_search相同。如果只查询一个index可以在URL中带上index这样如果查询index可以直接用空对象表示。查询所有match_all使用match_all默认只返回10条数据。原因_search查询默认采用的是分页查询每页记录数size的默认值是10。如果想要显示更多数据指定size即可。GET /es_db/_search 等同于 GET /es_db/_search { query: { match_all: { } } } GET /es_db/_search { query: { match_all: { } }, size : 20, from : 5 }分页from、to、排序sort在Elasticsearch中sort、from和size参数可以一起使用来实现排序和分页。以下是一个示例它将返回field1字段值为value1的文档结果按照field2字段的值降序排序跳过前10个结果返回接下来的5个结果GET /index_name/_search { query: { match: { field1: value1 } }, sort: [ { field2: desc } ], from: 10, size: 5 }在这个示例中query对象定义了查询条件即field1字段值为value1的文档。sort数组定义了排序规则即按照field2字段的值降序排序。你可以在这个数组中指定多个排序字段。from参数定义了要跳过的结果数量即跳过前10个结果。这个参数的值默认为0。size参数定义了要返回的结果数量即返回接下来的5个结果。这个参数的值默认为10最大值可以在Elasticsearch的配置中设置但不能超过10000。这种方式可以用来实现分页例如你可以在用户请求第二页时将from参数设置为第一页的结果数量将size参数设置为每页的结果数量。关键字查询/精确查询term精确查询Term Query这种查询会对字段值进行精确匹配不进行分词。term用来使用关键字查询精确匹配还可以用来查询没有被进行分词的数据类型。Term是表达语意的最小单位搜索和利用统计语言模型进行自然语言处理都需要处理term。match在匹配时会对锁查询的关键词进行分词然后按粉刺匹配查找而term会直接对关键词进行查找。一般模糊查找的时候多用match而精确查找时可以使用term。ES中默认使用分词器为标准分词器Standard Analyzer标准分词器对于英文单词分词对于中文单字分词。在ES的Mapping type中keyword、date、integer、long、double、boolean、ip这些类型不分词只有text类型会分词。GET /index_name/_search { query: { term: { field1: exact value } } }在ES中term查询对输入不做分词。会将输入作为一个整体在倒排索引中查找准确的词项并且使用相关度算分公式为每个包含该词项的文档进行相关度算分。范围查询range范围查询Range Query这种查询会匹配在指定范围内的字段值。GET /index_name/_search { query: { range: { field1: { gte: start value, lte: end value } } } }多id查询idsGET /index_name/_search { query: { ids: { values: [1,2] } } }模糊查询fuzzy在实际搜索中我们有时候会打错字从而导致查询不到在ES中我们可以使用fuzziness属性来进行模糊查询从而达到搜索中有错别字的情形。fuzzy查询会用到两个很重要的参数fuzziness、prefix_length。fuzziness表示输入的关键字通过几次操作可以转变成ES库里面的对应的field字段。操作是指新增/删除/修改一个字符每次操作可以记做编辑距离为1.入中文集团到中威集团编辑距离就是1只需要修改一个字符。该参数默认值为0即不开启模糊查询。prefix_length表示限制输入关键字和ES对应查询field的内容开头的第n个字符必须完全匹配不允许错别字。如这里1则表示开头的字必须匹配不匹配则不返回。默认值也是0加大prefix_length的值可以提高效率和准确率。GET /index_name/_search { query: { fuzzy: { address : { value : 白云山, fuzziness: 1 } } } }注意fuzzy模糊查询最大模糊错误必须在0-2之间。布尔查询Bool Query这种查询可以组合多个查询条件。GET /index_name/_search { query: { bool: { must: [ { match: { field1: search text } }, { term: { field2: exact value } } ], filter: [ { range: { field3: { gte: start value, lte: end value } } } ] } } }在这些示例中“field1”、field2和field3是字段名你需要将它们替换为你的索引中的实际字段名。高亮查询highlighthighlight关键字可以让符合条件的文档中的关键字高亮。相关属性如下pre_tags前缀标签post_tags后缀标签tags_schema设置为styled可以使用内置高亮央视require_field_match多字段高亮需要设置为false深度分页什么是深度分页在Elasticsearch中通过from和size参数进行分页其中from表示起始结果的偏移size表示返回的结果数量当from size超出index.max_result_window限制时深度分页会导致性能问题因为搜索引擎需要执行大量的数据跳过skipping over data这在内存资源消耗上是昂贵的。注意参数index.max_result_window主要用来限制单次查询满足查询条件的结果窗口的大小窗口大小由from size组成。不能简单理解成查询返回给调用方的数据量主要是为了降低内存消耗。为什么深度分页会造成问题性能下降深度分页需要处理和排除大量数据这会增加查询延时。资源消耗为了找到深处的页面Elasticsearch必须处理很多不必要的数据消耗大量的CPU和内存资源。这是因为Elasticsearch在执行分页查询时需要跳过前面的所有结果。例如如果你请求第10000页每页10条数据Elasticsearch需要跳过前99990条结果。这需要大量的时间和资源尤其是在数据量非常大的情况下。如何解决深度分页问题对于深度分页问题除了修改index.max_result_window强烈不建议这样做之外有几个解决方案可以提高性能并减少资源消耗限制用户可访问的最大页面数在应用逻辑上限制用户可以请求的最大页数。例如不允许用户请求超过100页的数据。这种方法通过减少可访问的结果范围来避免深度分页的问题。滚动搜索Scroll APIScroll API可以在长时间运行的搜索任务中用来检索大量的Elasticsearch文档。这个API可以维持一个稳定的视图并持续返回结果直到不再需要更多数据。它的工作原理是创建一个快照然后在这个快照上迭代这样可以避免深度分页的性能问题。search_after参数提供了一种有效的方式来进行深度分页。这种方法不需要设定from参数而是直接跟在上一页的最后一个结果后。你需要提供上一页最后一个文档的排序键的值作为search_after的输入。Scroll API和Search_afterScroll APIScroll API主要用于处理大规模的数据导出场景它可以获取大量数据比如数百万或数十亿而不需要深度分页。以下是一个基本的使用示例# 初始化scroll查询命令中新增scroll1m说明采用游标查询保持游标查询窗口1分钟 GET /my_index/_search?scroll1m { size: 100, query: { match_all: {} } } # 继续获取数据scroll_id就是上一个请求中返回的scroll_id的值 GET /_search/scroll { scroll: 1m, scroll_id: DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAAAD4WYm9laVYtZndUQlNsdDcwakFMNjU1QQ }在初始化scroll时你需要提供一个scroll参数这个参数定义了在数据变化时保持一致性的时间。然后你可以使用返回的scroll_id来获取下一批数据。Search_after参数Search_after参数可以让你从上一次搜索的最后一个结果开始获取数据这样可以避免深度分页的性能问题。以下是一个基本的使用示例# 获取第一批数据GET /my_index/_search{size:100,query:{match_all:{}},sort:[{date:asc},{tie_breaker_id:asc}]}# 获取下一批数据GET /my_index/_search{size:100,query:{match_all:{}},search_after:[2017-02-10T13:35:00,tie_breaker_id],sort:[{date:asc},{tie_breaker_id:asc}]}在使用search_after参数时你需要提供一个排序条件并且在获取下一批数据时使用上一次返回的最后一个结果的排序值。需要注意的是这两种方法都只适用于获取大量数据的场景如果你需要支持随机访问任意页面的分页查询可能需要考虑其他的解决方案比如使用更强大的硬件、优化查询条件、增加索引等。ES检索原理

更多文章