ES

ES概述:

是一个基于RESTful WEB接口并且构建在Apach Lucene之上的开源分布式搜索引擎,能够支持全部检索,结构化检索和数据分析的工具

ps:Lucene是一个开放源代码的全部搜索引擎工具包,,全文搜索的引擎机构

ES的特点

  1. 开源分布式的搜索引擎
  2. 高扩展,处理PB级结构化和非结构化的数据
  3. ES的存储形式为文件存储,每个字段都能被用作索引
  4. 支持全部检索和结构化检索

ES的参数基本概念

ps:可以参考我们elk平台

1.Index: ES索引–>存储数据的地方,类似于我们正常数据库中的database
2. Type: 文档类型–>类似于databse下面的n张表,每个Index下面会有多个type
3. Document: 文档数据,类似于database里面一行一行的数据
4.Fieled: ES的json类型的字段,相当于database中表的列(Column)
5. Mapping: 索引中文档的约束,列入字段类型的约束。类似于database中的表的结构(Schema)
6. DSL: DSL是ES提供json类型风格的请求语句,类似于sql语句(增删改查)

ES数据同步

同步双写

ps:将数据写入到mysql中同时也写入到ES中,两者数据是同步的
流程: 程序–>(写入Mysql/ES)
在这里插入图片描述

优点

  1. 业务逻辑简单,实现方便

缺点

1.硬编码:在需要写入mysql中,同时需要添加ES写入的代码
2.ES代码和业务代码混合一起,耦合性较强,不符合高内聚低耦合的思想
3.存在双写过程中写入失败,数据丢失的风险
4.业务功能性能和体验比较长,mysql性能本身不高,这时候在处理ES会导致性能更差

异步双写

ps: 通过引入消息队列的模式,例如(MQ),从而形成异步处理。两者处理不会在同一个节点下进行
流程: 程序–>分别写入MQ–>(写入Mysql/ES)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DieaQbsi-1657686296136)(https://note.youdao.com/yws/res/3162/WEBRESOURCE3afc9cfd9dd2d52fa235090e8b4bc8e0)]

优点

  1. 性能高;
  2. 不存在丢数据的情况

缺点

  1. 硬编码问题:需要增加写入MQ的代码
  2. 业务耦合性也比较强,需要在处理Mysql的同时,也会要处理ES的问题
  3. 复杂度增加:系统中加入了MQ,使系统的复杂性增加
    4.MQ的消费需要根据服务器的性能和MQ的队列配置,网络等因素影响,导致数据的写入会存在一定的延迟问题

异步双写(WORKE模式)

ps:不管是同步双写还是MQ异步双写,对代码的植入性都很强,可能会影响正常业务。如果系统对实时性要求不高的情况下,引入定时器的概念,在程序一定的时间内扫描mysql表相关变化的数据,然后逐条对变化的数据写入到ES中

流程: 程序–>Mysql数据库<–定时器(查询crud的数据)–>写入MQ
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2ZWwlhZQ-1657686296137)(https://note.youdao.com/yws/res/3164/WEBRESOURCEf16c4a08d8a6ecba6f2b4cd3965b9f62)]

优点

  1. 耦合性比较低:不会对业务代码存在强耦合,影响正常业务功能
  2. 不会影响正常程序的性能
  3. 不存在硬编码

缺点

  1. worker模式时效性差,实时层面没有同步双写和异步双写(MQ模式)时效性高
  2. 对mysql数据库有一定的轮训压力,改进方法常有:对数据库的表进行分表,将轮训放到压力不大的数据库上面

Binlog模式

ps: 解决硬编码,高耦合,代码植入以及时效性差的问题,可以通过监听mysql的crud的binlog日志,将读取的信息转换为MQ,MQ通过不断消费去写入到ES中
流程: 程序–>Mysql数据库<–提取Binlog日志–>Binlog同步系统–>写入MQ<–MQ消费程序–>写入到ES
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8BTBPZiO-1657686296137)(https://note.youdao.com/yws/res/3171/WEBRESOURCE12b9a6991e8f2750be4c9aab20d0508e)]

优点

  1. 没有代码入侵,提高低耦合和代码植入的风险
  2. 性能高,与业务之间完全解耦,不会影响业务的正常功能

缺点

  1. 构建binlog系统复杂
  2. 引用MQ存在时效性的问题

ES常用类型

  1. binary类型: 二进制类型 ,值以base64字符串的形式存贮,_source默认不会存贮该类型的值,如果需要实际的存贮,请设置 store属性为true默认是false
  2. Bool类型: 布尔类型 ,True或False
  3. Keyword类型:关键字类型,该字段适合聚合和排序的使用,在es分词中当做一个整体,如果涉及term精确查询,也可以进行考虑。
  4. widecard类型: 适合通配符类型和正则表达式类型搜索,而text类型不支持通配符的搜索
  5. 数字类型:short,interger,long unsigned_long,
  6. Dates类型:日期类型包含Date ,Date_nanos
  7. alais类型:为已存在的字段定义别名,别名可用于却大多数搜索api和field capabilities
  8. object类型:该类型值为一个json类型
  9. text类型: 该类型为全文搜索类型,常与match系列进行匹配
  10. Arrays类型:在ES中没有专门的数组类型,所有类型字段都可以有一个或多个的值
  11. nested类型:子文档就存在父文档某个字段内部,适合子文档数量较少的情况

注意:

  1. 一个文档最多有50个nested类型的字段
  2. 一个文档所有nested类型的字段存储文档最大数量是10000条
#定义一个mapping
PUT _index
{
    "mapping":{
        
        "type_name":{ #_type名称
            "properties": {
                "binary_name":{ #设置为binary类型字段
                    "type":"binary",
                     "store": true #默认为False,如果需要在source显示 则设置为True
                },
                 "boolean_name":{ #设置为boolean类型字段
                     "type": "boolean" 
                },
                "keyword_name":{ #设置为keyword类型字段
                    "type":"keyword"
                },
                "constant_keyword_name":{
                    "type": "constant_keyword", #设置该类型表示所有文档该字段值都是一样的
                    "value":"constant"
                },
                "wildcard_name": {#设置为wildcard类型字段
                    "type": "wildcard"
                },
                "integer_name": {#设置为integer类型字段
                    "type": "integer"
                },
                "float_name": {#设置为float类型字段
                    "type": "float"
                },
                "date_name":{#设置为date类型字段
                    "type": "date",
                    "format":"yyyy-MM-dd HH:mm:ss"#设置指定格式化类型,如果不设置则默认类型为yyyy-MM-dd ‘T’ HH:mm:ss.SSSZ
                },
                "text_name":{#设置为text_name类型字段
                    "type":"text"
                },
                "nested_name":{ #设置为nested类型字段
                    "type": "nested",
                    "properties": {
                        "names":{
                            "type":"text"
                        },
                        "alias_name":{ #设置为alias类型字段别名
                            "type": "alias",
                            "path":"nested_name.names"
                        }
                    }  
                }
            }
        
        }
    
    }

ES查询

ps: 在es中默认分词器规则为英文会按照空格进行切换,大写转换为小写,中文会按照单个词进行分词

Restful基础操作

ps:为了保证演示在文章中_index表示索引的名称,_type表示索引的文档类型

获取Mapping结构

ps:PUT方法有则修改,无则新增

GET _index/_type/_mapping
创建文档

ps:PUT方法有则修改,无则新增

PUT _index/_type/1
{
"name": "xw",
"age":18
}
或
POST _index/_type/1
{
"name": "xw",
"age":18
}
查询指定的索引信息
GET _index

查询指定文档的信息
GET _index/_type/1
查询指定条件(非结构化)
GET _index/_type/_search?q=name:xuw    #q:代表query,name:代表文档的对应的列字段,xuw:值
查询对应索引下所有的文档数据
GET _index/_type/_search
或
GET _index/_type/_search
"query":{
	"match_all":{
	}
}
删除指定的文档
DELETE _index/_type/1  #删除指定索引下的文档的第一条数据
删除指定的索引
DELETE _index
修改指定的文档方式
POST _index/_type/1/_update
{
	"doc":{
		"name":"xw1"
		}
}

ES的基础查询-match系列

match系列-match查询

ps: match为单字段查询,不能进行多字段组合查询

#结构化写法
GET _index/type_search
{
	"query":{
		"match":{
			"name":"xw 是好人" #根据es默认分词器,则为:['xw','是','好','人'],只要匹配任何一个则会进行返回
		}
	}
}
或
GET _index/type_search
{
	"query":{
		"match":{
			"name":{ #ES的Fieled值
				"query":"xw ,是好人" #根据es默认分词器,则为:['xw','是','好','人']
				#"operator":"or",  #默认为or,所以不写,则只需要匹配任何一个即可
				#"operator": "and" #要匹配所有关键词
			}
		}
	}
}

#参数
operator: 值为and 和 or
值and:相当于要匹配所有的关键词,对分词以后类似于mysql的:(key1=value1 and key2=value and …)
值or: 只需要匹配其中一个关键词就可,对分词以后类似于mysql的:(key1=value1 or key2=value or …)

match系列->match_all查询

ps: match_all则查询全部
ps: 类似于mysql select查询不带任何的条件

#结构化用法

GET _index/_type/_search
{
	"query":{
		"match_all":{
		
		}
	}
}
match系列->match_phrase

ps: match_phrase为短语查询,对应的的都要进行匹配,相对于match的operator的and
ps: match_phrase 类似mysql的 like ‘%<值>%’

#结构化用法

#例如name为: Kobe Bean Bryant
GET _index/_type/_search
{
	"query":{
		"match_phrase":{
			"name":"Kobe Bean" 
			
		}
	}
}
或 
GET _index/_type/_search
{
	"query":{
		"match_phrase":{
			"name":{
				"query": "Kobe Bean",
				# "slop":0  #slop参数默认为0,slop参数为两组词之间的最大可移动的间隔和顺序,在搜索的时候更加灵活
			}
			
		}
	}
}

#参数
slop: 表示两组词之间的最大可移动的间隔和顺序

例如slop 为1 ,表示可以支持最大的间隔和顺序,上方query的值可以为:"Kobe Bryant"进行匹配

match系列-> match_phrase_prefix

ps: match_phrase_prefix 是最左前缀匹配,类似match_phrase ,差异点是根据分词器进行前缀匹配
ps: match_phrase_prefix相当于对分词以后,然后根据类似mysql的 like ‘<值>%’ 语法

#结构化语法


GET _index/_type/_search
{
	"query":{
		"match_phrase_prefix":{
			"name": Kobe Be",  #根据分词器然后进行最左前缀匹配,如果是"name": Kobe Be" 则match_phrase_prefix可以匹配,但是在match_phracse无法匹配
			#"max_expansions":5 #前缀查询对性能影响很大,所以再使用的时候会对结果集进行限制,默认不进行限制
			}
		}
}

#参数
max_expansions:前缀查询对性能影响很大,所以再使用的时候会对结果集进行限制,默认不进行限制

match系列->multi_match

ps: 相对于前面几种都是单字段查询,而multi_match则是多字段查询

#结构化语法

#例如name为: Kobe Bean Bryant,remark为:Kobe Bean is beast player

GET _index/_type/_search
{
	"query":{
		"multi_match":{
			"query":"Bean",
			"fields" ["name","remark"]
			#"type":"" #type选项值的可以为:phrase 和 phrase_prefix
		}
	}
}

#参数
type查询的类型

值为phrase: 实现 match_phrase的方法
值为phrase_prefix : 实现match_phrase_prefixd的方法

ES词项查询

ps: ES此项查询可以理解为类似于mysql的运算符

query-term:精确查询

ps: term查询可以理解为mysql中的"="
#结构化语法

#name 为 xuw
GET _index/_type/_search
{
	
	"query":{
		"term":{
				"name":"xuw" #类似mysql的 name="xuw"
			}
		}
}
或
GET _index/_type/_search
{
	
	"query":{
		"term":{
				"name":{
					"value":"xuw" ,#类似mysql的 name="xuw"
					"boost": 1.0 #权重
				}
			}
		}
}
query-terms:精准多项匹配

ps:与term类似,只是terms是匹配多个,相当于mysql类似的 in语法

name 为xuw
GET _index/_type/_search
{
 
 "query":{
  "terms":{
    "name":["xuw","LIH"] #类似mysql的 name in ("xuw","LIH")
   }
  }
}
query-range: 区间匹配
age 为19
GET _index/_type/_search
{
 
 "query":{
  "range":{
    "age":{ #key值如果是字符串类型则需要加.keyword 例如: "age.keyword"
     "lt": 20, #小于20
     "gt": 10, #大于10
     #"format": "yyyy-mm-dd" #如果查询时间范围,可以指定时间格式
    } 
   }
  }
}
或
GET _index/_type/_search
{
 
 "query":{
  "range":{
    "age":{  #key值如果是字符串类型则需要加.keyword 例如: "age.keyword"
     "from": 10, #小于10
     "to": 20, #大于20 
     "includeLower": true, #为true包含下界,false不包含
     "includeUpper": true #为true包含上界,false不包含
    } 
   }
  }
}
query-exists 对空值进行过滤处理

ps: query-exists查询会返回字段中至少一个非空值的文档

GET _index/_type/_search
{
	
	"query":{
		"exists":{
				"field":"user" # user不存在或者user为[],null [null] 则都会进行过滤处理
			}
		}
}
query-prefix 对前缀进行匹配

ps:查询用于某个字段中以给定的前缀开始的文档

#name 为 hello world
GET _index/_type/_search
{
	
	"query":{
		"prefix":{
				"name":"hello" #类似于mysql中的:like "hello%"
			}
		}
}
query-wildcard 通配符匹配

ps: 类似常用sql中的模糊匹配,支持单个字符通配符和多字符通配,"?“为1个任意字符,”*"为匹配零个或多个字符

#name 为  我是王小小
GET _index/_type/_search
{
	
	"query":{
		"wildcard":{
				"name":"王小?", #可以匹配王小小,如果值为 : "王?" 则无法匹配:王小小
				#"name":"王*", #可以匹配:王小,也可以匹配:王小小
				#"name":"*王*" #可以匹配:洲王小,也可以匹配:洲洲洲王小
			}
		}
}

query-regexp 正则表达式匹配

ps: regexp为正则表达式进行匹配

name 为 W000a
GET _index/_type/_search
{
	"query": {
		"regexp": {
			"name": "W[0-9].+"
		}
	}
}
query-type 查询指定类型文档

ps: 查询es下指定index下的文档

GET _index/_search
{
	"query": {
		"type": {
			"value": "doc" #doc为指定类型的文档
		}
	}
}
query-ids 查询具有指定id的文档

ps: 用于查询指定type下的文档,类似mysql 中指定数据库下指定id的数据

GET _index/_type/_search
{
	"query": {
		"ids": {
			"type": "doc" #type为对应的文档名称
			
			"value": ["1","6"] #对应文档id为 1和6的数据
		}
	}
}
query-fuzzy 纠错模糊查询

ps: 自动将拼写错误的搜索文本,进行纠正,纠正以后去尝试匹配索引中的数据

  1. 一个字符 替换 另一个字符: _f_ox → _b_ox
  2. 插入 一个新的字符:sic → sic_k_
  3. 删除 一个字符:b_l_ack → back
#设置name为 xxuw
GET _index/_type/_search
{
  "query": {
    "fuzzy": {
      "title": "surprize", #surprize --> 拼写错误 --> surprise --> s -> z
       "fuzziness" 2 #fuzziness 默认为2,设置纠错的步骤次数
    }
  }

track_total_hits参数

ps:如果现实需要超过1w条数据,则需要track_total_hits为true,否则不指定该参数显示为9999
如果需要显示指定的数据,那可以指定track_total_hits具体的值

GET _index/_type/_search
{
	
	"query":{
		 #省略
		}
	"track_total_hits":true #显示超过1w条数据加上
	#"track_total_hits":200 #最大只显示200条数据
	#"track_total_hits":false #最大只显示9999条数据
}
query-nested查询

ps: 对子文档下的父文档进行查询匹配,,即让数组中的对象各自地进行索引。目的是对象之间彼此独立被查询出来。

设置文档下某个studens的数据为
"student":[
        {
            "name":"xuw",
            "sex":"男",
            "age":18
        },
        {
            "name":"jon",
            "sex":"男",
            "age":19
        }
]
GET _type/_index/_search
{
    "query":{
        "nested":{
            "path": "student",
            "query":{
                "bool":{
                    "must":[
                        "term":{
                            "student.name":"xuw" #如果将name 的值设置为jon,则无法搜索该数据
                        },
                        "term":{
                            "student.age":"18"
                        }
                        
                    ]
                }
            }
        }
    }
}

adjust_pure_negative参数

ps:这东西缺省是true,所以你显式指定了true等于没写。
用在你的条件如果全是must_not的时候,它会额外添加上一个matchALL,防止没有数据返回。
如果你显式指定了是false,它就没有数据返回了。

{
	"adjust_pure_negative":true,
	"query":{
		 #省略
		}

}
boost参数

ps:查询时的权重提升 是可以用来影响相关度的主要工具,任意类型的查询都能接受 boost 参数,适当的提升boost的值会提高的相关度评分 _score

ES的基础查询-bool系列

ps: bool查询可以将一些简单的查询组合在一起,使用must ,not must,should,filter选项来表示简单逻辑之间的查询,每个选项可以支持0次到多次

must: 所有的条件都要匹配文档,类似于mysql的 and 语法,可以参与评分
must_not: 与must相反,must_not下所有的条件匹配到了文档都不会返回,must_not语句不影响评分,她的语句是将不想关的文档进行排除
should: should下的过滤条件可以匹配也可以不匹配文档,相当于mysql语法的 or ,且会参与评分
filter : filter和must实际处理逻辑是一样的,区别是:filter不评分,只是做过滤和排除,与must_not相反

GET _index/_type/_search
{
  "query": {
    "bool" : {
      "must" : {   #查询一定包含匹配查询内容,并且提供得分
        #查询条件 #多个条件则每个条件为一个对应key:value;例如 "must":{条件1:判断1,条件2:判断2,条件3:判断3}
      },
      "filter": { #查询一定包含匹配查询内容,但是不提供得分,会对查询结果进行缓存
        #查询条件 #多个条件则每个条件为一个对应key:value;例如 "filter":{条件1:判断1,条件2:判断2,条件3:判断3}
      },
      "must_not" : { #查询一定不包含查询内容,来自于filter 上下文,所以不会由评分,但是会缓存
         #查询条件 #多个条件则每个条件为一个对应key:value;例如 "must_not":{条件1:判断1,条件2:判断2,条件3:判断3}
      },
      "should" : { #子查询不一定包含查询内容 有一个包含即可

         #查询条件  #多个条件则每个条件为一个对应key:value;例如 "should":{条件1:判断1,条件2:判断2,条件3:判断3}
      },
      "minimum_should_match" : 1, #最小匹配一个should条件
      "boost" : 1.0
    }
  }
}
或
GET _index/_type/_search
{
  "query": {
    "bool" : {
      "must" : [ #查询一定包含匹配查询内容,并且提供得分(真真为真)
        #查询条件   #多个条件则每个条件为一个字典类型例如 "must":[{条件1},{条件2},{条件3}]
      [,
      "filter": [ #查询一定包含匹配查询内容,但是不提供得分,会对查询结果进行缓存(真真为真)
        #查询条件   #多个条件则每个条件为一个字典类型例如 "filter":[{条件1},{条件2},{条件3}]
      ],
      "must_not" : [#查询一定不包含查询内容,来自于filter 上下文,所以不会由评分,但是会缓存(假假为真)
         #查询条件  #多个条件则每个条件为一个字典类型例如 "must_not":[{条件1},{条件2},{条件3}]
      ],
      "should" : [#子查询不一定包含查询内容 有一个包含即可(真假为真)
         #查询条件  #多个条件则每个条件为一个字典类型例如 "should":[{条件1},{条件2},{条件3}]
      ],
      "minimum_should_match" : 1, #最小匹配一个should条件
      "boost" : 1.0
    }
  }
}

ES的排序基础操作-sort

ps: sort代表es的排序关键词,类似于mysql中的order by

#结构化语法

GET _index/_type/_search
{
	"query":{
		#忽略条件
		}
	"sort":{
		"age":{
			"order":"asc"  #asc代表升序,desc代表降序
			},
		"name":{
			"order":"desc"  #asc代表升序,desc代表降序
			}
	}
}
或
GET _index/_type/_search
{
	"query":{
		#忽略条件
		}
	"sort":[
			{
				"age":{
					"order":"asc"  #asc代表升序,desc代表降序
				}
			
			},
			{
				"name":{
					"order":"desc"  #asc代表升序,desc代表降序
				}
			
			}
	]
}

#上述语法类似mysql中的: order by age asc,name desc

ES的分页基础操作

ps: ES的分页是根据关键字from:从那里开始查,size:往后返回第几条数据,类似于mysql中的:LIMIT [offset,] rows

GET _index/_type/_search
{
	"query":{
		#忽略条件
		},
	"sort":{
		#忽略条件
	}
	"from": 0, #相当于mysql的limit 的 offset,从那里开始查
	"size":10 #相当于mysql的 limit 的 rows,往后返回第几条
}
#上述语法匹配mysql 的 limit 0,10

ES指定返回的字段:_source

ps: 在查询过程中,为了保证输出字段的可控,来减少资源消耗,可以使用_source来进行指定和不指定对应的字段

GET _index/_type/_search
{
	"query":{
		#忽略条件
		},
	"sort":{
		#忽略条件
	}
	"from": 0, 
	"size":10,
	"_source":["name","age","sex"] #指定列表中的字段作为返回,相当于 select name ,age,sex from table
}
或
GET _index/_type/_search
{
	"query":{
		#忽略条件
		},
	"sort":{
		#忽略条件
	}
	"from": 0,  
	"size":10,
	"_source":{
		"excludes":["sex"], #不指定列表的的字段值
		"includes":["name","age"] #指定列表的字段值
	}
}

ES聚合

#待补充

ES和Mysql的比较

1.Mysql是关系型数据库,更擅长事务型和业务型的操作(增删改查),可以确保数据的安全和一致性。
ps:像我们正常业务中商品,客户等基础数据以及下单,支付等业务数据的场景使用

2.ES更擅长海量的数据检索,搜索,分析和计算。

ES常见的使用场景

  1. 打分制的搜索
  2. 运维平台的资源监控
  3. 海量数据的快速检索,分析及报表查询
  4. 非结构化的数据查询
  5. logstash日志的采集,日志的分析,复杂的数据分析

涉及ES的测试模式建立

  1. 需要了解业务报表相关的统计逻辑
  2. 根据开发给出的不同同步方式,设计不同的数据同步测试点
  3. 数据需要涉及增删改查(CRUD)
  4. 了解相关的ES相关增删改查语句,能够快速验证问题,在开发过程中发现问题和缺陷定位问题
  5. 了解ES相关特性例如匹配的方式,ES分词的特性等

ps:本文章参考网上相关资料,主要用于学习,如果侵权请联系我用于删除

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐