一起来学ElasticSearch(六)

本文涉及的产品
检索分析服务 Elasticsearch 版,2核4GB开发者规格 1个月
简介: 一起来学ElasticSearch(六)

前言

目前正在出一个Es专题系列教程, 篇幅会较多, 喜欢的话,给个关注❤️ ~


承接上文,把上节剩下的部分给大家整一下, 本节带大家学习一下文档查询API基本操作。


本文偏实战一些,好了, 废话不多说直接开整吧~


查询文档 & 基本操作

为了方便学习, 本节中所有示例沿用上节的索引


按照ID单个

GET class_1/_doc/1
复制代码


查询结果:

{
  "_index" : "class_1",
  "_type" : "_doc",
  "_id" : "1",
  "_version" : 4,
  "_seq_no" : 4,
  "_primary_term" : 3,
  "found" : true,
  "_source" : {
    "name" : "l",
    "num" : 6
  }
}
复制代码


按照ID批量

GET class_1/_mget
{
"ids":[1,2,3]
}
复制代码


返回:

{
  "docs" : [
    {
      "_index" : "class_1",
      "_type" : "_doc",
      "_id" : "1",
      "_version" : 4,
      "_seq_no" : 4,
      "_primary_term" : 3,
      "found" : true,
      "_source" : {
        "name" : "l",
        "num" : 6
      }
    },
    {
      "_index" : "class_1",
      "_type" : "_doc",
      "_id" : "2",
      "found" : false
    },
    {
      "_index" : "class_1",
      "_type" : "_doc",
      "_id" : "3",
      "_version" : 3,
      "_seq_no" : 10,
      "_primary_term" : 4,
      "found" : true,
      "_source" : {
        "num" : 9,
        "name" : "e",
        "age" : 9,
        "desc" : [
          "hhhh"
        ]
      }
    }
  ]
}
复制代码


查询文档是否存在 & 通过id判断

HEAD class_1/_doc/1
复制代码


返回:

200 - OK
复制代码


HEAD class_1/_doc/1000
复制代码


返回:

404 - Not Found
复制代码


查询部分字段内容

GET class_1/_doc/1?_source_includes=name
复制代码


返回:

{
  "_index" : "class_1",
  "_type" : "_doc",
  "_id" : "1",
  "_version" : 4,
  "_seq_no" : 4,
  "_primary_term" : 3,
  "found" : true,
  "_source" : {
    "name" : "l"
  }
}
复制代码

可以看到只返回了name字段, 以上是一个基本的操作,下面给大家讲下条件查询~


查询文档 & 条件查询

查询的复杂度取决于它附加的条件约束,跟我们写sql一样。下面就带大家一步一步看一下ES中如何进行条件查询~


不附加任何条件

GET class_1/_search
复制代码


返回:

{
  "took" : 15,
  "timed_out" : false,
  "_shards" : {
    "total" : 3,
    "successful" : 3,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 8,
      "relation" : "eq"
    },
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "class_1",
        "_type" : "_doc",
        "_id" : "h2Fg-4UBECmbBdQA6VLg",
        "_score" : 1.0,
        "_source" : {
          "name" : "b",
          "num" : 6
        }
      },
      {
        "_index" : "class_1",
        "_type" : "_doc",
        "_id" : "iGFt-4UBECmbBdQAnVJe",
        "_score" : 1.0,
        "_source" : {
          "name" : "g",
          "age" : 8
        }
      },
      {
        "_index" : "class_1",
        "_type" : "_doc",
        "_id" : "iWFt-4UBECmbBdQAnVJg",
        "_score" : 1.0,
        "_source" : {
          "name" : "h",
          "age" : 9
        }
      },
      {
        "_index" : "class_1",
        "_type" : "_doc",
        "_id" : "imFt-4UBECmbBdQAnVJg",
        "_score" : 1.0,
        "_source" : {
          "name" : "i",
          "age" : 10
        }
      },
      {
        "_index" : "class_1",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 1.0,
        "_source" : {
          "num" : 9,
          "name" : "e",
          "age" : 9,
          "desc" : [
            "hhhh"
          ]
        }
      },
      {
        "_index" : "class_1",
        "_type" : "_doc",
        "_id" : "4",
        "_score" : 1.0,
        "_source" : {
          "name" : "f",
          "age" : 10,
          "num" : 10
        }
      },
      {
        "_index" : "class_1",
        "_type" : "_doc",
        "_id" : "RWlfBIUBDuA8yW5cu9wu",
        "_score" : 1.0,
        "_source" : {
          "name" : "一年级",
          "num" : 20
        }
      },
      {
        "_index" : "class_1",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 1.0,
        "_source" : {
          "name" : "l",
          "num" : 6
        }
      }
    ]
  }
}
复制代码


可以看到索引class_1中的所有数据都是上节添加的。这里提一下,我们也可以添加多个索引一起查,然后返回,用,逗号隔开就可以了

GET class_1,class_2,class_3/_search
复制代码


{
  "took" : 7,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 9,
      "relation" : "eq"
    },
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "class_1",
        "_type" : "_doc",
        "_id" : "h2Fg-4UBECmbBdQA6VLg",
        "_score" : 1.0,
        "_source" : {
          "name" : "b",
          "num" : 6
        }
      },
      {
        "_index" : "class_2",
        "_type" : "_doc",
        "_id" : "RWlfBIUBDuA8yW5cu9wu",
        "_score" : 1.0,
        "_source" : {
          "name" : "一年级",
          "num" : 20
        }
      },
      ....
    ]
  }
}
复制代码

可以看到返回了索引class_2中的数据,并且合并到了一起。


相关字段解释

有的小伙伴可能对返回的字段有点陌生,这里给大家统一解释一下:

{
    "took":"查询操作耗时,单位毫秒",
    "timed_out":"是否超时",
    "_shards":{
        "total":"分片总数",
        "successful":"执行成功分片数",
        "skipped":"执行忽略分片数",
        "failed":"执行失败分片数"
    },
    "hits":{
        "total":{
            "value":"条件查询命中数",
            "relation":"计数规则(eq计数准确/gte计数不准确)"
        },
        "max_score":"最大匹配度分值",
        "hits":[
            {
                "_index":"命中结果索引",
                "_id":"命中结果ID",
                "_score":"命中结果分数",
                "_source":"命中结果原文档信息"
            }
        ]
    }
}
复制代码

下面我们看下带条件的查询~


基础分页查询

基本语法: es中通过参数sizefrom来进行基础分页的控制

  • from:指定跳过多少条数据
  • size:指定返回多少条数据


下面看下示例:


url参数

GET class_1/_search?from=2&size=2
复制代码


返回:

{
  "took" : 5,
  "timed_out" : false,
  "_shards" : {
    "total" : 3,
    "successful" : 3,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 8,
      "relation" : "eq"
    },
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "class_1",
        "_type" : "_doc",
        "_id" : "iWFt-4UBECmbBdQAnVJg",
        "_score" : 1.0,
        "_source" : {
          "name" : "h",
          "age" : 9
        }
      },
      {
        "_index" : "class_1",
        "_type" : "_doc",
        "_id" : "imFt-4UBECmbBdQAnVJg",
        "_score" : 1.0,
        "_source" : {
          "name" : "i",
          "age" : 10
        }
      }
    ]
  }
}
复制代码


body 参数

GET class_1/_search
{
    "from" : 2,
    "size" : 2
}
复制代码


返回结果和上面是一样的~


单字段全文索引查询

这个大家应该不陌生,前面几节都见过。使用query.match进行查询,match适用与对单个字段基于全文索引进行数据检索。对于全文字段,match使用特定的分词进行全文检索。而对于那些精确值,match同样可以进行精确匹配,match查询短语时,会对短语进行分词,再针对每个词条进行全文检索

GET class_1/_search
{
  "query": {
    "match": {
      "name":"i"
    }
  }
}
复制代码


返回:

{
  "took" : 4,
  "timed_out" : false,
  "_shards" : {
    "total" : 3,
    "successful" : 3,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 1.3862942,
    "hits" : [
      {
        "_index" : "class_1",
        "_type" : "_doc",
        "_id" : "imFt-4UBECmbBdQAnVJg",
        "_score" : 1.3862942,
        "_source" : {
          "name" : "i",
          "age" : 10
        }
      }
    ]
  }
}
复制代码


单字段不分词查询

使用query.match_phrase进行查询, 它与match的区别就是不进行分词,干说,可能有点抽象,下面我们通过一个例子给大家分清楚:


先造点数据进去:

PUT class_1/_bulk
{ "create":{  } }
{"name":"I eat apple so haochi1~","num": 1}
{ "create":{  } }
{ "name":"I eat apple so zhen haochi2~","num": 1}
{ "create":{  } }
{"name":"I eat apple so haochi3~","num": 1}
复制代码


假设有这么几个句子,现在我有一个需求我要把I eat apple so zhen haochi2~这句话匹配出来


match分词结果

GET class_1/_search
{
  "query": {
    "match": {
      "name": "apple so zhen"
    }
  }
}
复制代码


返回:

{
  "took" : 15,
  "timed_out" : false,
  "_shards" : {
    "total" : 3,
    "successful" : 3,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 3,
      "relation" : "eq"
    },
    "max_score" : 2.2169428,
    "hits" : [
      {
        "_index" : "class_1",
        "_type" : "_doc",
        "_id" : "cMfcCoYB090miyjed7YE",
        "_score" : 2.2169428,
        "_source" : {
          "name" : "I eat apple so zhen haochi2~",
          "num" : 1
        }
      },
      {
        "_index" : "class_1",
        "_type" : "_doc",
        "_id" : "b8fcCoYB090miyjed7YE",
        "_score" : 1.505254,
        "_source" : {
          "name" : "I eat apple so haochi1~",
          "num" : 1
        }
      },
      {
        "_index" : "class_1",
        "_type" : "_doc",
        "_id" : "ccfcCoYB090miyjed7YE",
        "_score" : 1.505254,
        "_source" : {
          "name" : "I eat apple so haochi3~",
          "num" : 1
        }
      }
    ]
  }
}
复制代码


从结果来看,刚刚的几句话都被查出来了,但是结果并大符合预期。从score来看,"_score" : 2.2169428得分最高,排在了第一,语句是I eat apple so zhen haochi2~,说明匹配度最高,这个句子正是我们想要的结果~


match_phrase 不分词查询结果

GET class_1/_search
{
  "query": {
    "match_phrase": {
      "name": "apple so zhen"
    }
  }
}
复制代码


结果:

{
  "took" : 6,
  "timed_out" : false,
  "_shards" : {
    "total" : 3,
    "successful" : 3,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 2.2169428,
    "hits" : [
      {
        "_index" : "class_1",
        "_type" : "_doc",
        "_id" : "cMfcCoYB090miyjed7YE",
        "_score" : 2.2169428,
        "_source" : {
          "name" : "I eat apple so zhen haochi2~",
          "num" : 1
        }
      }
    ]
  }
}
复制代码


结果符合预期,只返回了我们想要的那句。那么match为什么都返回了,这就是前面讲到的分词,首先会对name: apple so zhen进行分词,也就是说存在apple的都会被返回。


当然,真正业务中的需求比这个复杂多了,这里只是为了给大家做区分~ 下面接着看~


多字段全文索引查询

相当于对多个字段执行了match查询, 这里需要注意的是query的类型要和字段类型一致,不然会报类型异常

GET class_1/_search
{
  "query": {
    "multi_match": {
      "query": "apple",
      "fields": ["name","desc"]
    }
  }
}
复制代码


{
  "took" : 5,
  "timed_out" : false,
  "_shards" : {
    "total" : 3,
    "successful" : 3,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 3,
      "relation" : "eq"
    },
    "max_score" : 0.752627,
    "hits" : [
      {
        "_index" : "class_1",
        "_type" : "_doc",
        "_id" : "b8fcCoYB090miyjed7YE",
        "_score" : 0.752627,
        "_source" : {
          "name" : "I eat apple so haochi1~",
          "num" : 1
        }
      },
      {
        "_index" : "class_1",
        "_type" : "_doc",
        "_id" : "ccfcCoYB090miyjed7YE",
        "_score" : 0.752627,
        "_source" : {
          "name" : "I eat apple so haochi3~",
          "num" : 1
        }
      },
      {
        "_index" : "class_1",
        "_type" : "_doc",
        "_id" : "cMfcCoYB090miyjed7YE",
        "_score" : 0.7389809,
        "_source" : {
          "name" : "I eat apple so zhen haochi2~",
          "num" : 1
        }
      }
    ]
  }
}
复制代码


范围查询

使用range来进行范围查询,适用于数组时间等字段

GET class_1/_search
{
  "query": {
    "range": {
      "num": {
        "gt": 5,
        "lt": 10
      }
    }
  }
}
复制代码


返回:

{
  "took" : 6,
  "timed_out" : false,
  "_shards" : {
    "total" : 3,
    "successful" : 3,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 3,
      "relation" : "eq"
    },
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "class_1",
        "_type" : "_doc",
        "_id" : "h2Fg-4UBECmbBdQA6VLg",
        "_score" : 1.0,
        "_source" : {
          "name" : "b",
          "num" : 6
        }
      },
      {
        "_index" : "class_1",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 1.0,
        "_source" : {
          "num" : 9,
          "name" : "e",
          "age" : 9,
          "desc" : [
            "hhhh"
          ]
        }
      },
      {
        "_index" : "class_1",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 1.0,
        "_source" : {
          "name" : "l",
          "num" : 6
        }
      }
    ]
  }
}
复制代码


单字段精确查询

使用term进行非分词字段的精确查询。需要注意的是,对于那些分词的字段,即使查询的value是一个完全匹配的短语,也无法完成查询

GET class_1/_search
{
 "query": {
   "term": {
     "num": {
       "value": "9"
     }
   }
 }
}
复制代码


返回:

{
  "took" : 4,
  "timed_out" : false,
  "_shards" : {
    "total" : 3,
    "successful" : 3,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "class_1",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 1.0,
        "_source" : {
          "num" : 9,
          "name" : "e",
          "age" : 9,
          "desc" : [
            "hhhh"
          ]
        }
      }
    ]
  }
}
复制代码


字段精确查询 & 多值

与term一样, 区别在于可以匹配一个字段的多个值,满足一个即检索成功

GET class_1/_search
{
 "query": {
   "terms": {
     "num": [
      9,
      1
     ]
   }
 }
}
复制代码


返回:

{
  "took" : 8,
  "timed_out" : false,
  "_shards" : {
    "total" : 3,
    "successful" : 3,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 4,
      "relation" : "eq"
    },
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "class_1",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 1.0,
        "_source" : {
          "num" : 9,
          "name" : "e",
          "age" : 9,
          "desc" : [
            "hhhh"
          ]
        }
      },
      {
        "_index" : "class_1",
        "_type" : "_doc",
        "_id" : "b8fcCoYB090miyjed7YE",
        "_score" : 1.0,
        "_source" : {
          "name" : "I eat apple so haochi1~",
          "num" : 1
        }
      },
      {
        "_index" : "class_1",
        "_type" : "_doc",
        "_id" : "ccfcCoYB090miyjed7YE",
        "_score" : 1.0,
        "_source" : {
          "name" : "I eat apple so haochi3~",
          "num" : 1
        }
      },
      {
        "_index" : "class_1",
        "_type" : "_doc",
        "_id" : "cMfcCoYB090miyjed7YE",
        "_score" : 1.0,
        "_source" : {
          "name" : "I eat apple so zhen haochi2~",
          "num" : 1
        }
      }
    ]
  }
}
复制代码


文档包含字段查询

为了确定当前索引有哪些文档包含了对应的字段,es中使用exists来实现

GET class_1/_search
{
  "query": {
    "exists": {
      "field": "desc"
    }
  }
}
复制代码


返回:

{
  "took" : 8,
  "timed_out" : false,
  "_shards" : {
    "total" : 3,
    "successful" : 3,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "class_1",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 1.0,
        "_source" : {
          "num" : 9,
          "name" : "e",
          "age" : 9,
          "desc" : [
            "hhhh"
          ]
        }
      }
    ]
  }
}
复制代码


结束语

本节主要讲了ES中的文档查询API操作,该部分内容较多, 下节继续给大家讲,就先消化这么多~API大家都不要去背,多敲几遍就记住了,关键是多用,多总结 。

相关实践学习
使用阿里云Elasticsearch体验信息检索加速
通过创建登录阿里云Elasticsearch集群,使用DataWorks将MySQL数据同步至Elasticsearch,体验多条件检索效果,简单展示数据同步和信息检索加速的过程和操作。
ElasticSearch 入门精讲
ElasticSearch是一个开源的、基于Lucene的、分布式、高扩展、高实时的搜索与数据分析引擎。根据DB-Engines的排名显示,Elasticsearch是最受欢迎的企业搜索引擎,其次是Apache Solr(也是基于Lucene)。 ElasticSearch的实现原理主要分为以下几个步骤: 用户将数据提交到Elastic Search 数据库中 通过分词控制器去将对应的语句分词,将其权重和分词结果一并存入数据 当用户搜索数据时候,再根据权重将结果排名、打分 将返回结果呈现给用户 Elasticsearch可以用于搜索各种文档。它提供可扩展的搜索,具有接近实时的搜索,并支持多租户。
相关文章
|
6月前
|
自然语言处理 网络架构 索引
Elasticsearch7.1之cerebro使用(一)
Elasticsearch7.1之cerebro使用(一)
80 1
|
7月前
|
自然语言处理 Java 网络安全
ElasticSearch
ElasticSearch
80 2
|
7月前
|
搜索推荐 关系型数据库 MySQL
【Elasticsearch】初识elasticsearch
【Elasticsearch】初识elasticsearch
74 1
|
7月前
|
存储 JSON 监控
Elasticsearch简单讲解
Elasticsearch简单讲解
79 0
|
存储 关系型数据库 MySQL
Elasticsearch(二)
Elasticsearch(二)
64 0
|
自然语言处理 索引
Elasticsearch(三)
Elasticsearch(三)
72 0
|
存储 Java 关系型数据库
一起来学ElasticSearch(九)
前言 目前正在出一个Es专题系列教程, 篇幅会较多, 喜欢的话,给个关注❤️ ~ 本节给大家讲下es中如何做聚合操作, 内容有点多,需要耐心看完~ 本文偏实战一些,好了, 废话不多说直接开整吧~ 什么是聚合 聚合的概念有点类似mysql中group by,sum(...),这么说大家可能就有点印象了, 但是在es中聚合操作功能更强大。 在了解es中聚合的概念之前,先来看下这两个概念, 聚合就是一个或多个桶和零个或多个指标的组合。
|
Java API 索引
还不会ElasticSearch?一文搞定
本文讲解Java操作ElasticSearch
179 1