Elasticsearch 学习

Elasticseach 学习

ES 简介

ES结合kibana、Logstash、Beat,也就是elastic stack(ELK)。用于日志数据分析可视化,实时监控等领域

Elasticsearch 学习_第1张图片

elasticseach是slastic stack的核心,负责存储,搜索,分析数据

elasticseach的底层是Lucene,Lucene是Java语言的一个搜索引擎类库,是Apache公司的顶级项目,官网https://lucene.apache.org/

Elasticsearch 学习_第2张图片

Elasticsearch 学习_第3张图片

基于Lucene做二次开发形成elasticseach

Elasticsearch 学习_第4张图片

Elasticsearch 学习_第5张图片

正向索引和倒排索引

传统数据库,如MySQL采用正向索引

![image-20231103141052785](https://gitee.com/zwx0203/cloudimage/raw/master/202311031410896.png

Elasticsearch 学习_第6张图片

Elasticsearch 学习_第7张图片

Elasticsearch 学习_第8张图片

ES 与 MySQL概念对比

文档(可以理解为mysql表中一行数据),序列化为json格式后存储在elasticseach中

Elasticsearch 学习_第9张图片

索引(index):相同类型的文档的集合

Elasticsearch 学习_第10张图片

Elasticsearch 学习_第11张图片

概念对比

DSL使用JSON风格语句来CRUD。

在MySQL中SQL通过connection发给MySQL。

DSL通过http来发送请求,因为es给的是restful接口,这种接口与语言无关,任何只要能发http请求的语言都能把它的DSL发给es的restful接口让es进行处理。

Elasticsearch 学习_第12张图片

问题:什么时候用mysql什么时候用es ?

两者实际上是互补关系,而不是替代的关系

用户写数据直接写到mysql,因为mysql可确保数据安全&一致性。

用户搜索数据则通过es来进行。

通过中间组件将mysql数据同步给es

Elasticsearch 学习_第13张图片

Elasticsearch 学习_第14张图片

安装ES、Kibana、Ik分词器

elasticsearch:Elasticsearch 7.12.0 | Elastic

​ 下载解压后,双击bin中的elasticsearch.bat 然后访问http://localhost:9200/ 若生成如下界面 则成功

Elasticsearch 学习_第15张图片

Kibana:Kibana 7.12.0 | Elastic

​ 下载解压后,双击bin中kibana.bat 然后访问http://127.0.0.1:5601/ 若生成如下界面 则成功

Elasticsearch 学习_第16张图片

ik分词器:https://github.com/medcl/elasticsearch-analysis-ik 将ik分词器解压后放到es目录的plugins下

Elasticsearch 学习_第17张图片

IK分词器的用法

ik_smart 分词算法 ,最少切分

Elasticsearch 学习_第18张图片

Elasticsearch 学习_第19张图片

ik_max_word 模式 最细切分

image-20231103155411841

![image-20231103155325717](https://gitee.com/zwx0203/cloudimage/raw/master/202311031553762.png

Elasticsearch 学习_第20张图片

ik分词器的使用:【精选】ElasticSearch——IK分词器的下载及使用_ik分词器下载-CSDN博客

ik分词器-拓展词库

Elasticsearch 学习_第21张图片

ik分词器-禁用词库

Elasticsearch 学习_第22张图片

什么时候分词?

答:有两个时间分词。第一个是将文档创建到索引的时候,要对文档某个内容进行分词,将词条创建倒排索引

第二个是当用户来搜索时,用户输入一大串话,需要给它进行分词

IK分词器总结

image-20231103161928090

索引库操作

索引库对应MySQL中的表,文档对应MySQL表中一行行的数据。

在MySQL中先创建表,才能在表中存入数据。

在elasticsearch中同样先得建立索引库,才能存入文档。

因此,这里先学索引库操作,再学文档操作。

mapping映射属性

es中没有数组,但它允许同一种类型有多个值。数据类型则为数组中数据的类型

Elasticsearch 学习_第23张图片

Elasticsearch 学习_第24张图片

索引库的CRUD

创建索引库

Elasticsearch 学习_第25张图片

创建下面的索引表

Elasticsearch 学习_第26张图片

#创建索引库
PUT /heima_all
{
  "mappings":{
    "properties": {
      "age": {
        "type": "integer"
      },
      "weigth": {
        "type": "float"
      },
      "isMarried": {
        "type": "boolean"
      },
      "info": {
        "type": "text",
        "analyzer": "ik_max_word"
      },
      "email": {
        "type": "keyword",
        "index": false
      },
      "score": {
        "type": "float"
      },
      "name": {
        "type": "object",
        "properties": {
          "firstname": {
            "type": "keyword"
          },
          "lastName": {
            "type": "keyword"
          }
        }
      }
    }
  }
}
查、删 索引库

GET /索引库名

DELETE /索引库名

Elasticsearch 学习_第27张图片

修改索引库

es禁止修改索引库,但可以添加新的字段

Elasticsearch 学习_第28张图片

#在heimaa索引库中新增"address"字段
PUT /heimaa/_mapping
{
  "properties": {
    "address": {
      "type": "text",
      "analyzer": "ik_smart"
    }
  }
}

Elasticsearch 学习_第29张图片

文档的CRUD

新增文档

Elasticsearch 学习_第30张图片

查询文档,删除文档

Elasticsearch 学习_第31张图片

Elasticsearch 学习_第32张图片

修改文档

Elasticsearch 学习_第33张图片

总结

Elasticsearch 学习_第34张图片

RestClient操作索引库

案例

Elasticsearch 学习_第35张图片

Elasticsearch 学习_第36张图片

Elasticsearch 学习_第37张图片

Elasticsearch 学习_第38张图片

要根据多个字段,比如根据brand,name,business等来查,则可以使用copy_to定义一个字段,将brand,name,business等拷贝到指定字段如下。在通过指定字段去查就好了

Elasticsearch 学习_第39张图片

###酒店demo的mapping
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"
      }
    }
  }
}

步骤3详见 hotel-demo项目 D:\zwx\code3\hotel-demo

Elasticsearch 学习_第40张图片

步骤4 用JavaRestClient来创建索引库

在测试类中先进行如下操作,http://localhost:9200为ES客户端的地址

private RestHighLevelClient client;

@BeforeEach
void setUp() {
    this.client = new RestHighLevelClient(RestClient.builder(
            HttpHost.create("http://localhost:9200")
    ));
}

@AfterEach
void tearDown() throws IOException {
    this.client.close();
}

Elasticsearch 学习_第41张图片

Elasticsearch 学习_第42张图片

总结Java RestClient索引库操作的步骤

Elasticsearch 学习_第43张图片

RestClient操作文档

案例

Elasticsearch 学习_第44张图片

步骤1 初始化在操作索引库中已经完成

步骤2 新增文档

Elasticsearch 学习_第45张图片

 /**
     * 创建文档(倒排索引)
     * @throws IOException
     */
    @Test
    void AddHotelDocument() throws IOException {
        //根据id查询酒店数据
        Hotel hotel = hotelService.getById(47478L);
        //转化为文档类型
        HotelDoc hotelDoc = new HotelDoc(hotel);

        //1 准备request对象
        IndexRequest request = new IndexRequest("hotel").id(hotelDoc.getId().toString());
        //2 准备json 文档
        //JSON.toJSONString(对象) :将对象序列化为Json
        request.source(JSON.toJSONString(hotelDoc),XContentType.JSON);

        //3 发送请求
        client.index(request, RequestOptions.DEFAULT);
    }

步骤3 查询文档

Elasticsearch 学习_第46张图片

 /**
     * 查找文档
     * @throws IOException
     */
    @Test
    void getDocumentById() throws IOException {
        //1 准备请求
        GetRequest request = new GetRequest("hotel","47478");

        //2 发出响应,返回结果
        GetResponse response = client.get(request, RequestOptions.DEFAULT);

        //3 处理结果
        String json = response.getSourceAsString();
        HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
        
        System.out.println(hotelDoc);
    }

步骤4 修改文档

Elasticsearch 学习_第47张图片

/**
     * 修改文档-局部更新
     */
    @Test
    void updateDocumentById() throws IOException {
        //1 创建request对象
        UpdateRequest request = new UpdateRequest("hotel","47478");

        //2 准备参数
        request.doc(
                "name","速8酒店(上海松江中心店)"
        );
        //3
        client.update(request, RequestOptions.DEFAULT);
    }

步骤5 删除文档

   /**
     * 删除文档
     */
    @Test
    void deleteDocumentById() throws IOException {
        //1 创建request对象
        DeleteRequest request = new DeleteRequest("hotel","47478");

        //2 删除
        client.delete(request, RequestOptions.DEFAULT);
    }

总结

Elasticsearch 学习_第48张图片

RestClient 批量导入Mysql数据到ES

Elasticsearch 学习_第49张图片

/**
     * 将mysql中酒店数据全导入es
     * @throws IOException
     */
    @Test
    void testBulkRequest() throws IOException {
        //批量查询酒店数据
        List<Hotel> hotels = hotelService.list();

        //1 创建Request
        BulkRequest request = new BulkRequest();
        //2 准备参数 添加多个Request对象
        for (Hotel hotel : hotels) {
            // 将hotel转成hotelDoc
            HotelDoc hotelDoc = new HotelDoc(hotel);
            // 创建新增文档的Request对象, add里面可以写Index,Delete等语句
            request.add(new IndexRequest("hotel")
                    .id(hotelDoc.getId().toString())
                    .source(JSON.toJSONString(hotelDoc), XContentType.JSON));
        }

        //3 发送请求
        client.bulk(request,RequestOptions.DEFAULT);
    }

ES 搜索功能

Elasticsearch 学习_第50张图片

详见官网文档:[Elasticsearch Guide 8.11] | Elastic

Elasticsearch 学习_第51张图片

DSL查询语法

Elasticsearch 学习_第52张图片

Elasticsearch 学习_第53张图片

全文检索查询

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

Elasticsearch 学习_第54张图片

match查询:全文检索查询的一种,会对用户输入内容分词,然后去倒排索引库检索

multi_match查询:根据多个字段查

查询语法:

###全文检索查询
#match查询  推荐使用 搜索的字段越多,查询的效率越低
GET /hotel/_search
{
  "query": {
    "match": {
      "all": "外滩如家"
    }
  }
}
#multi_match查询
GET /hotel/_search
{
  "query": {
    "multi_match": {
      "query": "外滩如家",
      "fields": ["all","city"]
    }
  }
}

小结

建议使用copyto,把多个要查的字段拷贝到一个字段中。如下 “all” 字段包含了 name,brand,business 三个字段

###酒店demo的mapping
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"
      }
    }
  }
}

Elasticsearch 学习_第55张图片

精确查询

查keyword、数值、日期、boolean等字段,不分词

Elasticsearch 学习_第56张图片

image-20231208152825601

例如:

###精确检索: 不分词,搜到的跟给的一模一样
#term查询
GET /hotel/_search
{
  "query": {
    "term": {
      "city": {
        "value": "深圳上海"
      }
    }
  }
}
#range查询
GET /hotel/_search
{
  "query": {
    "range": {
      "price": {
        "gte": 1108, 
        "lte": 3000
      }
    }
  }
}

小结

Elasticsearch 学习_第57张图片

地理查询

FIELD的类型为"geo_point"

Elasticsearch 学习_第58张图片

geo_bounding_box 查询(用的比较少),

Elasticsearch 学习_第59张图片

#geo_bounding_box: 查询geo_point值落在某个矩形范围的所有文档
GET /hotel/_search
{
  "query": {
    "geo_bounding_box": {
      "location": {
        "top_left": {
          "lat": 31.1,
          "lon": 121.5
        },
        "bottom_right": {
          "lat": 30.9,
          "lon": 121.7
        }
      }
    }
  }
}

geo_distance 查询 (用的多)

Elasticsearch 学习_第60张图片

#geo_distance 查询
GET /hotel/_search
{
  "query": {
    "geo_distance": {
      "distance": "2km",
      "location": "31.21,121.5"
    }
  }
}

复合查询

前面全文检索查询,精确查询,地理查询统称为简单查询。复合查询是将简单查询组合起来,实现更复杂的搜索逻辑

Elasticsearch 学习_第61张图片

相关性算分

Elasticsearch 学习_第62张图片

Elasticsearch 学习_第63张图片

复合查询之Function score查询

使用Function Score Query 来人为地修改相关性算分(比如针对RMB玩家,让人家的相关性算分高一点)

Elasticsearch 学习_第64张图片

案例:给"如家"酒店排名靠前

Elasticsearch 学习_第65张图片

#function score查询
GET /hotel/_search
{
  "query": {
    "function_score": {
      "query": {
        "match": {
          "all": "外滩"
        }
      },
      "functions": [
        {
          "filter": {
            "term": {
              "brand": "如家"
            }
          },
          "weight": 10
        }
      ],
      "boost_mode": "sum"
    }
  }
}
复合查询之Boolean 查询,,也叫过滤查询

Elasticsearch 学习_第66张图片

案例

Elasticsearch 学习_第67张图片

放到must中,会影响算分,算分的条件越多,性能越差,故把不重要的放到must_not中

#复合查询之bool查询  过滤查询
GET /hotel/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "name": "如家"
          }
        },
        {
          "geo_distance": {
            "distance": "10km",
            "location": {
              "lat": 31.21,
              "lon": 121.5
            }
          }
        }
      ],
      "must_not": [
        {
          "range": {
            "price": {
              "gt": 400
            }
          }
        }
      ]
    }
  }
}

放到must_not中不影响算分

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
            }
          }
        }
      ]
    }
  }
}

bool查询小结

Elasticsearch 学习_第68张图片

ES搜索结果处理

排序

Elasticsearch 学习_第69张图片

案例1:酒店数据按照用户评价降序排序,评价相同则按照价格升序排序

Elasticsearch 学习_第70张图片

#sort 排序
GET /hotel/_search
{
  "query": {
    "match_all": {}
  },
  "sort": [
    {
      "score": "desc"
    },
    {
      "price": "asc" 
    }
  ]
}


GET /hotel/_search
{
  "query": {
    "match_all": {}
  },
  "sort": [
    {
      "score": {
        "order": "desc"
      },
      "price": {
        "order": "asc"
      }
    }
  ]
}

案例2:看地图上哪些酒店离你近,做一个升序排序

Elasticsearch 学习_第71张图片

分页

from = (第几页 - 1) * size,从1开始

Elasticsearch 学习_第72张图片

GET /hotel/_search
{
  "query": {"match_all": {}},
  "sort": [{"price": "asc"}],
  "from": 9990  ,
  "size": 10
}

深度分页问题

Elasticsearch 学习_第73张图片

Elasticsearch 学习_第74张图片

es分页小结 (from+size用的最多)Elasticsearch 学习_第75张图片

高亮

把搜索结果中的关键字高亮显示

Elasticsearch 学习_第76张图片

#高亮,#默认标签是。 默认情况下,ES搜索字段必须与高亮字段一致,但可以把"require_field_match" 设为false来实现,搜索字段与高亮字段不一致也可以高亮
GET /hotel/_search
{
  "query": {
    "match": {
      "all": "如家"
    }
  }, 
  "highlight": {
    "fields": {
      "name": {
        "pre_tags": "", # 这两句可以不写,因为Es默认就是这两句 
        "post_tags": "", #
        "require_field_match": "false"
      }
    }
  }
}

ES搜索结果处理整体语法

Elasticsearch 学习_第77张图片

RestClient 查询文档

Elasticsearch 学习_第78张图片

返回结果的字段解析

Elasticsearch 学习_第79张图片

Elasticsearch 学习_第80张图片

Elasticsearch 学习_第81张图片

查询

Elasticsearch 学习_第82张图片

match、multi_match、match_all

QueryBuilders.matchAllQuery()

Elasticsearch 学习_第83张图片

精确查询

Elasticsearch 学习_第84张图片

复合查询
Elasticsearch 学习_第85张图片

 @Test
    void testBool() throws IOException {
        //1 准备request
        SearchRequest request = new SearchRequest("hotel");

        //2 准备DSL
        // 准备booleanQuery
        BoolQueryBuilder booledQuery = QueryBuilders.boolQuery();
        // 添加term
        booledQuery.must(QueryBuilders.termQuery("city","深圳"));

        booledQuery.filter(QueryBuilders.rangeQuery("price").lte(350));

        request.source().query(booledQuery);
        //3 发送请求
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);

        //4 处理请求
        handleResponse(response);
    }

    private static void handleResponse(SearchResponse response) {
        //解析结果
        SearchHits searchHits = response.getHits();

        long total = searchHits.getTotalHits().value;

        System.out.println("一共搜索到" + total + "条数据");

        SearchHit[] hits = searchHits.getHits();

        for (SearchHit hit : hits) {

            String json = hit.getSourceAsString();

            HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);

            System.out.println(hotelDoc);
        }
    }

要构建查询只需要记住QueryBuilders类就行了

排序和分页

对搜索结果的排序和分页是与查询在同级的参数

Elasticsearch 学习_第86张图片

 @Test
    void testPageAndSort() throws IOException {
        //页码, 每页大小
        int page = 2,size =5;

        //1 准备request
        SearchRequest request = new SearchRequest("hotel");

        //2 准备DSL
        //2.1 query
        request.source().query(QueryBuilders.matchAllQuery());
        //2.2 sort
        request.source().sort("price", SortOrder.ASC);
        //2.3 分页 from、size
        request.source().from((page - 1) * size).size(5);
        //3 发送请求
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);

        //4 处理请求
        handleResponse(response);
    }

高亮

Elasticsearch 学习_第87张图片

Elasticsearch 学习_第88张图片

@Test
void testHighlight() throws IOException {
    //页码, 每页大小
    int page = 2,size =5;


    //1 准备request
    SearchRequest request = new SearchRequest("hotel");

    //2 准备DSL
    //2.1 query
    request.source().query(QueryBuilders.matchQuery("all","如家  "));

    //2.4 高亮 highlight
    request.source().highlighter(new HighlightBuilder().field("name").requireFieldMatch(false));
    //3 发送请求
    SearchResponse response = client.search(request, RequestOptions.DEFAULT);

    //4 处理请求
    handleHighlightResponse(response);
}
    
    
private static void handleHighlightResponse(SearchResponse response) {
    //4解析结果
    SearchHits searchHits = response.getHits();
    //4.1 获取总条数
    long total = searchHits.getTotalHits().value;
    System.out.println("一共搜索到" + total + "条数据");
    //4.2 文档数组
    SearchHit[] hits = searchHits.getHits();
    //4.3 遍历
    for (SearchHit hit : hits) {
        //获取文档source
        String json = hit.getSourceAsString();
        //反序列化
        HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
        //获取高亮结果
        Map 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);
    }
}

Elasticsearch 学习_第89张图片

黑马旅游案例

  • 酒店搜索和分页
  • 酒店结果过滤
  • 我周边的酒店
  • 酒店竞价排名

启动hotel-deomo服务,进入http://localhost:8089/

酒店搜索与分页

Elasticsearch 学习_第90张图片

Elasticsearch 学习_第91张图片

Elasticsearch 学习_第92张图片

酒店结果过滤

Elasticsearch 学习_第93张图片

Elasticsearch 学习_第94张图片

Elasticsearch 学习_第95张图片

我附近的酒店

Elasticsearch 学习_第96张图片

Elasticsearch 学习_第97张图片

广告置顶

Elasticsearch 学习_第98张图片

#添加isAD字段
POST /hotel/_update/1908594080
{
  "doc": {
    "isAD": true
  }
}

POST /hotel/_update/1725781423
{
  "doc": {
    "isAD": true
  }
}

function score 组合查询Java语法
Elasticsearch 学习_第99张图片

你可能感兴趣的:(elasticsearch,微服务,全文检索,springboot,java,idea,spring,boot)