SpringCloud学习路线(11)——分布式搜索ElasticSeach场景使用

这篇具有很好参考价值的文章主要介绍了SpringCloud学习路线(11)——分布式搜索ElasticSeach场景使用。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、DSL查询文档

(一)DSL查询分类

ES提供了基于JSON的DSL来定义查询。

1、常见查询类型:

  • 查询所有: 查询出所有的数据,例如,match_all
  • 全文检索(full text)查询: 利用分词器对用户输入内容分词,然后去倒排索引库中匹配。例如:
    • match_query
    • multi_match_query
  • 精确查询: 根据精确词条值查找数据,一般查找精确值,例如:
    • ids
    • range
    • term
  • 地理(geo)坐标查询: 根据经纬度查询,例如:
    • geo_distance
    • geo_bounding_box
  • 复合(compound)查询: 复合查询可以将伤处查询条件组合起来,合并查询条件,例如:
    • bool
    • function_score

2、查询的基本语法

GET /indexName/_search
{
	"query": {
		"查询类型": {
			"查询条件": "条件值"
		}
	}
}

3、match_all的使用

GET /indexName/_search
{
	"query": {
		"match_all": { }
	}
}

查询效果

{
  "took" : 446,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "test",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 1.0,
        "_source" : {
          "info" : "这是我的ES拆分Demo",
          "age" : 18,
          "email" : "zengoo@163.com",
          "name" : {
            "firstName" : "Zengoo",
            "lastName" : "En"
          }
        }
      }
    ]
  }
}

(二)全文检索查询

全文检索查询,会对用户输入内容分词,常用于搜索框搜索。

1、match查询

(1)结构

GET /indexName/_search
{
	"query": {
		"match": { 
			"FILED": "TEXT"
		}
	}
}

(2)简单使用

GET /test/_search
{
	"query": {
		"match": { 
		  "info": "ES"  #当有联合属性all,进行匹配,就可以进行多条件匹配,按照匹配数量来确定权值大小。
		}
	}
}

使用结果

{
  "took" : 71,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 0.2876821,
    "hits" : [
      {
        "_index" : "test",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 0.2876821,
        "_source" : {
          "info" : "这是我的ES拆分Demo",
          "age" : 18,
          "email" : "zengoo@163.com",
          "name" : {
            "firstName" : "Zengoo",
            "lastName" : "En"
          }
        }
      }
    ]
  }
}

2、multi_match查询

从使用效果上,与条件查询的"all"字段相同。

(1)结构

GET /indexName/_search
{
	"query": {
		"multi_match": { 
			"query": "TEXT",
			"fields": ["FIELD1", "FIELD2"]
		}
	}
}

(2)简单使用

GET /test/_search
{
  "query": {
    "multi_match": {
      "query": "ES",
      "fields": ["info","age"]
    }
  }
}

(三)精准查询

精确查询一般是查找精确值,所以不会对搜索条件分词。

1、term: 根据词条精确值查询,在商城项目中,通常会用在类型筛选上。

(1)结构

GET /test/_search
{
  "query": {
    "term": {
      "FIELD": {
        "value": "VALUE"
      }
    }
  }
}

(2)简单使用

GET /test/_search
{
  "query": {
    "term": {
      "city": {
        "value": "杭州" #精确值
      }
    }
  }
}

2、range: 根据值范围查询,在商城项目中,通常会用在价值筛选上。

(1)结构

GET /test/_search
{
  "query": {
    "range": {
      "FIELD": {
        "gte": 10,
        "lte": 20
      }
    }
  }
}

(2)简单使用

GET /test/_search
{
  "query": {
    "range": {
      "price": {
        "gte": 699, #最低值,gte 大于等于,gt 大于
        "lte": 1899 #最高值,lte 小于等于,lt 小于
      }
    }
  }
}

(四)地理坐标查询

1、geo_distance: 查询到指定中心小于某个距离值的所有文档(圆形范围圈)。

(1)结构

GET /indexName/_search
{
  "query": {
    "geo_distance": {
    	"distance": "15km",
     	"FIELD": "13.21,121.5"
    }
  }
}

(2)简单使用

GET /test/_search
{
  "query": {
    "geo_distance": {
    	"distance": "20km",
     	"location": "13.21,121.5"
    }
  }
}

2、geo_bounding_box: 查询geo_point值落在某个举行范围的所有文档(矩形范围圈)。

(1)结构

GET /indexName/_search
{
  "query": {
    "geo_bounding_box": {
      "FIELD": {
        "top_left": {
          "lat": 31.1,
          "lon": 121.5
        },
        "bottom_right": {
          "lat": 30.9,
          "lon": 121.7
        }
      }
    }
  }
}

(五)复合查询

复合查询可以将其它简单查询组合起来,实现更复杂的搜索逻辑。

1、function score: 算分函数查询,可以控制文档相关性算分,控制文档排名。

当我们利用match查询时,文档结果会根据搜索词条的关联度打分(_score),返回结果时按照分值降序排列。
例如,在搜索CSDNJava。

[
	{
		"_score": 17.85048,
		"_source": {
			"name": "Java语法菜鸟教程"
		}
	},
	{
		"_score": 12.587963,
		"_source": {
			"name": "Java语法W3CScool"
		}
	},
	{
		"_score": 11.158756,
		"_source": {
			"name": "CSDNJava语法学习树"
		}
	},
]

相关算法:

  • 最开始的算分算法:TF(词条频率) = 词条 / 文档词条总数
  • 避免公共词条改良的算分算法:TF-IDF算法
    • IDF(逆文档频率) = Log( 文档总数 / 包含词条的文档总数 )
    • socre = (∑(i,n) TF) * IDF
  • BM25算法: 现在默认采用的算法,该算法比较复杂,其词频曲度最终会趋于水平。

(1)结构

GET /hotel/_search
{
	"query": {
		"function_socre": {    #查询类型
			"query": {  #查询原始数据
				"match": {
					"all": "外滩"
				}
			},
			"functions": [  #解析方法
				{
					"filter": {     # 过滤条件
						"term": {
							"id": "1"
						}
					},
					"weight": 10  # score算分方法,weight是直接以常量为函数结果,其它的还有feild_value_factor:以某字段作为函数结果,random_score: 随机值作为函数结果,script_score:定义计算公式
				}
			],
			"boost_mode": "multiply"  # 加权模式,定义function score 与 query score的运算方式,包括 multiply:两者相乘(默认);replace:用function score 替换 query score;其它: sum、avg、max、min
		}
	}
}

(2)简单使用

需求: 将用户给的词条排名靠前

需要考虑的元素:

  • 哪些文档需要算分加权 : 包含词条内容的文档
  • 算分函数是什么: weight
  • 加权模式用哪个: sum

实现:

GET /hotel/_search
{
	"query": {
		"function_socre": {	# 算分算法
			"query": {
				"match": {
					"all": "速8快捷酒店"
				}
			},
			"functions": [ 
				{
					"filter": {	# 满足条件,品牌必须是速8
						"term": {
							"brand": "速8"
						}
					},
					"weight": 2  #算分权重为 2
				}
			],
			"boost_mode": "sum"
		}
	}
}

2、复合查询 Boolean Query

子查询的组合方式:

  • must: 必须匹配每个子查询,类似 “与”
  • should: 选择性匹配子查询,类似 “或”
  • must_not: 排除匹配模式,不参与算分,类似 “非”
  • filter: 必须匹配,不参与算分

实现案例

#搜查位置位于上海,品牌为“皇冠假日”或是“华美达”,并且价格500<price<600元,且评分大于等于45的酒店
GET /hotel/_search
{
	"query": {
		"bool": {
			"must": [	# 必须匹配的条件
				{ "term": { "city: "上海" } }
			],
			"should": [	# 可以匹配到条件
				{ "term": { "brand": "皇冠假日" } },
				{ "term": { "brand": "华美达" } }
			],
			"must_not": [	#不匹配的条件
				{ "range": { "price": {"lte": 500, "gte": 600} }}
			],
			"filter": [	#筛选条件
				{ "range": { "score": { "gte": 45 } } }
			]
		}	
	}
}

二、搜索结果处理

(一)排序

ES支持对搜索结果排序,默认根据(_score)来排序,可以排序的字段类型有:keyword、数值类型、地理坐标类型、日期类型等

1、结构:

# 普通类型排序
GET /test/_search
{
  "query": {
    "match_all": {}
  },
  "sort": [
    {
      "FIELD": {
        "order": "desc"		# 排序字段和排序方式ASC、DESC
      }
    }
  ]
}

# 地理坐标型排序
GET /test/_search
{
  "query": {
    "match_all": {}
  },
  "sort": [
    {
      "_geo_distance": {
        "FIELD": {  #精度维度
          "lat": 40,
          "lon": -70
        },
        "order": "asc",
        "unit": "km"
      }
    }
  ]
}

2、实现案例

排序需求: 按照用户评价降序,评价相同的按照价格升序。

GET /hotel/_search
{
  "query": {
    "match_all": {}
  },
  "sort": [
    {
      "score": {  # 简化结构可以使用,"score": "desc"
        "order": "desc"
      },
      "price": {
        "order": "asc"
      }
    }
  ]
}

排序需求: 按照距离用户位置的距离进行升序。

GET /hotel/_search
{
  "query": {
    "match_all": {}
  },
  "sort": [
    {
      "_geo_distance": {
        "location": {
          "lat": 40.58489,
          "lon": -70.59873
        },
        "order": "asc",
        "unit": "km"
      }
    }
  ]
}

(二)分页

修改分页参数

GET /hotel/_search
{
  "query": {
    "match_all": {}
  },
  "sort": [
    {
      "price": "asc"
    }
  ],
  "from": 100,	#	分页开始的位置,默认为0
  "size": 20,	#	期望获取的文档总数
}

深度分页问题

当我们将ES做成一个集群服务,那么我们需要选择前10的数据时,ES底层会如何去实现呢?

ES由于使用的是倒排索引,每一台ES都会分片数据。

1、每个数据分片上都排序并查询前1000条文档。

2、聚合所有节点的结果,在内存中重新排序选出前1000条文档。

3、从前1000挑中,选取from=990,size=10的文档

如果搜索页数过深,或者结果集过大,对内存和CPU的消耗越高,因此ES设置的结果集查询上限是10000条。

如何解决深度分页的问题?

  • seach after: 分页时需要排序,原理是从上一次的排序值开始,查询下一页数据(官方推荐)。
  • scroll: 原理是将排序数据形成缓存保存在内存(官方不推荐)。

(三)高亮

1、概念: 在搜索结果中搜索关键字突出显示。

2、原理

  • 将搜索结果中的关键字用标签标记出来
  • 在页面中给标签添加css样式

3、语法:

GET /indexName/_search
{
 "query": {
   "match": {
     "FIELD": "TEXT"
   }
 },
 "highlight": { 	#高亮字段
   "fields": {
     "FIELD": {
       "pre_tags": "<em>",  	#标签前缀
       "post_tags": "</em>", 	#标签后缀
       "require_field_match": "false"	#判断该字段是否与前面查询的字段匹配
     }
   }
 }
}

三、RestClient查询文档

(一)实现简单查询案例

//1、准备Request
SearchRequest request = new SearchRequest("hotel");
//2、组织DSL参数,QueryBuilders是ES的查询API库
request.source().query(QueryBuilders.matchAllQuery());
//3、发送请求,得到响应结果
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
//4、解析响应结果,搜索结果会放置在Hits集合中
SearchHits searchHits = response.getHits();
//5、查询总数
long total = searchHits.getTotalHits().value;
//6、查询的结果数组
SearchHit[] hits = searchHits.getHits();
for(SearchHit hit: hits) {
	//得到source,source就是查询出来的实体信息
	String json = hit.getSourceAsString();
	//序列化
	HotelDoc hotelDoc = JSON.parseObject(json,HotelDoc.class);
}

(二)match查询


//1、准备Request
SearchRequest request = new SearchRequest("hotel");
//2、组织DSL参数,QueryBuilders是ES的查询API库
//单字段查询
request.source().query(QueryBuilders.matchQuery("all","皇家"));
//多字段查询
//request.source().query(QueryBuilders.multiMatchQuery("皇家","name","buisiness"));
//3、发送请求,得到响应结果
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
//4、解析响应结果,搜索结果会放置在Hits集合中
SearchHits searchHits = response.getHits();
//5、查询总数
long total = searchHits.getTotalHits().value;
//6、查询的结果数组
SearchHit[] hits = searchHits.getHits();
for(SearchHit hit: hits) {
	//得到source,source就是查询出来的实体信息
	String json = hit.getSourceAsString();
	//序列化
	HotelDoc hotelDoc = JSON.parseObject(json,HotelDoc.class);
}

(三)精确查询

//词条查询
QueryBuilders.termQuery("city","杭州");
//范围查询
QueryBuilders.rangeQuery("price").gte(100).lte(150);

(四)复合查询

//创建布尔查询
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
//添加must条件
boolQuery.must(QueryBuilders.termQuery("city","杭州"));
//添加filter条件
boolQuery.filter(QueryBuilders.rangeQuery("price").lte(250));

(五)排序、分页、高亮

1、排序与分页

// 查询
request.source().query(QueryBuilders.matchAllQuery());
// 分页配置
request.source().from(0).size(5);
// 价格排序
request.source().sort("price", SortOrder.ASC);

2、高亮

高亮查询请求

request.source().highlighter(new HighLightBuilder().field("name").requireFieldMatch(false));

处理高亮结果文章来源地址https://www.toymoban.com/news/detail-604513.html

// 获取source
HotelDoc hotelDoc = JSON.parseObject(hit.getSourceAsString(), HotelDoc.class);
// 处理高亮
Map<String, HighlightFields> highlightFields = hit.getHighlightFields();
if(!CollectionUtils.isEmpty(highlightFields)) {
	// 获取字段结果
	HighlightField highlightField = highlightFields.get("name");
	if (highlightField != null) {
		// 去除高亮结果数组的第一个
		String name = highlightField.getFragments()[0].string();
		hotelDoc.setName(name);
	}
}

到了这里,关于SpringCloud学习路线(11)——分布式搜索ElasticSeach场景使用的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • SpringCloud系列(十六)[分布式搜索引擎篇] - DSL 查询及相关性算分的学习 (部分)

    在SpringCloud系列(十五)[分布式搜索引擎篇] - 结合实际应用场景学习并使用 RestClient 客户端 API这篇文章中我们已经对 RestClient 有了初步的了解, 并且已经将一些数据进行了存储, 但是这并不是我们学习 ElasticSearch 的目的, ElasticSearch 最擅长的还是对数据的搜索及分析, 因此本篇

    2024年02月17日
    浏览(47)
  • 【Springcloud】分布式搜索elasticsearch

    先看下翻译: elasticsearch是一款非常强大的 开源搜索引擎 ,可以帮助我们 从海量数据中快速找到需要的内容 以下是生活中ES的使用场景: 项目在运行的时候会产生海量的日志信息,而elasticsearch结合kibana、Logstash、Beats,也就是elastic stack( ELK ),即ELK技术栈。被广泛应用在

    2024年02月08日
    浏览(41)
  • 微服务技术栈SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式(五):分布式搜索 ES-下

    聚合(aggregations)可以实现对文档数据的统计、分析、运算。聚合常见的有三类: 桶(Bucket)聚合:用来对文档做分组 TermAggregation:按照文档字段值分组 Date Histogram:按照日期阶梯分组,例如一周为一组,或者一月为一组 度量(Metric)聚合:用以计算一些值,比如:最大值

    2024年03月26日
    浏览(65)
  • Springcloud中间件-----分布式搜索引擎 Elasticsearch

    该笔记是根据黑马程序员的课来自己写了一遍的,b站有对应教程和资料 第一部分 第二部分 第三部分 预计看完跟着练习5小时足够 1.1.1.elasticsearch的作用 elasticsearch是一款非常强大的开源搜索引擎,具备非常多强大功能,可以帮助我们从海量数据中快速找到需要的内容 例如:

    2024年02月08日
    浏览(60)
  • SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈

    我们发现在微服务中有一个令人头疼的问题——部署,用Docker去解决这个部署难题 1、项目部署的问题 2、Docker 扔到一台机器上,它们的依赖难道没有干扰吗?不会,docker将打包好的程序放到一个隔离容器去运行,使用沙箱机制,避免互相干扰,之间不可见,这样就解决了混

    2023年04月24日
    浏览(46)
  • (黑马出品_07)SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式

    [此文档是在心向阳光的天域的博客加了一些有助于自己的知识体系,也欢迎大家关注这个大佬的博客](https://blog.csdn.net/sinat_38316216/category_12263516.html) [是这个视频](https://www.bilibili.com/video/BV1LQ4y127n4/?p=5spm_id_from=pageDrivervd_source=9beb0a2f0cec6f01c2433a881b54152c) 聚合 可以让我们极其方便

    2024年03月12日
    浏览(56)
  • (黑马出品_高级篇_04)SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式

    [此文档是在心向阳光的天域的博客加了一些有助于自己的知识体系,也欢迎大家关注这个大佬的博客](https://blog.csdn.net/sinat_38316216/category_12263516.html) [是这个视频](https://www.bilibili.com/video/BV1LQ4y127n4/?p=5spm_id_from=pageDrivervd_source=9beb0a2f0cec6f01c2433a881b54152c) 消息队列在使用过程中,面

    2024年03月19日
    浏览(48)
  • Redis学习路线(6)—— Redis的分布式锁

    一、分布式锁的模型 (一)悲观锁: 认为线程安全问题一定会发生,因此在操作数据之前先获取锁,确保线程串行执行。例如Synchronized、Lock都属于悲观锁。 优点: 简单粗暴 缺点: 性能略低 (二)乐观锁: 认为线程安全问题不一定会发生,因此不加锁,只有在更新数据时

    2024年02月14日
    浏览(37)
  • SpringCloud分布式搜索引擎、数据聚合、ES和MQ的结合使用、ES集群的问题

    目录 数据聚合 聚合的分类 ​编辑 DSL实现Bucket聚合 ​编辑  DSL实现Metrics聚合​编辑 RestAPI实现聚合  对接前端接口​编辑  自定义分词器​编辑 Completion suggester查询 Completion suggester查询 酒店数据自动补全 实现酒店搜索框界面输入框的自动补全  数据同步问题分析​编辑 同

    2024年02月16日
    浏览(49)
  • 微服务学习——分布式搜索

    elasticsearch是一款非常强大的开源搜索引擎,可以帮助我们从海量数据中快速找到需要的内容。 elasticsearch结合kibana、Logstash、Beats,也就是elastic stack(ELK)。被广泛应用在日志数据分析、实时监控等领域。 elasticsearch是elastic stack的核心,负责存储、搜索、分析数据。 Lucene是一个

    2024年02月03日
    浏览(38)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包