前言
我们生活在一个信息爆炸的时代,每天各种信息充斥的我们的大脑。我们要求这些海量的数据能够永久保存,而且在我们的用的时候也能快速检索到(我们这些贪婪的人类)。我们的技术进步就是来源于我们各种奇怪的新需求,正因为这般需求Elasticsearch诞生了。它能保存海量数据,检索速度快,提供分布式,提供全文搜索功能,即是我们输入的关键字不准确,也能搜索到想要的数据。总之,Elasticsearch好处多多,赶快学习吧!
1、为什么学习Elasticsearch?
1、在海量的数据中执行搜索功能时,如果使用MySQL,效率太低
2、如果关键字输入不准确,一样可以搜索到想要的数据。
3、将搜索关键字,以红色的字体展示。
2、Elasticsearch介绍
1、Java语言并且基于Lucene编写的搜索引擎框架
2、提供分布式的全文搜索功能
3、提供基于RESTFul风格的web接口
4、官方客户端也对多种语言都提供了相应的API
Lucene本身就是一个搜索引擎的底层。
分布式:ES主要为了突出它的横向扩展能力
全文检索:将一段词语进行分词。(倒排索引)
应用广泛:GitHub、WIKI、京东等
3、Elasticsearch与Slor的区别:
1、Slor在查询死数据时、速度相对ES更快。但是数据如果是实时改变的,Slor的速度会降低很多,ES的查询效率基本没有变化。
2、Solr搭建基于需要依赖Zookeeper来帮助管理。ES本身就支持集群的搭建,不需要第三方的介入。
3、最开始Solr的社区可以说是非常火爆的,针对国内的文档并不是很多。在ES出现之后,ES的社区火爆程度直线上升,ES的文档非常健全。
4、ES对现在的云计算和大数据支持的特别好。
4、深分页Scroll
ES对from+size是有限制的,from和size二者之和不能超过1W
原理:
from+size在查询数据的方式
第一步:先将用户指定的关键字进行分词
第二步:将词汇去分词库中进行检索,得到多个文档的ID。
第三步:去各个分片中去拉去指定的数据,耗时较长。
第四步:将数据根据score进行排序,耗时较长。
第五步:根据from的值,将查询到的数据舍弃一部分。
第六步:返回结果
Scroll+size在ES中查询数据的方式:
第一步:先将用户指定的关键字进行分词
第二步:将词汇去分词库中进行检索,得到多个文档ID。
第三步:将文档的ID存放在一个ES的上下文中。
第四步:根据你指定的size去ES中检索指定的数据,拿完数据的文档ID,会从上下文中移除。
第五步:如果需要下一页数据,直接去ES的上下文中,找后续的内容
第六步:循环第四步和第五步。
【*】Scroll查询方式,不适合做实时的查询。
5、倒排索引
解释:
- 将存放的数据以一定的方式进行分词,并将分词的内容存放到一个单独的分词库中。
- 当用户取查询数据时,会将用户的查询关键字进行分词,然后去分词库中匹配内容,最终得到数据的id标识。
- 根据id标识去存放数据的位置拉去指定数据。
6、ES的基本概念
- 索引(index),分片,备份
ES服务中会创建多个索引
每个缩影默认被分成5个分片
每个分片存在至少一个备份分片
备份分片 不会帮助检索数据(当ES检索压力特别大的时候才,备份分片才会帮助检索数据)
备份的分片必须放在不同的服务器中
- 类型(type)
一个索引下可以创建多个类型
PS:版本不同,类型的创建也不同
- 文档(document)
一个类型下可以有多个文档,这个文档就相当于mysql表中的多行数据
- 属性Field
一个文档中可以包含多个属性,类似于mysql 表中的一行数据有多个列
7、Elasticsearch的查询语法(RESTful 风格)
-
这是ES查询语句的整体结构:
{ "query":{}, //查询的条件 "from":0, //分页:从第几页开始 "size":5, //每页显示几条数据 "sort":[{},{}], //排序 "highlight":{}, //高亮查询 "aggs":"" //聚合查询 }
-
关于query里面的结构
- 根据多个ID查询数据
{ “query”:{ “ids”:{ "values": ["1","2","3"] } } }
- term和terms查询
terms 和 term 查询的机制一样,搜索之前不会对你搜索的关键字进行分词,直接拿 关键字 去文档分词库中匹配内容
terms:是针对一个字段包含多个值 term : where province =北京 terms: where province = 北京 or province =? (类似于mysql 中的 in) 也可针对 text, 只是在分词库中查询的时候不会进行分词
{
"query" : {
"term" : {
"属性名": {
"value" : ""
}
},
"terms" : {
"属性名" : ["",""]
}
}
}
- match和match_all查询
match_all:查询全部内容,不指定查询条件。
match:指定一个Field 作为查询条件。
布尔match 查询:基于一个field 匹配的内容,按照 and 或者or的方式连接
{
"query":{
"match":{
"属性名": ""
},
"match_all" : {},
"match":{
"属性名": {
# 既包含 战士 也包含 团队
"query": "战士 团队",
"operator": "and"
},
}
}
}
- 其他查询说明:
multi_match:match 针对一个field 做检索,multi_math 针对多个field 进行检索,多个field对应一个文本。
prefix 查询:前缀查询,可以通过一个关键字去指定一个field 的前缀,从而查询到指定文档
fuzzy 查询:模糊查询,我们可以输入一个字符的大概,ES 可以根据输入的大概去匹配内容。查询结果不稳定
wildcard 查询:通配查询,同mysql中的like 是一样的,可以在查询时,在字符串中指定通配符*和占位符?
rang 查询:范围查询,只针对数值类型,对一个field 进行大于或者小于的范围指定
regexp 查询:正则查询,通过你编写的正则表达式去匹配内容
Ps:prefix wildcard fuzzy 和regexp 查询效率比较低 ,在要求效率比较高时,避免使用
复合查询:复合过滤器,将你的多个查询条件 以一定的逻辑组合在一起,
must:所有条件组合在一起,表示 and 的意思
must_not: 将must_not中的条件,全部都不匹配,表示not的意思
should:所有条件用should 组合在一起,表示or 的意思
boosting查询:可以帮助我们去影响查询后的score。
positive:只有匹配上positive 查询的内容,才会被放到返回的结果集中
negative: 如果匹配上了positive 也匹配上了negative, 就可以 降低这样的文档score.
negative_boost:指定系数,必须小于1 0.5
关于查询时,分数时如何计算的:
搜索的关键字再文档中出现的频次越高,分数越高
指定的文档内容越短,分数越高。
我们再搜索时,指定的关键字也会被分词,这个被分词的内容,被分词库匹配的个数越多,分数就越高。
filter查询:
query 查询:根据你的查询条件,去计算文档的匹配度得到一个分数,并根据分数排序,不会做缓存的。
filter 查询:根据查询条件去查询文档,不去计算分数,而且filter会对经常被过滤的数据进行缓存。
{
“query”:{
“ids/term/terms/match/multi_match/prefix/fuzzy/wildcard/range/regexp”:{},
“bool”:{
“should”: [],
“must_not”:[],
“must”: [],
“filter”:[{},{}]
},
“boosting”:{
“positive”:{ “match”:{}},
“negative”:{“match”:{}},
“negative_boost”: 0.2 }
}
}
-
高亮查询
高亮查询就是用户输入的关键字,以一定特殊样式展示给用户,让用户知道为什么这个结果被检索出来
高亮展示的数据,本身就是文档中的一个field,单独将field以highlight的形式返回给用户
ES提供了一个highlight 属性,他和query 同级别。
frament_size: 指定高亮数据展示多少个字符回来
pre_tags:指定前缀标签<front color="red">
post_tags:指定后缀标签 </font>
{
"query" : {
"match": {
"属性名": ""
}
},
"highlight" : {
"fields" : {
"属性名" : {}
},
"pre_tags":"<font color='red'>",
"post_tags": "</font>",
"fragment_size": 10
}
}
-
聚合查询
去重计数,cardinality 先将返回的文档中的一个指定的field进行去重,统计一共有多少条
范围统计:统计一定范围内出现的文档个数,比如,针对某一个field 的值再0~100,100~200,200~300 之间文档出现的个数分别是多少
范围统计 可以针对 普通的数值,针对时间类型,针对ip类型都可以响应。
数值 rang
时间 date_rang
ip ip_rang
统计聚合:他可以帮你查询指定field 的最大值,最小值,平均值,平方和...
使用 extended_stats
其他聚合:查看官方文档
{
"aggs" : {
"自定义查询名(一般为agg)": {
"聚合类型(cardinality,range,ip_range,extended_stats)" : {
"field": "属性名",
}
}
}
}
-
地图经纬度搜索
ES 的地图检索方式
geo_distance :直线距离检索方式
geo_bounding_box: 以2个点确定一个矩形,获取再矩形内的数据
geo_polygon:以多个点,确定一个多边形,获取多边形的全部数据
{
"query": {
"geo_distance" : {
//确定一个点
"location": {
"lat" : 39.95499,
"lon" : 116.434739
},
//半径长度
"distance": 2000,
//指定形状是圆形
"distance_type": "arc"
},
"geo_bounding_box":{
"location":{
"top_left":{
"lon":116.327805,
"lat":39.95499
},
"bottom_right":{
"lon": 116.363162,
"lat":39.938395
}
}
},
"geo_polygon":{
"location":{
# 指定多个点确定 位置
"points":[{
"lon":116.220296,
"lat":40.075013
},{
"lon":116.346777,
"lat":40.044751
},{
"lon":116.236106,
"lat":39.981533
}]
}
}
}
}
8、通过使用JavaAPI对ES进行操作
// 1.SearchRequest 查询操作/ DeleteByQueryRequest:删除操作/ IndexRequest 新增操作 / UpdateRequest 更新操作
//DeleteByQueryRequest request = new DeleteByQueryRequest(index);
//IndexRequest request = new IndexRequest(index,type,person.getId().toString());
//UpdateRequest request = new UpdateRequest(index,type,"1");
SearchRequest request= new SearchRequest(index);
searchRequest.types(type);
// 2.指定查询条件
SearchSourceBuilder builder = new SearchSourceBuilder();
builder.query(QueryBuilders.matchAllQuery());
//指定scroll信息,过期时间
searchRequest.scroll(TimeValue.timeValueMinutes(1L));
// ES 默认只查询10条数据
builder.size(20);
builder.sort("fee", SortOrder.DESC);
//组合查询
BoolQueryBuilder boolBuilder = QueryBuilders.boolQuery();
boolBuilder.filter(QueryBuilders.termQuery("corpName","海尔智家公司"));
builder.query(boolBuilder);
//高亮查询
HighlightBuilder highlightBuilder = new HighlightBuilder();
highlightBuilder.field("smsContent",10)
.preTags("<font colr='red'>")
.postTags("</font>");
builder.highlighter(highlightBuilder);
//聚合查询 (范围统计)
builder.aggregation(AggregationBuilders.range("agg").field("fee")
.addUnboundedTo(30)
.addRange(30,60)
.addUnboundedFrom(60));
builder.aggregation(AggregationBuilders.extendedStats("agg").field("fee"));
//聚合查询 (去重计数)
builder.aggregation(AggregationBuilders.cardinality("provinceAgg")
.field("province"));
request.source(builder);
//client.index(request, RequestOptions.DEFAULT);
//client.delete(request, RequestOptions.DEFAULT)
//client.update(request, RequestOptions.DEFAULT);
client.search(request, RequestOptions.DEFAULT);
总结
这篇博文是我学习Elasticsearch的笔记,可能对Elasticsearch的知识点分享不够全面细致。任何技术学习的开始,对这个技术的认识都是浅薄的,不可能学习了几天就能获得几年的经验。这边博文只是Elasticsearch入门的第一步,目的就是对Elasticsearch有一个整体的认识和基本的使用,之后的就需要我们在使用中积累经验了。加油吧,少年!!
看到这里了,记得点赞+关注哦!!!谢谢