ElasticSearch 用的最多的地是他的查询,统计,还有就是地理信息这块。在项目中我用的到的比较多的是查询和统计。
目录
查询关键字:
- term 精确查询
- match 匹配查询
Match 匹配查询
match查询属于全文查询,它会首先分析查询字符串,根据字符串的分词构建查询,最终返回查询结果。
匹配查询一共包括三种类型:
- 布尔(默认)
- 短语
- 前缀
布尔查询 match
对字符串进行分词,将满足分词的文档查询出来,举例:
{
"query":{
"match":{
"eventname":"azure aws cloud"
}
}
}
eventname是字段名,此字段可以匹配包含azure,aws或者cloud的文档。
match 还有两个查询参数,用于设定匹配条件。
- operator
- minimum_should_match
{
"query":{
"match":{
"eventname":{
"query":"azure aws cloud security",
"operator":"or",
"minimum_should_match":2
}
}
}
}
operator可以为or或者and or代表满足任意一个分词结果 and 代表同时包括所有的分词结果。
minimus_should_match指定operator为or时,最少匹配的数量。
以上示例代表,只要文档至少包含[azure,aws,cloud,security] 中的2个 就可以完成匹配。
MatchQueryBuilder matchQueryBuilder = new MatchQueryBuilder("字段名称","字段值");
matchQueryBuilder.operator(Operator.AND);
matchQueryBuilder.minimumShouldMatch("2");
短语查询 match_phrase
对字符串进行分词,从分析后的文本中构建短语。意思就是必须匹配短语中的所有分词且要保证各个分词位置不变。举例
{
"query":{
"match_phrase":{
"eventname":"Open Source"
}
}
}
短语前缀查询 match_phrase_prefix
短语前缀查询和短语查询几乎一样,区别在于,短语前缀查询的最后一个分词,做了前缀匹配。
{
"query":{
"match_phrase_prefix":{
"eventname":{
"query":"Open Source hac",
"max_expansions":50
}
}
}
}
以上示例,匹配的文档例如:[Open Source Hack Night,Open Source Hack GOD]
max_expansions 控制参数默认是50,代表的是通配符数目
Term 精确查询
精确查询 term和match查询不同,它不会关联分数,不会走分词分析。他会精确匹配短语,适用的字段为keyword fields, or in numeric or date fields
{
"query": {
"term": {
"exact_value": "Quick Foxes!"
}
}
}
精确匹配 exact_value值为quick foxes!的
Term匹配和Match匹配,查询结果对比:
1.构造实例
PUT my_index
{
"mappings": {
"_doc": {
"properties": {
"full_text": {
"type": "text"
},
"exact_value": {
"type": "keyword"
}
}
}
}
}
PUT my_index/_doc/1
{
"full_text": "Quick Foxes!",
"exact_value": "Quick Foxes!"
}
2.构造查询
GET my_index/_search
{
"query": {
"term": {
"exact_value": "Quick Foxes!"
}
}
}
GET my_index/_search
{
"query": {
"term": {
"full_text": "Quick Foxes!"
}
}
}
GET my_index/_search
{
"query": {
"term": {
"full_text": "foxes"
}
}
}
GET my_index/_search
{
"query": {
"match": {
"full_text": "Quick Foxes!"
}
}
}
1.可以精确查找到exact_value 值为Quick Foxes!的。
2.匹配不到,因为full_text不是关键字类型。
3.可以匹配到full_text分词后包含foxes的。
4.可以匹配至少包含[quick,foxes]中其一的。
排序
根据年龄 日期 es字段(_score)进行排序
{
"sort": [
{
"date": "desc"
},
{
"age": "desc"
},
"_score"
],
"query": {
"term": {
"name": "李四"
}
}
}
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
SortBuilder sortBuilder = SortBuilders.fieldSort("字段名称").order(SortOrder.DESC);
searchSourceBuilder.sort(sortBuilder);
分页查询
{
"from":0,
"size":10,
"query": {
"match": {
"full_text": "Quick Foxes!"
}
}
}
分页查询三种方式的优缺点
分页方式 | 说明 | 优点 | 缺点 | 使用场景 |
---|---|---|---|---|
from+size | 假设现在你要查询第100页的10条数据,但是对于es来说,from=1000000,size=100,这时 es需要从各个分片上查询出来10000100条数据,然后汇总计算后从其中取出100条。如果有5个分片则需要查询出来5*10000100条数据。 | 灵活性好,使用简单 | 内存消耗大 | 数据量小 |
scroll | scroll查询原理是在第一次查询的时候一次性生成一个快照,根据上一次的查询的id来进行下一次的查询,这个就类似于关系型数据库的游标,然后每次滑动都是根据产生的游标id进行下一次查询,这种性能比上面说的分页性能要高出很多,基本都是毫秒级的。 注意:scroll不支持跳页查询。 | 效率高, | 对实时性要求不高的查询,例如微博或者头条滚动查询。报表导出 |
条件查询
条件查询需要配合 match和term结合使用
- fiflter 会缓存结果,不会关联分数
- must/must_not 不会缓存结果,会关联分数(分数指文档的匹配度,分数越高 越匹配)
简单举例:
{
"query": {
"bool": { @1
"must": [@2
{ "match": { "title": "Search" }},
{ "match": { "content": "Elasticsearch" }}
],
"filter": [ @3
{ "term": { "status": "published" }},
{ "range": { "publish_date": { "gte": "2015-01-01" }}}
]
}
}
}
@2 使用query context,意味着他们会返回score来表达匹配结果
@3 使用fiflter context, 意味着会过滤不匹配的文档
fiflter和range的结合,可以用来做范围查询,比如时间或者数值大小
统计
在实际项目中,主要应用到的是日期统计。比如统计每个月接口的成功数量,失败数量。
也有其他的统计维度,比如统计接口出错的Top10。等等
时间统计
POST /sales/_search?size=0 //size 0 不返回文档内容 只显示统计结果
{
"aggs" : {
"sales_over_time" : {//这个统计自己起的名字
"date_histogram" : {//使用date_histogram关键字
"field" : "date",//参数
"interval" : "1M",//时间维度
"format" : "yyyy-MM-dd" //格式化
}
}
}
}
Response:
{
...
"aggregations": {
"sales_over_time": {
"buckets": [
{
"key_as_string": "2015-01-01",
"key": 1420070400000,
"doc_count": 3
},
{
"key_as_string": "2015-02-01",
"key": 1422748800000,
"doc_count": 2
},
{
"key_as_string": "2015-03-01",
"key": 1425168000000,
"doc_count": 2
}
]
}
}
}
Java 代码:
DateHistogramAggregationBuilder dateBuilder = AggregationBuilders.dateHistogram("sales_over_time").field("date").format("yyyy-MM-dd").dateHistogramInterval(DateHistogramInterval.DAY);
//指定根据key(日期)进行排序
dateBuilder.order(BucketOrder.key(true));
数值统计
举例:统计衬衫的平均值
POST /sales/_search?size=0
{
"aggs" : {
"t_shirts" : {//第一层 衬衫分组
"filter" : { "term": { "type": "t-shirt" } },
"aggs" : {//第二层 平均值 子统计查询
"avg_price" : { "avg" : { "field" : "price" } }
}
}
}
}
Response:
{
...
"aggregations" : {
"t_shirts" : {
"doc_count" : 3,
"avg_price" : { "value" : 128.33333333333334 }
}
}
}
Java代码:
TermQueryBuilder termQueryBuilder = new TermQueryBuilder("type","t-shirt");
AggregationBuilders.filter("t_shirts",termQueryBuilder).subAggregation(AggregationBuilders.avg("avg_price").field("field"));