这几天没有更新,其主要的的原因是,在学习对Elasticsearch的使用。Elasticsearch是一个非常强大的数据库索引工具。是一个基于Lucene库的搜索引擎。它提供了一个分布式、支持多租户的全文搜索引擎,具有HTTP Web接口和无模式JSON文档。Elasticsearch是用Java开发的,并在Apache许可证下作为开源软件发布。官方客户端在Java、.NET(C#)、PHP、Python、Apache Groovy、Ruby和许多其他语言中都是可用的。根据DB-Engines的排名显示,Elasticsearch是最受欢迎的企业搜索引擎,其次是Apache Solr,也是基于Lucene。
所以你可以不用,但是你不能不知道,不可谓重要。
ElasticSearch
是一个分布式、RESTful
风格的搜索和数据分析引擎,在国内简称为ES
;使用Java
开发的,底层基于Lucene
是一种全文检索的搜索库,直接使用使用Lucene
还是比较麻烦的,Elasticsearch
在Lucene
的基础上开发了一个强大的搜索引擎。
主要功能有:
Elastic
是Lucene
的封装,提供了REST API
的操作接口,开箱即用
Lucene
:是单机应用,只能在单台服务器上使用,最多只能处理单台服务器可以处理的数据量。Elasric
:ES自动可以将海量数据分散到多台服务器上去存储和检索海量数据的处理:
Stack Overflow
(国外的程序异常讨论论坛)GitHub
(开源代码管理)logstash
采集日志,ES进行复杂的数据分析(ELK
技术,elasticsearch+logstash+kibana
)Business Intelligence
OA
,CRM
,ERP
)优点:
Elasticsearch
,将全文检索、数据饭呢西、分布式技术合并到了一起。lucene
(全文检索),商用的数据分析软件(也是有的),分布式数据库(mycat
)PB
级数据,服务大公司;也可以运行在单机上,服务小公司ES
,就可以作为生产环境的系统来使用了,数据量不大,操作不是太复杂现在的安装并不像之前的版本那样,包括对Elasticsearch使用。主要存在的问题是密钥。说到密钥,这个就不得不说一个东西。
Elasticsearch其实有三个方面构成:
es-client
,当然对于Kibana的来说,是比不上的,但是轻量啊。安装没有那么复杂。执行需要在浏览器的插件管理中
下载就可以用了,非常方便这里建议安装用docker去安装。这里献上官方文档(官网的不一定能成,主要是看你的虚拟机是什么)
注意
:如果是按照别人博客上的安装的话,跟着就行。诺是按照官网的上的,你就注意:
这里不放我如何去安装的因为我怕更不上时代,到时候误人子弟,官网是一直在变的。
使用前提
ElasticSearch
服务器"github.com/elastic/go-elasticsearch/v8"
import "github.com/elastic/go-elasticsearch/v8"
但是这个包下面其实还有一些包,这些包非常的重要。当时我在使用的时候,根本不知道,走了不少的弯路的,找了官网的文档,又找了一些博客,都没有详细的说明情况和要点。要不就少些,要不就只把部分给列出来。但是现在我将这些无私的奉献给各位。
因为这个v8的包非常的多,所以很难将所有的放进去。这里我做一些解释:
NewDefaultClient()
和NewClient(cfg Config)
方法会返回一个普通客户端
NewDefaultClient()
不需要去配置链接时的配置参数,默认参数链接,并返回一个普通客户端NewClient(cfg Config)
需要按照总共需要的配置需求去配置参数,并返回一个普通客户端NewTypedClient(cfg Config)
会返回一个属性客户端(相比普通客户端强大,但是有局限,后面再说)普通客户端
进行调用的,使用的范围是对于批量处理数据
的情况ElasticSearch
进行处理的时候会有很多中情况:
ElasticSearch
有独属于他自己的一套语法。AI
进行处理的参数。(建议下一个翻译软件,去看看。那个参数太多了。。。也就是说功能非常齐全)ES存储结构 | Mysql存储结构 |
---|---|
Index(索引) | 表 |
document(文档) | 行,一行数据 |
Field(字段) | 表字段 |
mapping(映射) | 表结构定义 |
index
ES
中索引(index
)就像mysql
中的表一样,代表着文档数据的集合,文档就相当于ES
中存储的一条数据type
type
也就是文档类型,不过在Elasticsearch7.0
以后的版本,已经废弃文档类型了。Elasticsearch
老的版本中文档类型,代表一类文档的集合,index(索引)
类似mysql
的数据库、文档类型类似Mysql
的表。index(索引
)就类似mysql的表的概念,ES
没有数据库的概念了。document
ES
是面向文档的数据库,文档是ES存储
的最基本的存储单元,文档类似mysql
表中的一行数据。ES
中,文档指的就是一条JSON
数据ES支持任意格式的json数据
要注意:虽然说, 一个索引就理解成一个表,但是这个表是可以存任意数据的,也就是说,不遵从约定的一开始的索引也是可以的。(所以索引名一定不能错否则,会有脏数据)
一个
document
的数据
{
"_index" : "order",
"_type" : "_doc",
"_id" : "1",
"_version" : 2,
"_seq_no" : 1,
"_primary_term" : 1,
"found" : true,
"_source" : {
"productName": "12370",
"masterPic": "12345650",
"categoryId": 1,
"desc": "12345640",
"price": "12345630",
"tags": null,
"startProvinceCode": "12345690",
"startCityCode": "12345680",
"destinationProvinceCode": "12345640",
"destinationCityCode": "12345670",
"startDate": null
}
}
文档中的任何json字段都可以作为查询条件。并且文档的json格式没有严格限制,可以随意增加,减少字段,甚至每个文档的格式都不一样也可以。
值得注意的是:
_index
:代表当前json
文档所属的文档名字(重要)_type
:代表当前json
文档所属的类型。不过在es7.0
以后废弃了type
用法,但是元数据还是可以看到的(API可以)(重要)_id
:文档唯一ID
,如果我们没有为文档指定id
,系统自动生成。(重要,一定要自己去控制)_source
:代表我们插入进入json数据_version
:文档的版本号,每修改一次文档数据,字段就会加1,这个字段新版es也给取消了_seq_no
:文档的编号,替代老的 version
字段_primary_term
:文档所在主分区,这个可以跟seq_no
字段搭配实现乐观锁(重要)
Field
文档由多个json字段,这个字段跟mysql中的表的字段是类似的。ES中的字段也是有类型的:
数值类型
(long、integer、short、byte、double、float)
Date
日期类型
boolean
布尔类型
Text
支持全文搜索
Keyword
不支持全文搜索,例如:phone这种数据,用一个整体进行匹配就ok了,也不要进行分词处理
Geo
这里主要用于地理信息检索、多边形区域的表达。
mapping
:
Elasticsearch的mapping类似于mysql中的表结构体定义,每个索引都有一个映射的规则,我们可以通过定义索引的映射规则,提前定义好文档的json结构和字段类型,如果没有定义索引的映射规则,ElasticSearch会在写入数据的时候,根据我们写入的数据字段推测出对应的字段类型,相当于自动定义索引的映射规则。
这里献上一篇我在学习时看见的一篇非常详细的文章:
mappingTpl = `{
"mappings":{
"properties":{
"categoryId": {
"type": "long"
},
"productName": {
"type": "keyword"
},
"masterPic": {
"type": "text"
},
"desc": {
"type": "keyword"
},
"price": {
"type": "long"
},
"startProvinceCode": {
"type": "text"
},
"startCityCode": {
"type": "text"
},
"update_time": {
"type": "long"
},
"create_time": {
"type": "long"
}
}
}
}`
这样我们就定义好了,一个索引的结构
在使用ES时,查询是我们经常使用的
GET /{索引名}/_search
{
"from" : 0, // 搜索结果的开始位置
"size" : 10, // 分页大小,也就是一次返回多少数据
"_source" :[ ...需要返回的字段数组... ],
"query" : { ...query子句... },
"aggs" : { ..aggs子句.. },
"sort" : { ..sort子句.. }
}
ES
查询分页:通过from
和size
参数设置,相当于MYSQL
的limit
和offset
结构query
:主要编写类似SQL
的Where
语句,支持布尔查询(and/or
)、IN
、全文搜索、模糊匹配、范围查询(大于小于)aggs
:主要用来编写统计分析语句,类似SQL
的group by
语句sort
:用来设置排序条件,类似SQL的order by
语句source
:用于设置查询结果返回什么字段,相当于select
语句后面指定字段查询语句:GET /{索引名}/_search
查询 GET /test/_search
返回结果:
{
"took": 1,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 1006,
"relation": "eq"
},
"max_score": 1,
"hits": [
{
"_index": "test",
"_id": "bZ8TfIwBuOjgAaUNdD1u",
"_score": 1,
"_source": {
"productName": "123",
"masterPic": "123456",
"categoryId": 1,
"desc": "123456",
"price": "123456",
"tags": null,
"startProvinceCode": "123456",
"startCityCode": "123456",
"destinationProvinceCode": "123456",
"destinationCityCode": "123456",
"startDate": null
}
}
}
匹配单个字段
match
实现全文索引,全文搜索是ES的关键特性之一,我们平时使用搜索一些文本、字符串是否包含指定的关键词,但是如果两篇文章,都包含我们的关键词。GET /{索引名}/_search
{
"query": {
"match": {
"{FIELD}": "{TEXT}"
}
}
}
{FIELD} 就是我们需要匹配的字段名
{TEXT} 就是我们需要匹配的内容
精确匹配单个字段
当我们需要根据手机号、用户名来搜索一个用户信息时,这就需要使用精确匹配了。可以使用term
实现精确匹配语法
GET /{索引名}/_search
{
"query": {
"term": {
"{FIELD}": "{VALUE}"
}
}
}
{FIELD} - 就是我们需要匹配的字段名
{VALUE}- 就是我们需要匹配的内容,除了TEXT
类型字段以外的任意类型
多值匹配
多值匹配,也就是想mysql
中的in
语句一样,一个字段包含给定数组中的任意一个值匹配。上文使用term实现单值精确匹配,同理terms
就可以实现多值匹配
GET /{索引名}/_search
{
"query": {
"terms": {
"{FIELD}": [
"{VALUE1}",
"{VALUE2}"
]
}
}
}
{FIELD}- 就是我们需要匹配的字段名
{VALUE1}, {VALUE2} … {VALUE N} - 就是我们需要匹配的内容,除了TEXT类型字段以外的任意类型。
范围查询
使用range
就可以实现范围查询,相当于SQL语句的>,>=,<,<=
表达式
GET /{索引名}/_search
{
"query": {
"range": {
"{FIELD}": {
"gte": 100,
"lte": 200
}
}
}
}
范围参数有如下:
gt - 大于 ( > )
gte - 大于且等于 ( >= )
lt - 小于 ( < )
lte - 小于且等于 ( <= )
bool组合查询
前面的查询都是设置单个字段的查询条件,实际项目中这么应用是很少的,基本都是多个字段的查询条件。
GET /{索引名}/_search
{
"query": {
"bool": { // bool查询
"must": [], // must条件,类似SQL中的and, 代表必须匹配条件
"must_not": [], // must_not条件,跟must相反,必须不匹配条件
"should": [] // should条件,类似SQL中or, 代表匹配其中一个条件
}
}
}
排序
假设我们现在要查询订单列表,那么返回符合条件的列表肯定不会是无序的,一般都是按照时间进行排序的,所以我们就要使用到了排序语句。
ES
的默认排序是根据相关性分数排序,如果我们想根据查询结果中的指定字段排序。
sort
子句支持多个字段排序,类似SQL的order by
。
GET /{索引名}/_search
{
"query": {
...查询条件....
},
"sort": [
{
"{Field1}": { // 排序字段1
"order": "desc" // 排序方向,asc或者desc, 升序和降序
}
},
{
"{Field2}": { // 排序字段2
"order": "desc" // 排序方向,asc或者desc, 升序和降序
}
}
....多个排序字段.....
]
}
聚合查询
ES
中的聚合查询,类似SQL
的SUM
/AVG
/COUNT
/GROUP BY
分组查询,主要用于统计分析场景。
一般统计分析主要分为两个步骤:
分组
:
组内聚合
:
一些概念:
1. 桶
:
指标
:指标指的是对文档进行统计计算方式,又叫指标聚合。
桶内聚合
,说的就是先对数据进行分组(分桶),然后对每一个桶内的数据进行指标聚合
。
SUM
、COUNT
、MAX
等统计函数。{
"aggregations" : {
"" : {
"" : {
>
}
[,"aggregations" : { [>]+ } ]? // 嵌套聚合查询,支持多层嵌套
}
[,"" : { ... } ]* // 多个聚合查询,每个聚合查询取不同的名字
}
}
aggregations
sum
、avg
, 桶聚合:terms
、Date histogram
等等。
aggregation_name_2
例子:
GET /order/_search
{
"size" : 0, // 设置size=0的意思就是,仅返回聚合查询结果,不返回普通query查询结果。
"aggs" : { // 简写
"count_store" : { // 聚合查询名字
"terms" : { // 聚合类型为,terms,terms是桶聚合的一种,类似SQL的group by的作用,根据字段分组,相同字段值的文档分为一组。
"field" : "store_name" // terms聚合类型的参数,这里需要设置分组的字段为store_name,根据store_name分组
}
}
}
}
count函数
Value Count
:值聚合,主要用于统计文档总数,类似SQL
的count
函数。
GET /sales/_search?size=0
{
"aggs": {
"types_count": { // 聚合查询的名字,随便取个名字
"value_count": { // 聚合类型为:value_count
"field": "type" // 计算type这个字段值的总数
}
}
}
}
cardinality
基数聚合,也是用于统计文档的总数,跟Value Count
的区别是,基数聚合会去重,不会统计重复的值,类似SQL
的count(DISTINCT 字段)用法。
POST /sales/_search?size=0
{
"aggs" : {
"type_count" : { // 聚合查询的名字,随便取一个
"cardinality" : { // 聚合查询类型为:cardinality
"field" : "type" // 根据type这个字段统计文档总数
}
}
}
}
avg
求平均值POST /exams/_search?size=0
{
"aggs": {
"avg_grade": { // 聚合查询名字,随便取一个名字
"avg": { // 聚合查询类型为: avg
"field": "grade" // 统计grade字段值的平均值
}
}
}
}
Sum
求和计算POST /sales/_search?size=0
{
"aggs": {
"hat_prices": { // 聚合查询名字,随便取一个名字
"sum": { // 聚合类型为:sum
"field": "price" // 计算price字段值的总和
}
}
}
}
max
求最大值POST /sales/_search?size=0
{
"aggs": {
"max_price": { // 聚合查询名字,随便取一个名字
"max": { // 聚合类型为:max
"field": "price" // 求price字段的最大值
}
}
}
}
min
求最小值POST /sales/_search?size=0
{
"aggs": {
"min_price": { // 聚合查询名字,随便取一个
"min": { // 聚合类型为: min
"field": "price" // 求price字段值的最小值
}
}
}
}
到了这里查询语法就全部结束了,但是语法只是语法,如何去用包的API去调用就是一个非常重要的问题。这里我说明一下。无论是什么Elasticsearch语句,最后都会转换成相应的接口API去实现的。所以调用也会变得简单。
具体API调用方式请看这个文章:GoLang学习之路,对Elasticsearch的使用,一文足以(包括泛型使用思想)(二)
本来是想继续写下去,但是超过一万字真的好卡啊。。。。。csdn什么扩充一下啊。