
Kibanan语法:
GET _search
{
"query": {
"match_all": {}
}
}
GET /
#测试分词器 ik_max_word ik_smart
POST /_analyze
{
"text": "黑马程序员学习java太棒了",
"analyzer": "ik_max_word"
}
POST /_analyze
{
"text":"传智播客的课程可以白嫖,而且就业率高达95%,奥力给",
"analyzer": "ik_smart"
}
#创建索引库
PUT /heima
{
"mappings": {
"properties": {
"info":{
"type": "text",
"analyzer": "ik_smart"
},
"email":{
"type": "keyword",
"index": false
},
"name":{
"type": "object",
"properties": {
"firstName":{
"type":"keyword"
},
"lastName":{
"type":"keyword"
}
}
}
}
}
}
#查询索引库
GET /heima
#删除索引库
DELETE /heima
#修改索引库 (只能添加字段)
PUT /heima/_mapping
{
"properties":{
"age":{
"type":"long"
}
}
}
#插入数据
POST /heima/_doc/1
{
"info":"黑马程序员java讲师",
"email":"1142@qq.com",
"name":{
"firstName":"云",
"lastName":"赵"
}
}
#查询文档
GET /heima/_doc/1
#删除文档
DELETE /heima/_doc/1
#全量修改文档 (id不存在变成新增)
PUT /heima/_doc/1
{
"info":"黑马程序员java讲师",
"email":"dfl@qq.com",
"name":{
"firstName":"云",
"lastName":"赵"
}
}
#增量修改
POST /heima/_update/1
{
"doc": {
"email":"dfl999@qq.com"
}
}
PUT /hotel
{
"mappings": {
"properties":{
"id":{
"type":"keyword"
},
"name":{
"type": "text",
"analyzer": "ik_max_word",
"copy_to": "all"
},
"address":{
"type":"keyword",
"index": false
},
"price":{
"type":"integer"
},
"score":{
"type":"integer"
},
"brand":{
"type":"keyword",
"copy_to": "all"
},
"city":{
"type": "keyword"
},
"starName":{
"type":"keyword"
},
"business":{
"type":"keyword",
"copy_to": "all"
},
"location":{
"type": "geo_point"
},
"pic":{
"type": "keyword",
"index": false
},
"all":{
"type":"text",
"analyzer": "ik_max_word"
}
}
}
}
GET /hotel
DELETE /hotel
#查询数据
GET /hotel/_doc/61083
#批量查询数据
GET /hotel/_search
GET /hotel/_search
{
"query":{
"match_all": {}
}
}
#一:全文检索查询 match查询一个字段
GET /hotel/_search
{
"query":{
"match": {
"all": "外滩如家"
}
}
}
#通过使用all和下面的多个字段搜索是一样的,那么使用那个呢?参与搜索的字段越多查询效率越低推荐使用all的方法
#全文检索查询 match查询多个字段
GET /hotel/_search
{
"query": {
"multi_match": {
"query": "外滩如家",
"fields": ["brand","name","business"]
}
}
}
#二:精确查询 查询的条件它也不需要分词,而且搜索条件要和查找的字段值完全匹配
# 精确查询一般查找keyword、数值、日期、boolean等字段,不会对搜索的字段分词
#分为term:精确值查询 range:范围查询值
GET /hotel/_search
{
"query":{
"term": {
"city": {
"value": "上海"
}
}
}
}
GET /hotel/_search
{
"query":{
"range": {
"price": {
"gte": "100",
"lte": 300
}
}
}
}
#三:地理查询 查询距离中心点15公里的所有值
GET /hotel/_search
{
"query":{
"geo_distance":{
"distance":"15km",
"location":"31.21,121.5"
}
}
}
#geo_bounding_box 查询值落在矩形范围内的所有文档
GET /hotel/_search
{
"query":{
"geo_bounding_box":{
"location":{
"top_left":{
"lat":31.1,
"lon":121.5
},
"bottom_right":{
"lat":30.9,
"lon":121.7
}
}
}
}
}
#三:复合查询
#相关性算分 function_score:算分函数查询,控制文档的相关性算分,控制文档排名
#算分函数的结果functory_score会与query_score运算得到新的算分 weight:给一个常量值作为函数结果,field_value_factor文档中的某个字段值作为函数结果,random_score:随机生成一个值作为函数结果,script_score:自定义公式,作为函数结果
# filter 过滤条件复合条件的才会重新算分
#boost_mode:算分函数的结果functory_score会与query_score运算方式:加权模式默认multiply 两者相乘,replace:用functory_score替换query_score,其他sum、avg、max、min
GET /hotel/_search
{
"query": {
"function_score": {
"query": {
"match":{
"all":"外滩"
}
},
"functions": [
{
"filter": {
"term":{
"brand":"如家"
}
},
"weight": 10
}
],
"boost_mode": "sum"
}
}
}
#复合查询
#Boolean Query:不是计算相关性算分,而是把多个查询语句组合在一起,形成新的查询,被组合的查询称为子查询
# must_not和filter 不参与算分 果子查询较多,都参与算分,会非常影响性能
# ES会把filer的查询,放到缓存里面,将来在查询的时候,会近一步提高性能
# 除了跟算分相关的,一般是关键字,放到must和should里面
# 其他的都应该放到must_not和filter里面,尽可能的减少算分提高查询的效率
# 搜索框的内容关键字的搜索可以放到must里,因为它参与算分 品牌也好价格也好,放到must_not或者filter里面,放到这里面不参与算分
# must:必须匹配每个子查询类似与 should:选择性匹配子查询类似或 must_not:必须不匹配不参与算分类似非 filter:必须匹配,不参与算分
#查询名字包含如家,价格不高于400。坐标在31.21,121.5的范围内的
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
}
}
}
]
}
}
}
#排序 默认是根据算分的score来排序的,可以排序的字段有keyword 一旦进行了排序_score就没有值了
GET /hotel/_search
{
"query":{
"match_all": {}
},
"sort":[
{
"_geo_distance":{
"location":"31.21,121.5",
"order":"asc",
"unit":"km"
}
}
]
}
#根据用户评价降序排序,评价相同按照价格排序
GET /hotel/_search
{
"query":{
"match_all": {}
},
"sort": [
{
"score": {
"order": "desc"
},
"price":{
"order": "asc"
}
}
]
}
# 查询按照指定坐标的距离升序排序
GET /hotel/_search
{
"query":{
"match_all": {}
},
"sort":[
{
"_geo_distance":{
"location":{
"lat": 31.21,
"lon": 121.5
},
"order":"asc",
"unit":"km"
}
}
]
}
#分页 ,ES底层采用倒排索引,它的结构是不利于做分页的,实际上采用的是逻辑上的分页,比如查990到1000的数据,对ES来讲它或查询0到1000的所有数据,然后去截取990-1000的部分
GET /hotel/_search
{
"query":{
"match_all": {}
},
"sort":[
{
"price":"asc"
}
],
"from":20,
"size":10
}
# 会产生深度分页问题
GET /hotel/_search
{
"query":{
"match_all": {}
},
"sort":[
{
"price":"asc"
}
],
"from":9991,
"size":10
}
# 高亮
# ES搜索的字段必须与高亮的字段必须一致,如果不一致,需要添加require_field_match 默认是高亮字段和搜索字段匹配
GET /hotel/_search
{
"query":{
"match":{
"all":"如家"
}
},
"highlight": {
"fields": {
"name": {
"require_field_match": "true"
}
}
}
}
#如果不一致,需要添加require_field_match:false
GET /hotel/_search
{
"query":{
"match":{
"brand":"如家"
}
},
"highlight": {
"fields": {
"name": {
"require_field_match": "false",
"pre_tags": "<em>",
"post_tags": "</em>"
}
}
}
}
#搜索处理的整体语句
GET /hotel/_search
{
"query":{
"match":{
"name":"如家"
}
},
"from":0,
"size": 20,
"sort":[
{
"price":"asc"
},
{
"_geo_distance": {
"location": "31.21,121.5",
"order": "asc",
"unit": "km"
}
}
],
"highlight": {
"fields": {
"name": {
"pre_tags": "<em>",
"post_tags": "</em>"
}
}
}
}
Idea操作ES:
package cn.itcast.hotel;
import cn.itcast.hotel.constants.HotelIndexConstants;
import cn.itcast.hotel.pojo.Hotel;
import cn.itcast.hotel.pojo.HotelDoc;
import cn.itcast.hotel.service.IHotelService;
import com.alibaba.fastjson.JSON;
import org.apache.http.HttpHost;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.util.CollectionUtils;
import java.io.IOException;
import java.util.List;
import java.util.Map;
@SpringBootTest
class HotelIndexTestCopy {
private RestHighLevelClient client;
//单元测试里面的注解,提前完成对象的初始化
@BeforeEach
void setUp(){
this.client=new RestHighLevelClient(RestClient.builder(HttpHost.create("http://192.168.73.129:9200")));
}
//销毁注解
@AfterEach
void tearDown() throws IOException {
this.client.close();
}
//所有的单元测试,都会先运行BeforeEach 最后运行@AfterEach
@Test
void testInit(){
System.out.println(client+"===================");
}
//创建表
@Test
void createHotelIndex() throws IOException {
//1.创建Request对象
CreateIndexRequest request=new CreateIndexRequest("hotel");
//2.准备请求的参数DSL语句
request.source(HotelIndexConstants.MAPPING_TEMPLATE,XContentType.JSON);
//3.发送请求 client.indices()返回值是IndicesClient对象里面封装了操作索引库的API
client.indices().create(request,RequestOptions.DEFAULT);
}
//删除表
@Test
void testDeleteHotelIndex() throws IOException {
//1.创建Request对象
DeleteIndexRequest request=new DeleteIndexRequest("hotel");
//发起请求
client.indices().delete(request,RequestOptions.DEFAULT);
}
//判断表是否存在
@Test
void testExistHotelIndex() throws IOException {
//1.创建Request对象
GetIndexRequest request=new GetIndexRequest("hotel");
//发起请求
boolean exist=client.indices().exists(request,RequestOptions.DEFAULT);
System.out.println(exist ? "表存在!":"表不存在!");
}
@Autowired
private IHotelService hotelService;
//添加数据
@Test
void addDocumen() throws IOException {
//根据id查询酒店数据
Hotel hotel=hotelService.getById(61083);
System.out.println(hotel);
//转换对象类型
HotelDoc hotelDoc=new HotelDoc(hotel);
System.out.println(hotelDoc);
//准备request对象
IndexRequest request=new IndexRequest("hotel").id(hotel.getId().toString());
//准备json数据
request.source(JSON.toJSONString(hotelDoc),XContentType.JSON);
//发送请求 client.index() :index表示给文档创建倒排索引
client.index(request,RequestOptions.DEFAULT);
System.out.println("新增文档成功!");
}
//查询数据 根据id查询数据
@Test
void selectDocumen() throws IOException {
//创建request
GetRequest request=new GetRequest("hotel","61083");
//发送请求得到结果
GetResponse response=client.get(request,RequestOptions.DEFAULT);
//解析结果
String json=response.getSourceAsString();
System.out.println("解析的json数据:"+json);
//利用JSON反序列化为java对象
HotelDoc hotelDoc=JSON.parseObject(json,HotelDoc.class);
System.out.println("转化的java对象:"+hotelDoc);
}
//更新数据
@Test
void updateDocument() throws IOException {
//创建request
UpdateRequest request=new UpdateRequest("hotel","61083");
//准备参数
request.doc(
"price","666",
"startName","四钻"
);
//发送请求
client.update(request,RequestOptions.DEFAULT);
System.out.println("更新成功");
}
//删除数据
@Test
void deleteDocumen() throws IOException {
//创建request
DeleteRequest request=new DeleteRequest("hotel","61083");
//发送请求
client.delete(request,RequestOptions.DEFAULT);
System.out.println("删除数据成功");
}
//批量添加数据
@Test
void insertBulk() throws IOException {
//批量查询数据
List<Hotel> hotels=hotelService.list();
//创建Bulk请求
BulkRequest request=new BulkRequest();
//准备参数 添加多个新增的Request
for (Hotel hotel:hotels){
//转换java类型
HotelDoc hotelDoc=new HotelDoc(hotel);
//创建新增文档的Request
request.add(new IndexRequest("hotel")
.id(hotelDoc.getId().toString())
.source(JSON.toJSONString(hotelDoc),XContentType.JSON));
}
//发送请求
client.bulk(request,RequestOptions.DEFAULT);
System.out.println("批量添加成功!");
}
/**
* @description: DSL查询分类DSL查询分类 es检索数据
* @param: null
* @return:
* @author Administrator
* @date: 2025/3/8 14:03
*/
//查询数据 查询所有 DSL是通过HightLevelRestClient 中的source()来实现的,里面包含了查询、排序、分页、高亮
//QueryBuilders 里面包含了各种查询方法
@Test
void MallAll() throws IOException {
//准备request
SearchRequest request=new SearchRequest("hotel");
//组织DSL参数
request.source()
.query(QueryBuilders.matchAllQuery());
//发送请求,得到响应结果
SearchResponse response=client.search(request,RequestOptions.DEFAULT);
System.out.println("返回的数据"+response);
//解析结果
handResponse(response);
}
//查询数据 全文检索查询 match_query multi_match_query
@Test
void Match() throws IOException {
//准备request
SearchRequest request=new SearchRequest("hotel");
//组织DSL参数
request.source()
.query(QueryBuilders.matchQuery("all","如家"));
//multi_match_query
//request.source().query(QueryBuilders.multiMatchQuery("如家","name","business"));
//发送请求,得到响应结果
SearchResponse response=client.search(request,RequestOptions.DEFAULT);
System.out.println("返回的数据"+response);
//解析响应方法封装
handResponse(response);
}
//查询数据 精确查询 term range
@Test
void termMatch() throws IOException {
//准备request
SearchRequest request=new SearchRequest("hotel");
//组织DSL参数
request.source()
.query(QueryBuilders.termQuery("city","上海"));
//range
//request.source().query(QueryBuilders.rangeQuery("price").gte(100).lte(150));
//发送请求,得到响应结果
SearchResponse response=client.search(request,RequestOptions.DEFAULT);
System.out.println("返回的数据"+response);
//解析响应方法封装
handResponse(response);
}
//查询数据 复合查询 bool
@Test
void Bool() throws IOException {
//准备request
SearchRequest request=new SearchRequest("hotel");
//组织DSL参数
BoolQueryBuilder boolQuery=new BoolQueryBuilder();
//添加term
boolQuery.must(QueryBuilders.termQuery("city","上海"));
//添加range
boolQuery.filter(QueryBuilders.rangeQuery("price").lte(300));
request.source().query(boolQuery);
//发送请求,得到响应结果
SearchResponse response=client.search(request,RequestOptions.DEFAULT);
System.out.println("返回的数据"+response);
//解析响应方法封装
handResponse(response);
}
//排序、分页
@Test
void testPageAndSort() throws IOException {
//页面,每页大小
int page=1,size=5;
//准备request
SearchRequest request=new SearchRequest("hotel");
//组织DSL参数
request.source()
.query(QueryBuilders.matchAllQuery());
//排序
request.source().sort("price", SortOrder.ASC);
//分页
request.source().from((page-1)*size).size(5);
//发送请求,得到响应结果
SearchResponse response=client.search(request,RequestOptions.DEFAULT);
System.out.println("返回的数据"+response);
//解析结果
handResponse(response);
}
//解析方法
private static void handResponse(SearchResponse response) {
//解析结果
SearchHits searchHits= response.getHits();
//查询总条数
Long total=searchHits.getTotalHits().value;
System.out.println("共搜索到"+total+"条数据");
//查询结果数组
SearchHit[] hits=searchHits.getHits();
for(SearchHit hit: hits){
//得到json
String json=hit.getSourceAsString();
System.out.println("json数据:"+json);
}
}
//高亮显示
@Test
void Heighlight() throws IOException {
//准备request
SearchRequest request=new SearchRequest("hotel");
//组织DSL参数
request.source()
.query(QueryBuilders.matchQuery("all","如家"));
//高亮
request.source().highlighter(new HighlightBuilder().field("name").requireFieldMatch(false));
//发送请求,得到响应结果
SearchResponse response=client.search(request,RequestOptions.DEFAULT);
System.out.println("返回的数据"+response);
//解析结果
handResponseHighLight(response);
}
//解析方法
private static void handResponseHighLight(SearchResponse response) {
//解析结果
SearchHits searchHits= response.getHits();
//查询总条数
Long total=searchHits.getTotalHits().value;
System.out.println("共搜索到"+total+"条数据");
//查询结果数组
SearchHit[] hits=searchHits.getHits();
for(SearchHit hit: hits){
//得到json
String json=hit.getSourceAsString();
System.out.println("json数据:"+json);
//反序列化
HotelDoc hotelDoc=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].string();
//覆盖不高亮的字段
hotelDoc.setName(name);
}
}
System.out.println("hotelDoc:"+hotelDoc);
}
}
}