一、DSL查询语法以及整合JAVA代码使用
以下操作案例均基于上篇的hotel索引库及其数据进行。
1、查询基本语法
GET /indexName/_search
{
"query": {
"查询类型":{
"查询条件":"条件值"
}
}
}
2、查询所有
2.1、DSL语句
#查询所有
GET /hotel/_search
{
"query": {
"match_all": {
}
}
}
2.2、JAVA
//match_all查询所有
@Test
void testMatchAll() throws IOException {
//1.准备Request
SearchRequest request = new SearchRequest("hotel");
//2.准备DSL
request.source().query(QueryBuilders.matchAllQuery());
//3.发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
showResult(response);
}
注:showResult方法是将返回的响应进行解析,代码如下:
private void showResult(SearchResponse response){ //4.解析结果 SearchHits searchHits = response.getHits(); //4.1、查询结果总条数 long value = searchHits.getTotalHits().value; System.out.println("共" + value + "条"); //4.2、查询到的结果数据 SearchHit[] hits = searchHits.getHits(); for (SearchHit hit : hits) { String json = hit.getSourceAsString(); HotelDoc doc = JSON.parseObject(json,HotelDoc.class); System.out.println(doc); } }
下文操作均使用此方法对响应进行解析。
3、全文检索查询
全文检索查询会对用户输入的内容进行分词,常用于搜索框搜索。
3.1、DSL语句
#match查询
GET /hotel/_search
{
"query": {
"match": {
"all": "外滩"
}
}
}
#multi_match查询
#与match查询类似,只不过允许同时查询多个字段
GET /hotel/_search
{
"query": {
"multi_match": {
"query": "外滩如家",
"fields": ["business","name","brand"]
}
}
}
3.2、JAVA
//match查询
@Test
void testMatch() throws IOException {
//1.准备Request
SearchRequest request = new SearchRequest("hotel");
//2.准备DSL
request.source().query(QueryBuilders.matchQuery("all","外滩"));
//3.发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
showResult(response);
}
//multi_match查询
@Test
void testMultiMatch() throws IOException {
//1.准备Request
SearchRequest request = new SearchRequest("hotel");
//2.准备DSL
String[] fields = {"brand", "business", "name"};
request.source().query(QueryBuilders.multiMatchQuery("外滩如家",fields));
//3.发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
showResult(response);
}
4、精确查询
精确查询一般是查找keyword、数值、日期、boolean等类型字段。
- term:根据词条精确值查询
- range:根据值的范围查询
4.1、DSL语句
#精确查询(term精确值)
GET /hotel/_search
{
"query": {
"term": {
"brand": {
"value": "7天酒店"
}
}
}
}
#精确查询(range范围)
GET /hotel/_search
{
"query": {
"range": {
"price": {
"gte": 300,
"lte": 400
}
}
}
}
4.2、JAVA
//精确查询
@Test
void testTerm() throws IOException {
//1.准备Request
SearchRequest request = new SearchRequest("hotel");
//2.准备DSL
request.source().query(QueryBuilders.termQuery("brand","7天酒店"));
//3.发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
showResult(response);
}
//范围查询
@Test
void testRange() throws IOException {
//1.准备Request
SearchRequest request = new SearchRequest("hotel");
//2.准备DSL
request.source().query(QueryBuilders.rangeQuery("price").gte(300).lte(400));
//3.发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
showResult(response);
}
5、地理查询
- geo_bounding_box:查询geo_point值落在某个矩形范围内的所有文档。(不常用)
- geo_distance:查询到指定中心点小于某个距离值的所有文档。(以下操作均针对此查询)
5.1、DSL语句
#地理查询
GET /hotel/_search
{
"query": {
"geo_distance":{
"distance":"3km",
"location":"31.21,121.5"
}
}
}
5.2、JAVA
使用第三方工具获取当前地理位置,发送至后端,后端根据传递的地理位置对酒店距离进行排序后返回。(附近的酒店功能)
//2.3、距离排序
if (params.getLocation() != null && !params.getLocation().equals("")){
request.source().sort(SortBuilders.
geoDistanceSort("location",new GeoPoint(params.getLocation()))
.order(SortOrder.ASC)
.unit(DistanceUnit.KILOMETERS));
}
6、复合查询
6.1、function score:算分函数查询,可以控制文档相关性算分,控制文档排名。
①、DSL语句
#相关性算分(function score查询)
GET /hotel/_search
{
"query": {
"function_score": {
"query": {
"match": {
"all": "外滩"
}
},
"functions": [
{
"filter": {
"term": {
"brand": "如家"
}
}
, "weight": 10
}
],
"boost_mode": "multiply"
}
}
}
②、JAVA案例——对付了广告费的酒店进行排名靠前展示
//2.算分控制
FunctionScoreQueryBuilder functionScoreQuery =
QueryBuilders.functionScoreQuery(
//原始查询,相关性算分的查询
boolQuery,
//function score数组
new FunctionScoreQueryBuilder.FilterFunctionBuilder[]{
//其中的一个function score元素
new FunctionScoreQueryBuilder.FilterFunctionBuilder(
//过滤条件
QueryBuilders.termQuery("isAD",true),
//算分函数
ScoreFunctionBuilders.weightFactorFunction(10)
)
});
request.source().query(functionScoreQuery);
6.2、Boolean Query(复合查询)
①、DSL语句
搜索名字包含“如家”,价格不高于400,在坐标31.21,121.5周围10km范围内的酒店:
#复合查询(Boolean Query)
GET /hotel/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"name": "如家"
}
}
],
"must_not": [
{
"range": {
"price": {
"gt": 400
}
}
}
],
"filter": [
{
"geo_distance": {
"distance": "10km",
"location": {
"lat": 31.21,
"lon": 121.5
}
}
}
]
}
}
}
②、JAVA
//复合查询
@Test
void testBoolean() throws IOException {
//1.准备Request
SearchRequest request = new SearchRequest("hotel");
//2.准备DSL
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
boolQuery.must(QueryBuilders.matchQuery("name","如家"));
boolQuery.mustNot(QueryBuilders.rangeQuery("price").gt(400));
boolQuery.filter(QueryBuilders.geoDistanceQuery("location").distance("10km"));
request.source().query(boolQuery);
//3.发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
showResult(response);
}
二、搜索结果处理以及整合JAVA代码使用
1、排序
elasticsearch支持对搜索结果排序,默认是根据相关度算分(_score)来排序。可以排序字段类型有:keyword类型、数值类型、地理坐标类型、日期类型等。
1.1、DSL语句
查询所有酒店并按照酒店评分降序排列,评分一致时按照酒店价格升序排列。
#排序
GET /hotel/_search
{
"query": {
"match_all": {}
},
"sort": [
{
"score": "desc"
},
{
"price": "asc"
}
]
}
地理坐标排序:
#找到108.94647 , 34.34727 周围的酒店,并升序排序
GET /hotel/_search
{
"query": {
"match_all": {}
},
"sort": [
{
"_geo_distance": {
"location": {
"lat": 34.34727,
"lon": 108.94647
},
"order": "asc",
"unit": "km"
}
}
]
}
1.2、JAVA
//排序
@Test
void testSort() throws IOException {
//1.准备Request
SearchRequest request = new SearchRequest("hotel");
//2.准备DSL
request.source().query(QueryBuilders.matchAllQuery());
request.source().sort("score", SortOrder.DESC);
request.source().sort("price",SortOrder.ASC);
//3.发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
showResult(response);
}
地理坐标排序:
//2.3、距离排序
if (params.getLocation() != null && !params.getLocation().equals("")){
request.source().sort(SortBuilders.
geoDistanceSort("location",new GeoPoint(params.getLocation()))
.order(SortOrder.ASC)
.unit(DistanceUnit.KILOMETERS));
}
2、分页
2.1、DSL语句
#分页查询
GET /hotel/_search
{
"query": {
"match_all": {}
},
"sort": [
{
"price": "asc"
}
],
"from": 20,
"size": 10
}
2.2、JAVA
//分页
@Test
void testLimit() throws IOException {
//1.准备Request
SearchRequest request = new SearchRequest("hotel");
//2.准备DSL
request.source().query(QueryBuilders.matchAllQuery());
request.source().sort("price",SortOrder.ASC);
request.source().from(20);
request.source().size(10);
//3.发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
showResult(response);
}
3、高亮
高亮就是在搜索结果中把搜索关键字突出显示。
3.1、DSL语句
#高亮查询处理
GET /hotel/_search
{
"query": {
"match": {
"all": "如家"
}
},
"highlight": {
"fields": {
"name": {
"require_field_match": "false"
}
}
}
}
3.2、JAVA
//高亮
@Test
void testLight() throws IOException {
//1.准备Request
SearchRequest request = new SearchRequest("hotel");
//2.准备DSL
request.source().query(QueryBuilders.matchQuery("all","如家"));
request.source().highlighter(new HighlightBuilder().field("name").requireFieldMatch(false));
//3.发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
//4.解析结果
SearchHits searchHits = response.getHits();
//4.1、查询结果总条数
long value = searchHits.getTotalHits().value;
System.out.println("共" + value + "条");
//4.2、查询到的结果数据
SearchHit[] hits = searchHits.getHits();
for (SearchHit hit : hits) {
String json = hit.getSourceAsString();
HotelDoc doc = JSON.parseObject(json,HotelDoc.class);
//获取高亮结果
Map<String, HighlightField> highlightFields = hit.getHighlightFields();
if (!CollectionUtils.isEmpty(highlightFields)){
//根据字段名获取高亮结果
HighlightField highlightField = highlightFields.get("name");
if (highlightField != null){
//获取高亮值
String name = highlightField.getFragments()[0].toString();
//覆盖非高亮结果
doc.setName(name);
}
}
System.out.println(doc);
}
}