ES基础知识总结含SQL、DSL、GOLANG

news2024/11/22 17:39:11

在这里插入图片描述

一、简介

Elasticsearch是一个基于Lucene的全文搜索和分析引擎,Lucene Core是一个完全用Java编写的高性能、全功能搜索引擎库。

它可以快速地存储、实时搜索和分析大量数据。

它可以扩展到上百台服务器,处理PB级数据。PB = 2^50 Byte, 在数值上约等于1000个TB。 人类功能记忆容量约1.25TB, 也意味着800个人类记忆相当于1PB。

二、认知

1、Lucene

Lucene,封装好了各种建立倒排索引、匹配索引进行搜索的各种算法。我们可以引入Lucene,基于它的API进行开发。

ElasticSearch就在Lucene的基础上实现的,对Lucene进行了良好的封装,简化开发,并提供了很多高级功能

ElasticSearch生态

ElasticSearch 为快速检索和分析大数据而生,目前已形成丰富的生态。在这里插入图片描述

成熟的ELK体系:

  • Elasticsearch: 位于Elastic堆栈核心的分布式搜索和分析引擎
  • Logstash + Beats:收集、聚合、丰富数据,存储到Elasticsearch中
  • Kibana: 以交互方式探索、可视化、共享对数据的见解,并管理和监视堆栈

2、倒排索引

索引:通过key来寻找value。与之相反,就是倒排索引

Elasticsearch使用倒排索引的结构,适用于快速的全文搜索。一个倒排索引由文档中所有不重复词的列表构成,对于其中每个词,有一个包含它的文档列表。

正排索引: 书的目录
倒排索引: 词典中单词的索引页

查询包含“关键搜索”的文档的过程

  1. 通过倒排索引获得“关键搜索”对应的文档id列表
  2. 通过正排索引查询文档id列表的完整内容
  3. 返回最终结果

For instance

Doc 1 : no your po no your work

Doc 2 : enjoy your team work

Doc 3 : enjoy challenge with your team

为了创建索引,ES引擎通过分词器将每个文件的内容拆成单独的词(词条/term),再将这些词条创建成不含重复词条的排序列表,然后列出每个词条出现在哪个文档:

termDoc 1Doc 2Doc 3
no
po
work
enjoy
your
team
With
challenge

在这里插入图片描述

这种结构由文档中所有不重复的词的列表构成,对于其中每个词都有至少一个文档与之关联。这种由属性值来确定记录的位置的结构就是倒排索引,带有倒排索引的文件被称为倒排文件

核心概念:

  • 词条(term):索引中最小的存储和查询单元。
  • 词典(Term Dictionary):字典,是词条的组合。
  • 倒排表(Post list)
    • 一个文档通常由多个词组成,倒排表记录了某个词在那些文档出现过以及出现的位置。
    • 每条记录称为一个倒排项(Posting)。
    • 记录了文档编号、词频等信息。
  • 倒排文件(Inverted File)
    • 所有单词的倒排列表按顺序存储在磁盘的某个文件中,即为倒排文件
    • 词典在内存中; 倒排文件在磁盘中

3、基本概念

  • field
    • 字段, (类似Mysql中的一个字段)
  • Document
    • 文档,一条数据,用json格式表示
    • 一个Document包含多个field, json中的key即field
  • Type
    • 类型,一个Document分组,(类似于Mysql中的table)
    • 一个Type包含多个Document,同一个Type中的Document所拥有的field可以不同,但最好保持一致
  • Index
    • 索引,(类似Mysql中的database)
    • 一个Index包含多个Type。
    • 默认情况下,Document中所有的field都会被索引,这些field才会被搜索到
  • shard
    • 分片
    • 可以将一个Index中的数据切分为多个shard,然后存储到多台服务器上,以增大一个Index可以存储的数据量,加速检索能力,提升系统性能
  • replica
    • 副本
    • 与shard存储的数据是相同的,起到备份作用
    • 当shard发生故障时,可以从replica中读取数据,保证系统不受影响
  • Node
    • 节点
    • 单个Elasticsearch实例,一台机器可以有多个节点
    • 节点名称默认随机分配
  • Cluster
    • 集群
    • 一组Elasticsearch实例
    • 默认集群名称为 elasticsearch
Elasticsearch名称ElasticSearch概念数据库
Index索引
Type类型
Document文档
field字段

Document文档

Json Object,由字段(field)组成
每个文档有一个唯一id标志

  • 自行指定
  • es生成

Document MetaData 元数据,用于标注文档的相关信息

  • _index: 文档所在的索引名
  • _type: 文档所在的类型名
  • _id: 文档唯一id
  • uid: 组合id, 由type和id组成
  • _source: 文档的原始json数据,可从这里获取每个字段的内容
  • _all: 整合所有字段内容到该字段,默认禁用

数据类型

  • 核心数据类型
    • 字符串类型:text、keyword
    • 数值类型: long、integer、short、byte、double、float、half_float、scaled_float
    • 日期类型: date
    • 布尔类型: boolean
    • 二进制类型: binary
    • 范围类型: integer_range、float_range、long_range、double_range、date_range
  • 复杂数据类型
    • 数组类型: array
    • 对象类型: object
    • 嵌套类型: nested object
  • 地理位置数据类型
    • geo_point
    • geo_shape
  • 专用类型
    • 记录ip地址: ip
    • 实现自动补全: completion
    • 记录分词数:token_count
    • 记录字符串hash值: murmur3

三、es与kibana安装


version: '3.1'
services:
  elasticsearch:
    image: elasticsearch:7.13.3
    container_name: elasticsearch
    privileged: true
    environment:
      - "cluster.name=elasticsearch" #设置集群名称为elasticsearch
      - "discovery.type=single-node" #以单一节点模式启动
      - "ES_JAVA_OPTS=-Xms512m -Xmx1096m" #设置使用jvm内存大小
      - bootstrap.memory_lock=true
    volumes:
      - ./es/plugins:/usr/local/dockercompose/elasticsearch/plugins #插件文件挂载
      - ./es/data:/usr/local/dockercompose/elasticsearch/data:rw #数据文件挂载
      - ./es/logs:/usr/local/dockercompose/elasticsearch/logs:rw
    ports:
      - 9200:9200
      - 9300:9300
    deploy:
     resources:
        limits:
           cpus: "2"
           memory: 1000M
        reservations:
           memory: 200M
  kibana:
    image: kibana:7.13.3
    container_name: kibana
    depends_on:
      - elasticsearch #kibana在elasticsearch启动之后再启动
    environment:
      ELASTICSEARCH_HOSTS: http://elasticsearch:9200 #设置访问elasticsearch的地址
      I18N_LOCALE: zh-CN
    ports:
      - 5601:5601

将上述代码写入docker-compose.yml ,后运行即可拉起es、kibana服务:

docker-compose up -d

访问kibana主页: http://localhost:5601/app/home#/

四、kibana对elasticsearch管理

kibana中的Dev Tools开发者工具可以对es数据进行CRUD管理

method方法url地址描述
PUT/索引名称/类型名称/文档id创建文档(指定id)
POST/索引名称/类型名称创建文档(随机id)
POST/索引名称/类型名称/文档id/_update修改文档
DELETE/索引名称/类型名称/文档id删除文档
GET/索引名称/类型名称/文档id通过id查询文档
POST/索引名称/类型名称/_search查询所有数据

PUT /tool_index/
{
  "settings": {
    "index": {
      "number_of_shards":10,  
      "number_of_replicas":0
    }
  }
}

GET /tool_index/_settings

PUT /tool_index/tools/20230326214500
{
  "name": "ijie",
  "age": 22,
  "grade": 1,
  "hobby": "coding"
}

POST /tool_index/_doc
{
  "name": "erran_new",
  "age": 24,
  "grade": 2,
  "hobby": "code"
}

GET /tool_index/tools/_search

GET /tool_index/tools/_search?q=name:erran

GET /tool_index/tools/_search 
{
  "query": {
    "match": {
      "name.keyword": "erran"
    }
  }
  "_source": ["name", "grade"]
}

POST /tool_index/tools/20230326213100/_update
{
  "doc": {
    "grade": 3
  }
}

PUT /tool_index/tools/20230326214500
{
  "people": "ijie"
}

DELETE /tool_index/tools/20230326214500

DELETE tool_index

⚠️⚠️⚠️:

  • 创建索引后,插入的第一个数据的类型至关重要,如果指定为特殊类型,则后续插入的默认类型会变成该指定特殊类型;后续插入的其他特殊类型会报错!!【Rejecting mapping update to [tool_index] as the final mapping would have more than 1 type: [tools, demo】
  • 更新时
    • PUT操作,写几个字段便会将数据更新为几个字段
    • POST操作, 只修改指定字段的值
  • 字段匹配时,使用’field’ 或’field.keyword’皆可
  • 在devcloud部署时,会存在高危服务内网风险,解决方案:【增加访问控制措施】
    • iptables限制访问来源
    • nginx: server {listen 9200 default_server;server_name _;location / {proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_pass http://localhost:9200;#Basic字符串就是使用你的用户名(admin),密码(12345)编码后的值#注意:在进行Basic加密的时候要使用如下格式如:admin:123456的base64编码 注意中间有个冒号proxy_set_header Authorization "Basic 这里是basic认证的密码";}}
    • 通过es的Search Guard插件来设置api Basic鉴权:https://docs.search-guard.com/latest/http-basic-authorization

五、查询场景

在这里插入图片描述

测试数据:

  • 索引:person
  • 类型:_doc
nameagesexgradehobbyWeight
John242code
Alis241movie
Jack221code
Rookie234readsixty kilo grams
Jam253eatfifty-kilo-grams

下面使用github中Olivere框架,其封装了若干查询方法,简单上手

语句查询

词条查询

单值查询-term

即筛选出一个字段等于特定值的所有记录

SQL:

select * from person where name = 'Rookie';

ES:

GET /person/_search
{
  "query": {
    "term": {
      "name": "Rookie"
    }
  }
}

ES查询结果(取hits.hits[]):

      {
        "_index" : "person",
        "_type" : "_doc",
        "_id" : "rIpjQYcBtP47ROwdblh9",
        "_score" : 0.2876821,
        "_source" : {
          "name" : "Rookie",
          "age" : 23,
          "sex" : "男",
          "grade" : 4,
          "hobby" : "read"
        }
      }

Golang:

	client, err := elastic.NewClient(elastic.SetURL("http://xxxx:9200"),
		elastic.SetSniff(false),
		elastic.SetHealthcheck(false),
		elastic.SetBasicAuth("username", "password"))
	if err != nil {
		fmt.Println(err)
		return
	}
	q := elastic.NewTermQuery("name", "Rookie")
	req, err := client.Search().
		Index("person").
		Query(q).
		Do(context.Background())
	if err != nil {
		fmt.Println(err)
		return
	}
	for _, v := range req.Hits.Hits {
		var tmp interface{}
		_ = json.Unmarshal(v.Source, &tmp)
		fmt.Println(tmp)
	}

结果:

在这里插入图片描述

多值查询-terms

类似于IN查询

SQL:

select * from persons where age in(23, 24);

ES:

GET /person/_search
{
  "query": {
    "terms": {
      "age": [23,24]
    }
  }
}

ES结果:

      {
        "_index" : "person",
        "_type" : "_doc",
        "_id" : "rIpjQYcBtP47ROwdblh9",
        "_score" : 1.0,
        "_source" : {
          "name" : "Rookie",
          "age" : 23,
          "sex" : "男",
          "grade" : 4,
          "hobby" : "read"
        }
      },
      {
        "_index" : "person",
        "_type" : "_doc",
        "_id" : "n4phQYcBtP47ROwd1Vha",
        "_score" : 1.0,
        "_source" : {
          "name" : "Alis",
          "age" : 24,
          "sex" : "女",
          "grade" : 1,
          "hobby" : "movie"
        }
      },
      {
        "_index" : "person",
        "_type" : "_doc",
        "_id" : "vIlfQYcBzqYw9eGTVRry",
        "_score" : 1.0,
        "_source" : {
          "name" : "John",
          "age" : 24,
          "sex" : "男",
          "grade" : 2,
          "hobby" : "code"
        }
      }

Golang:

	q := elastic.NewTermsQuery("age", 23, 24)
	req, err := client.Search().
		Index("person").
		Query(q).
		Do(context.Background())

结果:

在这里插入图片描述

范围查询-range

即查询某字段在特定区间的记录

SQL:

select * from pesons where age between 21 and 23;

ES:

GET /person/_search
{
  "query": {
    "range": {
      "age": {
        "gte": 21,
        "lte": 23
      }
    }
  }
}

ES结果:

      {
        "_index" : "person",
        "_type" : "_doc",
        "_id" : "rIpjQYcBtP47ROwdblh9",
        "_score" : 1.0,
        "_source" : {
          "name" : "Rookie",
          "age" : 23,
          "sex" : "男",
          "grade" : 4,
          "hobby" : "read"
        }
      },
      {
        "_index" : "person",
        "_type" : "_doc",
        "_id" : "DYliQYcBzqYw9eGTqht2",
        "_score" : 1.0,
        "_source" : {
          "name" : "Jack",
          "age" : 22,
          "sex" : "男",
          "grade" : 1,
          "hobby" : "code"
        }
      }

Golang:

	q := elastic.NewRangeQuery("age").Gte(21).Lte(23)
	req, err := client.Search().
		Index("person").
		Query(q).
		Do(context.Background())

结果:

在这里插入图片描述

通配符查询-wildcard

与前缀查询类似,都属于模糊查询的范畴,但通配符显然功能更强

SQL:

select * from persons where hobby like '%o%';

ES:

GET /person/_search
{
  "query": {
    "wildcard": {
      "hobby": "*o*"
    }
  }
}

ES结果:

      {
        "_index" : "person",
        "_type" : "_doc",
        "_id" : "n4phQYcBtP47ROwd1Vha",
        "_score" : 1.0,
        "_source" : {
          "name" : "Alis",
          "age" : 24,
          "sex" : "女",
          "grade" : 1,
          "hobby" : "movie"
        }
      },
      {
        "_index" : "person",
        "_type" : "_doc",
        "_id" : "vIlfQYcBzqYw9eGTVRry",
        "_score" : 1.0,
        "_source" : {
          "name" : "John",
          "age" : 24,
          "sex" : "男",
          "grade" : 2,
          "hobby" : "code"
        }
      },
      {
        "_index" : "person",
        "_type" : "_doc",
        "_id" : "DYliQYcBzqYw9eGTqht2",
        "_score" : 1.0,
        "_source" : {
          "name" : "Jack",
          "age" : 22,
          "sex" : "男",
          "grade" : 1,
          "hobby" : "code"
        }
      }

Golang:

q := elastic.NewWildcardQuery("hobby", "*o*")
	req, err := client.Search().
		Index("person").
		Query(q).
		Do(context.Background())

结果:

在这里插入图片描述

匹配查询

Match query, 返回与提供的文本、数字、日期或布尔值匹配的文档,并在匹配之前分析提供的文本。

match 查询是执行全文搜索的标准查询,包括模糊匹配的选项。

以匹配weight=“fifty-kilo-grams”为例:

GET /person/_search
{
  "query": {
    "match": {
      "weight": {
        "query": "fifty-kilo-grams"
      }
    }
  }
}

match 用到的参数

  • query(必填)
    • 需要查找的text、number、boolean、date等
  • analyzer(可选,字符串)
    • 可用于将query值中的text转换为tokens。
    • 默认为
    • 如果没有映射分析器,则使用索引的默认分析器
  • auto_generate_synonyms_phrase_query(可选,布尔值)
    • 默认为true,自动为muti-term synonyms创建match phrase
  • fuzziness(可选,字符串)
    • 允许匹配的最大编辑距离
  • max_expansions(可选,整数)
    • 查询将terms最大数值,默认为50
  • prefix_length(可选,整数)
    • fuzzy match模糊匹配保留不变的起始字符,默认为0
  • fuzzy_transpositions(可选,布尔值)
    • 默认为true,模糊匹配包括两个相邻字符的换位(ab->ba)
  • fuzzy_rewrite(可选,字符串)
    • 用于重写查询的方法
    • 若fuzziness != 0, 则查询默认使用fuzzy_write方法。top_terms_blended_freqs_${max_expansions}
  • lenient(可选,布尔值)
    • 默认为false, 若为true,则忽略格式错误,例如为text字段提供number类型
  • operator(可选,字符串)
    • 用于查询中的布尔逻辑,有效值为OR(默认)AND
  • minimum_should_match(可选,字符串)
    • 要返回的文档必须匹配的最小子句数
  • zero_terms_query(可选,字符串)
    • 当analyzer删除索引tokens时(例如使用stopfilter),是否不返回任何结果
    • 有效值为none(默认)all

简单查询可以简化匹配语法:

GET /person/_search
{
  "query": {
    "match": {
      "weight": "fifty-kilo-grams"
    }
  }
}

模糊匹配:

可以使用fuzziness来模糊匹配字段, "AUTO"会根据词项的长度来产生可编辑距离,默认值是AUTO:3,6

  • 0…2

    单词长度为 0 到 2 之间时必须要精确匹配,这其实很好理解,单词长度太短是没有相似度可言的,例如 ‘a’ 和 ‘b’

  • 3…5

​ 单词长度 3 到 5 个字母时,最大编辑距离为 1

  • >5

​ 单词长度大于 5 个字母时,最大编辑距离为 2

可以使用prefix_lengthmax_expansions来控制模糊过程

可以使用fuzzy_rewrite来允许控制查询将如何被重写

可以使用fuzzy_transpositions来控制是否允许模糊换位(ab->ba)

GET /person/_search
{
  "query": {
    "match": {
      "weight": {
        "query": "2fifty-kilo-grams1",
        "fuzziness": "AUTO"
      }
    }
  }
}

关于text、keyword

首先查看索引下的proporties:

GET /person/_mapping

"properties" : {
  "age" : {
    "type" : "long"
  },
  "grade" : {
    "type" : "long"
  },
  "hobby" : {
    "type" : "keyword"
  },
  "name" : {
    "type" : "keyword"
  },
  "sex" : {
    "type" : "keyword"
  },
  "weight" : {
    "type" : "keyword"
  }
}

新建一个text类型的new_field,并设置new_field.keyword为keyword类型

PUT /person/_mapping
{
  "properties": {
    "new_field": {
      "type": "text",
      "fields": {
        "keyword": {
          "type": "keyword",
          "ignore_above": 256
        }
      }
    }
  }
}

给Rookie添加属性:

POST /person/_doc/rIpjQYcBtP47ROwdblh9
{
  "name": "Rookie",
  "age": 23,
  "sex": "男",
  "grade": 4,
  "hobby": "read",
  "weight": "sixty kilogram",
  "new_field": "sixty kilo grams, sixty kilogram, 60 千克"
}
POST /person/_doc/vYplQYcBtP47ROwdc1gz
{
  "name": "Jam",
  "age": 25,
  "sex": "女",
  "grade": 3,
  "hobby": "eat",
  "weight": "fifty-kilo-grams",
  "new_field": "60"
}

在这里插入图片描述

之后进行相关的text、keyword查询:

term——match——match_phrase

match_phrase_prefix(只用于text)

match_all(固定用法: "match_all": {}) 查询所有

使用analyze查看分词

GET /person/_analyze
{
  "text":"sixty kilo grams, sixty kilogram, 60 千克"
}

keyword: 只支持完整内容

texttermmatchmatch_phrase
分词器分词
分词器多个分词
完整内容
中文短语

match与match_phrase的区别:

  • match返回匹配到的所有文档
  • match_phrase返回顺序一致的、匹配到的所有文档

For instance

{ "id" : 1,"content":"关注我,系统学编程" }
{ "id" : 2,"content":"系统学编程,关注我" }
{ "id" : 3,"content":"系统编程,关注我" }
{ "id" : 4,"content":"关注我,间隔系统学编程" }

查询 关注我,系统学

  • match返回所有文档,因为使用“ik_smart”分词后,Token【关注、我、系统学】,包含Token即返回
  • match_phrase只返回id=1,包含Token且顺序一致
  • match_phrase添加slop参数——Token之间的位置距离容差值, id=4的Token【关注、我、间隔、系统学】,因此若添加slop=1,则返回文档1、文档4
q := elastic.NewMatchQuery("new_field", "60").Operator("and")
	//map[age:23 grade:4 hobby:read name:Rookie new_field:sixty kilo grams, sixty kilogram, 60 千克 sex:男 weight:sixty kilogram, 60kg,千克]
q2 := elastic.NewMatchPhraseQuery("new_field", "千克")
	//map[age:25 grade:3 hobby:eat name:Jam new_field:60 sex:女 weight:fifty-kilo-grams]
	//map[age:23 grade:4 hobby:read name:Rookie new_field:sixty kilo grams, sixty kilogram, 60 千克 sex:男 weight:sixty kilogram, 60kg,千克]

type MatchQuery struct {
	name                string    		// key
	text                interface{}		// value
  operator            string 				// or(默认)/and 使用and时,需要查询字段包含query中的所有分词
	analyzer            string
	boost               *float64			// 权重
  fuzziness           string				// AUTO(默认) 可编辑最大距离
	prefixLength        *int					// 未模糊的初始字符数
	maxExpansions       *int					// 结果返回term的数量限制
	minimumShouldMatch  string
	fuzzyRewrite        string
	lenient             *bool					// 忽略数据类型不匹配
	fuzzyTranspositions *bool
  zeroTermsQuery      string				// none(默认)/all 使用all时 忽略analyzer限制,效果与match_all相似
  cutoffFrequency     *float64			// 分数(0.02)表示频率,正整数(3)表示出现次数 
	queryName           string
}

type MatchPhraseQuery struct {
	name           string							// key
	value          interface{}				// value
	analyzer       string
	slop           *int								//分词词项最大移动次数
	boost          *float64
	queryName      string
	zeroTermsQuery string
}


GET /person/_search
{
  "query": {
    "multi_match": {
      "query": "sixty 60",
      "fields": ["weight", "new_field"]
    }
  }
}

GET /person/_search
{
  "query": {
    "dis_max": {
      "queries": [
        { "match": { "weight": "sixty 60" }},
        { "match": { "new_field": "sixty 60" }}
      ]
    }
  }
}

Multi-match query

the multi_match builds on the match query to allow multi-field queries

先来看multi_match的type参数,内部执行查询的方式取决于type:

  • best_fields:(默认)查找匹配任意field的文档,并根据_score来使用最佳field
  • most_fields:查找匹配任意field的文档并结合每个字段的_score
  • cross_fields:将field视为analyzer的一个大的field,在任意field中查找每一个单词
  • phrase:使用match_phrase查询每一个field并根据_score来使用最佳field
  • phrase_prefix:使用match_phrase_prefix查询每一个field并根据_score来使用最佳field
  • bool_prefix:创建match_bool_prefix查询每一个field并结合每个field的_score
q := elastic.NewMultiMatchQuery("sixty 60", "weight", "new_field").Operator("and")
// map[age:23 grade:4 hobby:read name:Rookie new_field:sixty kilo grams, sixty kilogram, 60 千克 sex:男 weight:sixty kilogram, 60kg,千克]
q := elastic.NewMultiMatchQuery("sixty 60", "weight", "new_field")
// map[age:23 grade:4 hobby:read name:Rookie new_field:sixty kilo grams, sixty kilogram, 60 千克 sex:男 weight:sixty kilogram, 60kg,千克]
// map[age:25 grade:3 hobby:eat name:Jam new_field:60 sex:女 weight:fifty-kilo-grams]

复合查询

实际应用中,需要过滤多个值/字段,这样的多条件等值查询,则需要使用组合过滤器

SELECT * FROM person WHERE sex='女' AND age>=23;
GET /person/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "term": {
            "sex": {
              "value": "女"
            }
          }
        },
        {
          "range": {
            "age": {
              "gte": 23
            }
          }
        }
      ]
    }
  }
}

golang:

query1 := elastic.NewTermQuery("sex", "女")
	query2 := elastic.NewRangeQuery("age").Gte(23)
	q := elastic.NewBoolQuery().Must(query1, query2)
// map[age:25 grade:3 hobby:eat name:Jam new_field:60 sex:女 weight:fifty-kilo-grams]
// map[age:24 grade:1 hobby:movie name:Alis sex:女]

布尔过滤器(bool filter)属于复合过滤器(compound filter)的一种,可以接受多个其他的过滤器作为参数,并将这些过滤器结合成各种布尔逻辑组合

Bool query

// Creates a new bool query.
func NewBoolQuery() *BoolQuery {
	return &BoolQuery{
		mustClauses:    make([]Query, 0),
		mustNotClauses: make([]Query, 0),
		filterClauses:  make([]Query, 0),
		shouldClauses:  make([]Query, 0),
	}
}
  • must: 所有的语句都必须匹配,与 ‘=’ 等价
  • must_not: 所有的语句都不能匹配,与 ‘!=’ 或 not in 等价
  • should: 至少有n个语句要匹配,n由参数控制(在olivere框架中会自动匹配个数,已封装好)
  • filter: 子句查询忽略评分、考虑缓存
    • 主要快在两个方面:对结果进行缓存;避免了计算分值
select *from persons
where 
	sex = '男'
and
	age between 22 and 25
and 
	grade != 1
and 
	(hobby = 'code' OR weight = 'sixty kilogram, 60kg,千克')
GET /person/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "term": {
            "sex": {
              "value": "男"
            }
          }
        },
        {
          "range": {
            "age": {
              "gte": 22,
              "lte": 25
            }
          }
        }
      ],
      "must_not": [
        {
          "match": {
            "grade": 1
          }
        }
      ],
      "should": [
        {
          "match": {
            "hobby": "code"
          }
        },
        {
          "match_phrase": {
            "weight": "sixty kilogram"
          }
        },
        {
          "match_phrase": {
            "weight": "60kg"
          }
        },
        {
          "match_phrase": {
            "weight": "千克"
          }
        }
      ]
    }
  }
}

使用filter加速

	query1 := elastic.NewTermQuery("sex", "男")
	query2 := elastic.NewRangeQuery("age").Gte(23).Lte(25)
	query3 := elastic.NewMatchQuery("grade", 1)
	query4 := elastic.NewMatchQuery("hobby", "code")
	query5 := elastic.NewMatchPhraseQuery("weight", "sixty kilogram")
	query6 := elastic.NewMatchPhraseQuery("weight", "60kg")
	query7 := elastic.NewMatchPhraseQuery("weight", "千克")
	query := elastic.NewBoolQuery().
		Must(query1, query2).
		MustNot(query3).
		Should(query4, query5, query6, query7)
	q := elastic.NewBoolQuery().Filter(query)

聚合查询

统计

查询最大、最小、平均年龄

GET /person/_search
{
  "aggs": {
    "max_age": {
      "max": {
        "field": "age"
      }
    },
    "min_age": {
      "min": {
        "field": "age"
      }
    },
    "avg_age": {
      "avg": {
        "field": "age"
      }
    }
  }
}
  aggs := elastic.NewMaxAggregation().Field("age")
	q := elastic.NewMatchAllQuery()
	req, err := client.Search().
		Index("person").
		Query(q).
		Aggregation("max_age", aggs).
		Do(context.Background())
// 结果在req.Aggregations中 
// 调用Aggregations对象的方法来获取想要的聚合结果
  aggResult, _ := req.Aggregations.Max("max_age")
	maxAge := *aggResult.Value
	fmt.Printf("Max age: %d\n", int(maxAge))
// Max age: 25

在这里插入图片描述

去重查询

查询一共多少种爱好

GET /person/_search
{
  "aggs": {
    "hobby_count": {
      "cardinality": {
        "field": "hobby"
      }
    }
  }
}
	aggs := elastic.NewCardinalityAggregation().Field("hobby")
	q := elastic.NewMatchAllQuery()
	req, err := client.Search().
		Index("person").
		Query(q).
		Aggregation("hobby_count", aggs).
		Do(context.Background())
//hobby count : 4

分组

查询每个性别的人数

GET /person/_search
{
  "aggs": {
    "count": {
      "terms": {
        "field": "sex",
        "size": 10
      }
    }
  }
}
//   "aggregations" : {
//    "count" : {
//      "doc_count_error_upper_bound" : 0,
//      "sum_other_doc_count" : 0,
//      "buckets" : [
//        {
//          "key" : "男",
//         "doc_count" : 3
//        },
//        {
//          "key" : "女",
//         "doc_count" : 2
//        }
//      ]
//    }
//  }
  aggs := elastic.NewTermsAggregation().Field("sex")
	q := elastic.NewMatchAllQuery()
	req, err := client.Search().
		Index("person").
		Query(q).
		Aggregation("count", aggs).
		Do(context.Background())
  aggResult, _ := req.Aggregations.Terms("count")
	for _, v := range aggResult.Buckets {
		fmt.Printf("%v--%d\n", v.Key, v.DocCount)
	}
//男--3
//女--2

Warning⚠️:Elasticsearch 不支持对 text 类型的字段进行聚合操作。

  • text 类型的字段被分词器处理成了多个词项(terms)
  • 聚合操作需要对每个文档的每个词项进行处理,这样会导致性能问题和内存消耗

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

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

相关文章

联通数科面试准备

Spring中Bean的生命周期 Spring Bean的生命周期全过程分为5个阶段,创建前准备阶段、创建实例阶段、依赖注入阶段和容器缓存阶段以及销毁实例阶段。 阶段1:创建前准备阶段这个阶段主要是在开始Bean加载之前,从Spring上下文中去获取相关的配置…

如何使用Alchemy开发NFT智能合约(ERC721)

🥸 本教程翻译自官网:[https://docs.alchemy.com/docs](https://docs.alchemy.com/docs)。对部分内容进行了修改。教程中所有实例经过本人实践,代码可见:https://github.com/ChuXiaoYi/web3Study 使用Solidity开发智能合约并在区块…

2022 第十三届蓝桥杯大赛软件赛决赛, 国赛,C/C++ 大学B组题解

2022 第十三届蓝桥杯大赛软件赛决赛, 国赛,C/C 大学B组题解 文章目录 第1题 —— 2022 (5分)第2题 —— 钟表 (5分)第3题 —— 卡牌 (10分)第4题 —— 最大数字 (10分)第…

bbys_tu_2016

1,三连 思路:栈溢出 2,IDA分析 利用函数: 思路:ret2text 偏移:24 3,payload from pwn import * context.log_level"debug"rremote(node4.buuoj.cn,29195)flag 0x804856Dpayload 24 * a p32(flag) r.se…

Unittest单元测试框架之unittest构建测试套件

构建测试套件 在实际项目中,随着项目进度的开展,测试类会越来越多,可是直到现在我 们还只会一个一个的单独运行测试类,这在实际项目实践中肯定是不可行的,在 unittest中可以通过测试套件来解决该问题。 测试套件&…

七、Zookeeper注册中心

目录 1、下载Zookeeper的服务jar包 2、下载好jar包后解压放到合适的目录(目录最好不要有中文及空格) 3、进入解压后的conf目录,复制zoo_sample.cfg文件并重命名为zoo.cfg,修改zoo.cfg文件内容如下 4、运行bin目录下的zkServer…

split,paste,eval命令及正则表达式

一、split命令 将 linux 下的一个大文件拆分成若干小文件 1.语法格式 格式:split 选项 参数 原始文件 拆分后文件名前缀 常用选项: -l:以行数拆分 -b:以大小拆分 2.命令演示 2.1选项 -l :以行数分隔 cat -n anaconda-ks.cfg…

Windows系统安装好MongoDB后运行方法

文章目录 1、先找到安装MongoDB的文件位置的bin文件夹:2、找到data/db文件夹位置(如果data文件夹中没有db文件夹需要创建一个):3、在刚刚打开的cmd窗口中运行以下命令:4、再另外从bin文件夹位置开一个cmd窗口&#xff…

图书管理系统(Java简单版)(完整代码+详解)

目录 详解: BookList类: InOperation接口 User类(父类) 和 Main类(这俩要一起看) 完整代码 book包 Book类 BookList类 operation包 AddBook类 BorrowBook类 DeleteBook类 FindBook类 Pr…

ESP32 FreeRTOS学习总结

2023.5.11 1.Task 创建任务常用API: 任务函数描述xTaskCreate()使用动态的方法创建一个任务xTaskCreatePinnedToCore指定任务的运行核心(最后一个参数)vTaskDelete(NULL)删除当前任务 BaseType_t xTaskCreate(TaskFunction_t pxTaskCode, // 任…

【HBase】架构

文章目录 整体架构Master负载均衡器元数据管理器预写日志处理器 Region ServerZookeeperHDFS Master架构Meta 表格 RegionServer 架构MemStoreWALBlockCache 读写流程HFile结构写流程读操作 整体架构 Master 实现类为 HMaster。 负责监控集群中所有的 RegionServer 实例。 &…

在Fedora-Workstation-Live-x86_64-36-1.5中使用佳能喷墨打印机ip2780

在Fedora-Workstation-Live-x86_64-36-1.5中使用佳能喷墨打印机ip2780 操作系统是64位的Fedora-Workstation-Live-x86_64-36-1.5.iso,实物打印机是佳能ip2780,USB接口 应用程序——其它——设置——打印机——解锁——输入root密码——将打印机USB插入电…

Redis数据结构——动态字符串、Dict、ZipList

一、Redis数据结构-动态字符串 我们都知道Redis中保存的Key是字符串,value往往是字符串或者字符串的集合。可见字符串是Redis中最常用的一种数据结构。 不过Redis没有直接使用C语言中的字符串,因为C语言字符串存在很多问题: 获取字符串长度…

智慧产业城彰显中国智造魅力,中联重科踏出“走上去”的关键一步

5月11日至14日,中联重科在长沙举行了“科技献礼新时代”系列活动。 借着活动,松果财经实地探访了全球规模最大、品种最全的工程机械产业基地,领略了前沿技术赋能先进制造的魅力。 作为湖南省“一号工程”和“十大重点项目之首”&#xff0c…

好家伙,又一份牛逼笔记面世了...

最近网传的一些裁员的消息,搞的人心惶惶。已经拿到大厂offer的码友来问我:大厂还能去,去了会不会被裁。 还在学习的网友来问我:现在还要冲互联网么? 我是认为大家不用恐慌吧,该看啥看啥,该学啥…

你一定要知道的unittest自动化测试框架详解

目录 框架的概念 Unittest单元测试框架 常用的assert语句 unittest创建测试代码的方式: unittest构建测试套件(测试用例集合): unittest忽略测试用例: 运行测试集 批量执行测试用例 生成HTMLTestRunner测试报告…

【运维知识进阶篇】集群架构-Nginx基础(安装+启动+配置+多业务实现+日志管理)

本篇文章介绍下Nginx有关内容,Nginx是一个开源且高性能、可靠的Http Web服务、代理服务。 开源:直接获取源代码,高性能:支持海量并发,可靠:服务稳定 Web服务有很多,选择Nginx是因为他的轻量化…

【软件测试】测试开发的一生之敌-BUG

文章目录 1.前言2.如何描述/创建一个BUG3.BUG的级别4.BUG的生命周期5.跟开发产生争执怎么办 1.前言 BUG相比大家都知道,程序运行出错或者与预期不符就是BUG.现在我们来用测试人员的角度来看待BUG. 2.如何描述/创建一个BUG 测试人员要测试开发人员的代码,找出开发人员可能忽略…

敏态开发在大兴机场数字化转型中的实践

一、最大事业是育人 大兴机场是一个年轻的企业,作为一个企业来讲,最宝贵的就是人才。我们在2017年开始社招大学生,到目前为止,公司有一半都是30岁左右的年轻人,并且每年都会招几十个。年轻人特别想做事,而…