ElasticSearch高级功能的使用(模版查询、地理位置查询等)

10 篇文章 1 订阅
9 篇文章 2 订阅

 一、搜索模板Search Template

搜索模板,search template,高级功能,就可以将我们的一些搜索进行模板化,每次执行这个搜索直接调用模板,传入一些参数就可以了。

类似于mysql的存储过程。

1.1 模版入门-固定参数模版

这种平常我们一般不会使用,不可重复利用

1.1.1 参数替换

# cars为索引库;template代表模版搜索
GET /cars/_search/template
{
  "source": {
    "query": {
      "match": {
        # 定义模版参数kw
        "remark": "{{kw}}"
      }
    },
    # 定义模版参数kw
    "size": "{{size}}"
  },
  # 传入模版参数
  "params": {
    "kw": "大众",
    "size": 2
  }
}


# 上述等同于
GET /cars/_search
{
    "query": {
      "match": {
        # 定义模版参数kw
        "remark": "大众"
      }
    },
    # 定义模版参数kw
    "size": 2
}

1.1.2 toJson方式传递参数

{{#toJson}}参数名称{{/toJson}}

因为中间使用了{{#toJson}}标签所以并不能为JSON所解析,所以需要转换成字符串形式。

GET cars/_search/template
{
  # {toJson}}相当于封闭符号;parameter相当于参数名称
  "source": "{ \"query\": { \"match\": {{#toJson}}parameter{{/toJson}} }}",
  "params": {
    # 给parameter参数赋值
    "parameter" : {
      # 相当于 {"query": 
      #            { "match": 
      #                {"remarck":"大众"}
      #            }
      #        }
      "remark" : "大众"
    }
  }
}

# 上述等同于
GET /cars/_search
{
  "query": {
    "match": {
      "remarck":"大众"
    }
  }
}

1.1.3 join方式传递参数

GET cars/_search/template
{
  "source": {
    "query": {
      "match": {
        # 参数值空格隔开
        "remark": "{{#join delimiter=' '}}kw{{/join delimiter=' '}}"
      }
    }
  },
  "params": {
    "kw": [
      "大众",
      "标致"
    ]
  }
}

# 上述等同于
GET /cars/_search
{
  "query": {
    "match": {
      "remark":"大众 标致"
    }
  }
}

1.1.4 搜索模板的默认值设置 default value

可以对搜索模板进行一些默认值的设置,如{{^end}}200000表示如果end参数为空,默认值为200000

GET cars/_search/template
{
  "source": {
    "query": {
      "range": {
        "price": {
          "gte": "{{start}}",
          "lte": "{{end}}{{^end}}200000{{/end}}"
        }
      }
    }
  },
  "params": {
    "start": 100000
  }
}

1.2 template实现重复调用

上述模版都是在创建时候就把参数固定了,不是我们常用的方式,我们希望在我们使用的时候再确定参数,从而根据我们传入的参数查询出我们期望的结果。

ES中实现了mustache语言。因此,搜索模板遵循脚本文档中描述的设置,然后通过键值对来替换模板中的变量。把脚本存储在本地磁盘中,默认的位置为:elasticsearch\config\scripts,通过引用脚本名称进行使用。

1.2.1 保存template到ES

# test是模版名称
POST _scripts/test
{
  "script": {
    # mustache语言
    "lang": "mustache",
    "source": {
      "query": {
        "match": {
          "remark": "{{kw}}"
        }
      }
    }
  }
}

1.2.2 调用template执行搜索

GET cars/_search/template
{
  # 调用模版名称为test的模版
  "id": "test",
  # 传入参数kw
  "params": {
    "kw": "大众"
  }
}

1.2.3 查询已定义的template

# 查询test模版信息
GET _scripts/test

1.2.4 删除已定义的template

# 删除test模版
DELETE _scripts/test

二、搜索建议Suggest Search(Completion Suggest)

suggest search(completion suggest):就是建议搜索或称为搜索建议,也可以叫做自动完成-auto completion。类似百度中的搜索联想提示功能,在搜索框中查找字段,会很快的返回用户的可能希望得到的数据,由于用户每次输入都会发送查询请求,所以对查询速度要求很高,ES 中使用suggest search来对建议搜索进行优化。

ES实现suggest的时候,性能非常高,其构建的不是倒排索引,也不是正排索引,就是纯的用于进行前缀搜索的一种特殊的数据结构,而且会全部放在内存中,所以suggest search进行的前缀搜索提示,性能是非常高。

和之前的前缀搜索有点像,但是底层原理实现是不一样的,前缀搜索是基于倒排索引的的,而这个是基于内存实现的。

需要使用suggest的时候,必须在定义index时,为其mapping指定开启suggest。具体如下:

PUT /movie
{
  "mappings": {
    "properties": {
      "title": {
        "type": "text",
        "analyzer": "ik_max_word",
        # 设置类似于子字段的一个字段suggest
        "fields": {
          "suggest": {
            # 类型设置为completion
            "type": "completion",
            "analyzer": "ik_max_word"
          }
        }
      },
      "content": {
        "type": "text",
        "analyzer": "ik_max_word"
      }
    }
  }
}

PUT /movie/_doc/1
{
  "title": "西游记电影系列",
  "content": "西游记之月光宝盒将与2021年进行......"
}

PUT /movie/_doc/2
{
  "title": "西游记文学系列",
  "content": "某知名网络小说作家已经完成了大话西游同名小说的出版"
}

PUT /movie/_doc/3
{
  "title": "西游记之大话西游手游",
  "content": "网易游戏近日出品了大话西游经典IP的手游,正在火爆内测中"
}

suggest 搜索:

GET /movie/_search
{
  "suggest": {
    "my-suggest": {
      "prefix": "西游记",
      "completion": {
        "field": "title.suggest"
      }
    }
  }
}

使用suggest search会大大的提升搜索的速度,但是也会增大索引在内存中的占用。所以使用时要进行评估,在资源比较充裕时使用,或者出现性能问题的时候可以再考虑使用。

三、geo point - 地理位置搜索和聚合分析

ES支持地理位置的搜索和聚合分析,可实现在指定区域内搜索数据、搜索指定地点附近的数据、聚合分析指定地点附近的数据等操作。

ES中如果使用地理位置搜索的话,必须提供一个特殊的字段类型: geo_point,地理位置的坐标点。

3.1 定义geo_point mapping

PUT /hotel_app
{
  "mappings": {
    "properties": {
      "pin": {
        "type": "geo_point"
      },
      "name": {
        "type": "text",
        "analyzer": "ik_max_word"
      }
    }
  }
}

3.2 录入数据

新增一个基于geo point类型的数据,可以使用多种方式。

多种类型描述geo_point类型字段的时候,在搜索数据的时候,显示的格式和录入的格式是统一的。不影响搜索。

数据范围要求:纬度范围是-90~90之间,经度范围是-180~180之间。经纬度数据都是浮点数或数字串(数字组成的字符串),最大精度:小数点后7位。(常用小数点后6位即可。)

3.2.1 基于对象:latitude:纬度、longitude:经度

语义清晰,建议使用

PUT /hotel_app/_doc/1
{
  "name": "七天连锁酒店",
  "pin": {
    "lat": 40.12,
    "lon": -71.34
  }
}

3.2.2 基于字符串:依次定义纬度、经度

不推荐使用

PUT /hotel_app/_doc/2
{
    "name": "维多利亚大酒店",
    "pin" : "40.99, -70.81"
}

3.2.3 基于数组:依次定义经度、纬度

不推荐使用

PUT /hotel_app/_doc/3
{
    "name": " 红树林宾馆",
    "pin" : [40, -73.81]
}

3.3 搜索指定区域范围内的数据

3.3.1 搜索矩形范围内的数据geo_bounding_box

矩形范围搜索:传入的top_left和bottom_right坐标点是有固定要求的。地图中以北作为top,南作为bottom,西作为left,东作为right。也就是top_left应该从西北向东南。Bottom_right应该从东南向西北。Top_left的纬度应该大于bottom_right的纬度,top_left的经度应该小于bottom_right的经度。(由两个点确定的矩形区域)

GET /hotel_app/_doc/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match_all": {}
        }
      ],
      "filter": {
        "geo_bounding_box": {
          "pin": {
            "top_left": {
              "lat": 41.73,
              "lon": -74.1
            },
            "bottom_right": {
              "lat": 40.01,
              "lon": -70.12
            }
          }
        }
      }
    }
  }
}

GET /hotel_app/_doc/_search
{
  "query": {
    "constant_score": {
      "filter": {
        "geo_bounding_box": {
          "pin": {
            "top_left": {
              "lat": -70,
              "lon": 39
            },
            "bottom_right": {
              "lat": -75,
              "lon": 41
            }
          }
        }
      }
    }
  }
}

# 使用query方式查询
GET /hotel_app/_doc/_search
{
  "query": {
    "geo_bounding_box": {
      "pin": {
        "top_left": {
          "lat": 41.73,
          "lon": -74.1
        },
        "bottom_right": {
          "lat": 40.01,
          "lon": -70.12
        }
      }
    }
  }
}

3.3.2 搜索多边形范围内的数据geo_polygon

指定多个点,然后多个点连接组成的区域

GET /hotel_app/_doc/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match_all": {}
        }
      ],
      "filter": {
        "geo_polygon": {
          "pin": {
            "points": [
              {
                "lat": 40.73,
                "lon": -74.1
              },
              {
                "lat": 40.01,
                "lon": -71.12
              },
              {
                "lat": 50.56,
                "lon": -90.58
              }
            ]
          }
        }
      }
    }
  }
}

3.3.3 搜索某地点附近的数据geo_distance

这个搜索在项目中更加常用,类似附近搜索功能。

distance距离的单位,常用的有米(m)和千米(km)。

建议使用filter来过滤geo_point数据,因为geo_point数据相关度评分计算比较耗时,使用query来搜索geo_point数据效率相对会慢一些,建议使用filter。

GET /hotel_app/_doc/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match_all": {}
        }
      ],
      "filter": {
        "geo_distance": {
          "distance": "200km",
          "pin": {
            "lat": 40,
            "lon": -70
          }
        }
      }
    }
  }
}

GET hotel_app/_search
{
  "query": {
    "geo_distance": {
      "distance": "90km",
      "pin": {
        "lat": 40.55,
        "lon": -71.12
      }
    }
  }
}

3.3.4 统计某位置附近区域内的数据

聚合统计分别距离某位置80英里,80-300英里,300-1000英里范围内的数据数量。

geo_distance:代表以圆的形式做统计

origin:原始位置(以某一个点为圆心)

unit是距离单位,常用单位有:米(m),千米(km),英里(mi)

distance_type是统计算法:sloppy_arc默认算法、arc最高精度、plane最高效率

GET /hotel_app/_doc/_search
{
  "size": 0,
  "aggs": {
    "agg_by_pin": {
      "geo_distance": {
        "distance_type": "arc",
        "field": "pin",
        "origin": {
          "lat": 40,
          "lon": -70
        },
        "unit": "mi",
        "ranges": [
          {
            "to": 80
          },
          {
            "from": 80,
            "to": 300
          },
          {
            "from": 300,
            "to": 1000
          }
        ]
      }
    }
  }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Elasticsearch使用深度分页功能需要注意以下几点: 1. 尽量避免使用深度分页功能,因为它会增加网络和计算开销,可能导致性能问题。 2. 深度分页功能是通过设置 from 和 size 参数来实现的。from 参数表示从哪个位置开始查询,size 参数表示每页返回的文档数量。 3. Elasticsearch 默认最多只能返回 10000 条记录,如果需要查询更多的记录,需要设置 index.max_result_window 参数。但是设置太大会占用过多的内存,影响性能。 下面是一个 Java 实现 Elasticsearch 分页查询的示例代码: ``` import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.action.search.SearchType; import org.elasticsearch.client.Client; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.search.SearchHit; import org.elasticsearch.search.SearchHits; import org.elasticsearch.search.sort.SortBuilders; import org.elasticsearch.search.sort.SortOrder; public class ESQuery { private Client client; public ESQuery(Client client) { this.client = client; } public void search(String index, String type, int from, int size) { SearchResponse response = client.prepareSearch(index) .setTypes(type) .setQuery(QueryBuilders.matchAllQuery()) .addSort(SortBuilders.fieldSort("_id").order(SortOrder.DESC)) .setSearchType(SearchType.DFS_QUERY_THEN_FETCH) .setFrom(from) .setSize(size) .execute() .actionGet(); SearchHits hits = response.getHits(); for (SearchHit hit : hits) { System.out.println(hit.getSourceAsString()); } } } ``` 调用示例: ``` ESQuery esQuery = new ESQuery(client); esQuery.search("my_index", "my_type", 0, 10); // 查询第一页,每页10条记录 esQuery.search("my_index", "my_type", 10, 10); // 查询第二页,每页10条记录,从第11条记录开始 ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值