Elasticsearch(高性能分布式搜索引擎)-上篇

news2024/11/24 7:37:34

Elasticsearch(高性能分布式搜索引擎)

文章目录

  • Elasticsearch(高性能分布式搜索引擎)
    • 1 初识elasticsearch
      • 1.1 认识和安装
      • 1.2 倒排索引
      • 1.3 IK分词器
      • 1.4 基础概念
        • 1.4.1 elasticsearch与数据库对比
    • 2 索引库的操作
      • 2.1 Mapping映射属性
      • 2.2 索引库操作
    • 3 文档操作
      • 3.1 文档CRUD
      • 3.2 批量处理
    • 4 JavaRestClient
      • 4.1 客户端初始化
      • 4.2 商品表Mapping映射
      • 4.3 索引库操作
      • 4.4 文档操作
      • 4.5 批处理

黑马商城作为一个电商项目,商品的搜索肯定是访问频率最高的页面之一。目前搜索功能是基于数据库的模糊搜索来实现的,存在很多问题。

首先,查询效率较低。

由于数据库模糊查询不走索引,在数据量较大的时候,查询性能很差。黑马商城的商品表中仅仅有不到9万条数据,基于数据库查询时,搜索接口的表现如图:

在这里插入图片描述

改为基于搜索引擎后,查询表现如下:

需要注意的是,数据库模糊查询随着表数据量的增多,查询性能的下降会非常明显,而搜索引擎的性能则不会随着数据增多而下降太多。目前仅10万不到的数据量差距就如此明显,如果数据量达到百万、千万、甚至上亿级别,这个性能差距会非常夸张。

其次,功能单一

数据库的模糊搜索功能单一,匹配条件非常苛刻,必须恰好包含用户搜索的关键字。而在搜索引擎中,用户输入出现个别错字,或者用拼音搜索、同义词搜索都能正确匹配到数据。

综上,在面临海量数据的搜索 ,或者有一些复杂搜索需求的时候,推荐使用专门的搜索引擎来实现搜索功能。

目前全球的搜索引擎技术排名如下:

在这里插入图片描述

1 初识elasticsearch

1.1 认识和安装

elasticsearch结合kibana、Logstash、Beats,是一整套技术栈,被叫做ELK。被广泛应用在日志数据分析、实时监控等领域。

1.2 倒排索引

传统数据库(如MySQL)采用正向索引,例如给下表(tb goods)中的id创建索引:

在这里插入图片描述

elasticsearch采用倒排索引:

  • 文档(document):每条数据就是一个文档
  • 词条(term):文档按照语义分成的词语

在这里插入图片描述

1.3 IK分词器

中文分词往往需要根据语义分析,比较复杂,这就需要用到中文分词器,例如IK分词器。IK分词器是林良益在2006年开源发布的,其采用的正向迭代最细粒度切分算法一直沿用至今。

在Kibana的DevTools中可以使用下面的语法来测试IK分词器:

语法说明:

  • POST:请求方式
  • /_analyze:请求路径,这里省略了http://虚拟机ip:9200 有kibana帮我们补充
  • 请求参数,json风格:
    • analyzer:分词器类型,这里默认是standard分词器
    • text:要分词的内容

在这里插入图片描述

1.4 基础概念

elasticsearch中的文档数据会被序列化为json格式后存储在elasticsearch中。

在这里插入图片描述

索引(index): 相同类型的文档的集合,可以称为数据库

映射(mapping): 索引中文档的字段约束信息,类似表的结构约束

在这里插入图片描述

1.4.1 elasticsearch与数据库对比

在这里插入图片描述

2 索引库的操作

2.1 Mapping映射属性

mapping是对索引库中文档的约束,常见的mapping属性包括:

  • type:字段数据类型,常见的简单类型有:
    • 字符串:text(可分词的文本)、keyword(精确值,例如:品牌、国家、ip地址)
    • 数值:long、integer、short、byte、double、float
    • 布尔:boolean
    • 日期:date
    • 对象:object
  • index:是否创建索引,默认为true(如果字段不参与索引、不参与排序,则可以不用索引)
  • analyzer:使用哪种分词器(一般只有可分词的文本才需要分词器)
  • properties:该字段的子字段

例如下面的json文档:

{
    "age": 21,
    "weight": 52.1,
    "isMarried": false,
    "info": "黑马程序员Java讲师",
    "email": "zy@itcast.cn",
    "score": [99.1, 99.5, 98.9],
    "name": {
        "firstName": "云",
        "lastName": "赵"
    }
}

对应的每个字段映射(Mapping):

字段名字段类型类型说明是否 参与搜索是否参与分词分词器
ageinteger整数——
weightfloat浮点数——
isMarriedboolean布尔——
infotext字符串,但需要分词IK
emailkeyword字符串,但是不分词——
scorefloat只看数组中元素类型——
firstNamekeyword字符串,但是不分词——
lastNamekeyword字符串,但是不分词——

name是个object类型,有两个properties,每个子字段都需要单独指定类型

2.2 索引库操作

Elasticsearch提供的所有API都是Restful的接口,遵循Restful的基本规范:

在这里插入图片描述

创建索引库和mapping的请求语法如下:

在这里插入图片描述
在这里插入图片描述

#创建索引库并设置mapping映射
PUT /heima
{
  "mappings": {
    "properties": {
      "info":{
        "type": "text",
        "analyzer": "ik_smart",
        "index": true
      },
      "age":{
        "type": "byte"
      },
      "email":{
        "type": "keyword",
        "index": false
      },
      "name":{
        "type": "object",
        "properties": {
          "firstName": {
            "type": "keyword"
          },
          "lastName":{
            "type": "keyword"
          }
        }
      }
    }
  }
}

#查询索引库
GET /heima

#删除索引库
DELETE /heima

索引库和mapping一旦创建无法修改,但是可以添加新的字段,语法如下:

在这里插入图片描述
在这里插入图片描述

3 文档操作

3.1 文档CRUD

新增文档的请求格式如下:

在这里插入图片描述

查看文档请求格式:

删除索引库的请求格式:

# 新增文档
POST /heima/_doc/1
{
  "info": "黑马程序员Java讲师",
  "age": 35,
  "email": "zy@itcast.cn",
  "name": {
    "first": "云",
    "lastname": "赵"
  }
}

# 查询文档
GET /heima/_doc/1

# 删除文档
DELETE /heima/_doc/1

修改索引库:

  • 方式一:全量修改,会删除旧文档,添加新文档

    # 全量修改
    PUT /heima/_doc/1
    {
        "info": "黑马程序员JAVA讲师",
      "age": 40,
      "email": "ZY@itcast.cn",
      "name": {
        "first": "云",
        "lastname": "赵"
      }
    }
    

    如果修改的id不存在,则会直接创建一个此id的新文档

  • 方式二:增量修改,修改指定字段值

    # 增量修改
    POST /heima/_update/1
    {
      "doc": {
        "email": "ZhaoYun@itcast.cn"
      }
    }
    

3.2 批量处理

Elasticsearch中允许通过一次请求中携带多次文档操作,也就是批量处理,语法格式如下:

# 批量新增
POST /_bulk
{"index":{"_index":"heima","_id":"3"}}
{"info":"黑马程序员C++讲师","email":"ww@itcast.cn","name":{"firstName":"五","lastName":"王"}}
{"index":{"_index":"heima","_id":"4"}}
{"info":"黑马程序员前端讲师","email":"zhangsan@itcast.cn","name":{"firstName":"三","lastName":"张"}}

# 批量删除
POST /_bulk
{"delete":{"_index":"heima","_id":"3"}}
{"delete":{"_index":"heima","_id":"4"}}

4 JavaRestClient

4.1 客户端初始化

Elasticsearch目前最新版本是8.0,其]ava客户端有很大变化。不过大多数企业使用的还是8以下版本,所以我们选择使用早期的)avaRestClient客户端来学习

>

  1. 引入es的RestHighLevelClient依赖:

    D

  2. 因为SpringBoot默认的ES版本是7.17.0,所以需要覆盖默认的ES版本:

  3. 初始化RestHighLevelClient:

在这里插入图片描述

4.2 商品表Mapping映射

要实现商品搜索,那么索引库的字段肯定要满足页面搜索的需求:

在这里插入图片描述

#商品索引库
PUT /hmall
{
  "mappings": {
    "properties": {
      "id": {
        "type": "keyword"
      },
      "name": {
        "type": "text",
        "analyzer": "ik_smart"
      },
      "price":{
        "type": "integer"
      },
      "image":{
        "type": "keyword",
        "index":false
      },
      "category":{
        "type":"keyword"
      },
      "brand":{
        "type": "keyword"
      },
      "sold":{
        "type": "integer"
      },
      "commentCount":{
        "type": "integer",
        "index": false
      },
      "isAD":{
        "type": "boolean"
      },
      "updateTime":{
        "type": "date"
      }
    }
  }
}

4.3 索引库操作

创建索引库 的Java与Restful接口API对比:

删除索引库:

查询索引库信息:

public class ElasticTest {

    private RestHighLevelClient client;

    @Test
    void testConnection(){
        System.out.println("client=" + client);
    }

    @Test
    void testCreateIndex() throws IOException {
        //1. 准备Request对象
        CreateIndexRequest request = new CreateIndexRequest("items");
        //2. 准备请求参数
        request.source(MAPPING_TEMPLATE, XContentType.JSON);
        //3. 发送请求
        client.indices().create(request, RequestOptions.DEFAULT);
    }

    @Test
    void testGetIndex() throws IOException {
        //1. 准备Request对象
        GetIndexRequest request = new GetIndexRequest("items");
        //2. 发送请求
        boolean exists = client.indices().exists(request, RequestOptions.DEFAULT);
        System.out.println(exists);
    }

    @Test
    void testDeleteIndex() throws IOException {
        //1. 准备Request对象
        DeleteIndexRequest request = new DeleteIndexRequest("items");
        //2. 发送请求
        client.indices().delete(request, RequestOptions.DEFAULT);
    }

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

    @AfterEach
    void tearDown() throws IOException {
        if(client != null){
            client.close();
        }
    }

    private static final String MAPPING_TEMPLATE = "{\n" +
            "  \"mappings\": {\n" +
            "    \"properties\": {\n" +
            "      \"id\": {\n" +
            "        \"type\": \"keyword\"\n" +
            "      },\n" +
            "      \"name\": {\n" +
            "        \"type\": \"text\",\n" +
            "        \"analyzer\": \"ik_smart\"\n" +
            "      },\n" +
            "      \"price\":{\n" +
            "        \"type\": \"integer\"\n" +
            "      },\n" +
            "      \"image\":{\n" +
            "        \"type\": \"keyword\",\n" +
            "        \"index\":false\n" +
            "      },\n" +
            "      \"category\":{\n" +
            "        \"type\":\"keyword\"\n" +
            "      },\n" +
            "      \"brand\":{\n" +
            "        \"type\": \"keyword\"\n" +
            "      },\n" +
            "      \"sold\":{\n" +
            "        \"type\": \"integer\"\n" +
            "      },\n" +
            "      \"commentCount\":{\n" +
            "        \"type\": \"integer\",\n" +
            "        \"index\": false\n" +
            "      },\n" +
            "      \"isAD\":{\n" +
            "        \"type\": \"boolean\"\n" +
            "      },\n" +
            "      \"updateTime\":{\n" +
            "        \"type\": \"date\"\n" +
            "      }\n" +
            "    }\n" +
            "  }\n" +
            "}";
}

在这里插入图片描述

4.4 文档操作

新增文档 的javaAPI如下:

删除文档 的JavaAPI如下:

查询文档 包含查询和解析响应结果两部分,对应的JavaAPI如下:

**文档操作: **

修改文档那个数据有两种方式:

  • 方式一:全量更新,再次写入id一样的文档,就会删除旧文档,添加新文档。与新增的JavaAPI一致
  • 方式二:局部更新。只更新指定部分字段

@SpringBootTest(properties = "spring.profiles.active=local")
public class ElasticDocumentTest {

    private RestHighLevelClient client;

    @Autowired
    private IItemService iItemService;

    @Test
    void testIndexDoc() throws IOException {
        //0. 准备文档数据
        //0.1 根据id查询数据库数据
        Item item = iItemService.getById(100000011127L);
        //0.2 把数据库数据转为文档数据
        ItemDoc itemDoc = BeanUtil.copyProperties(item, ItemDoc.class);

        //设置此项,则会修改索引库中对应文档的数据,相当于修改操作
        itemDoc.setPrice(29900);

        //1. 准备Request
        IndexRequest request = new IndexRequest("items").id(itemDoc.getId());
        //2. 准备请求参数
        request.source(JSONUtil.toJsonStr(itemDoc), XContentType.JSON);
        //3. 发送请求
        client.index(request, RequestOptions.DEFAULT);

    }

    @Test
    void testUpdateDoc() throws IOException{
        //1. 准备Request
        UpdateRequest request = new UpdateRequest("items", "100000011127");
        //2. 准备请求的参数
        request.doc(
                "price",25600,
                "sold",45000
        );
        //2. 发送请求
        client.update(request,RequestOptions.DEFAULT);
    }

    @Test
    void testGetDoc() throws IOException {
        //1. 准备Request
        GetRequest request = new GetRequest("items","100000011127");
        //2. 发送请求
        GetResponse response = client.get(request, RequestOptions.DEFAULT);
        //3. 解析响应结果
        String json = response.getSourceAsString();
        ItemDoc doc = JSONUtil.toBean(json, ItemDoc.class);
        System.out.println("doc = " + doc);
    }

    @Test
    void testDeleteDoc() throws IOException {
        //1. 准备Request
        DeleteRequest request = new DeleteRequest("items","100000011127");
        //2. 发送请求
        client.delete(request, RequestOptions.DEFAULT);
    }

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

    @AfterEach
    void tearDown() throws IOException {
        if (client != null) {
            client.close();
        }
    }

}

4.5 批处理

批处理代码流程与之前类似,只不过构建请求会用到一个名为BulkRequest来封装普通的CRUD请求:

批处理的API实例:

    @Test
    void testBulkDoc() throws IOException {
        int pageNo = 1, pageSize = 500;
        //1. 准备文档数据
        Page<Item> page = iItemService.lambdaQuery()
                .eq(Item::getStatus, 1)
                .page(Page.of(pageNo, pageSize));
        List<Item> records = page.getRecords();
        if(records == null || records.isEmpty()){
            return;
        }
        //1. 准备Request
        BulkRequest request = new BulkRequest();
        //2. 准备请求参数
        for (Item item : records) {
            request.add(new IndexRequest("items")
                    .id(item.getId().toString())
                    .source(JSONUtil.toJsonStr(BeanUtil.copyProperties(item,ItemDoc.class)),XContentType.JSON));
        }
//        request.add(new DeleteRequest("items").id("1"));
        //3. 发送请求
        client.bulk(request, RequestOptions.DEFAULT);
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1983021.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

FutureTask详解

FutureTask详解 1、FutureTask简介 FutureTask主要用于异步任务的执行和结果获取。其最重要的特性就是可以被提交到线程池中执行&#xff0c;同时也可以用来获取执行结果或检查任务的状态。 2、FutureTask内部结构 继承结构 public class FutureTask<V> implements …

Materialise Magics对齐实现分件对齐

零件‘对齐’三步曲之一 当我们需要对两个零件进行重叠&#xff0c;平行等对齐操作时&#xff0c;可以使用Magics->位置-> ‘对齐’ 功能。通过添加有效的约束条件&#xff0c;就可以实现自动对齐零件啦。 让我们看一下当两个单一方向的零件如何利用边线约束来对齐吧&a…

pxe自动安装linux

实验环境 1.rhel7主机 2开启主机图形&#xff08;本人最小化安装&#xff0c;先下载&#xff09; 3配置网络 4关闭VMware dhcp功能 5能够自动安装系统 完成rhedhat7图形,kickstart,启动图形化制作工具 安装kickstart 启动图形化制作工具 在ks.cfg可以添加安装时下载的包 …

C# 高级数据处理:深入解析数据分区 Join 与 GroupJoin 操作的应用与实例演示

文章目录 一、概述二. 数据分区 (Partitioning)三、Join 操作符1. Join 操作符的基本用法2. Join 操作符示例 四、GroupJoin 操作符1. GroupJoin 操作符的基本用法2. GroupJoin 操作符示例 总结 在数据处理中&#xff0c;联接&#xff08;Join&#xff09;操作是一种非常常见的…

Unity:Camera 对象操作的技术指南

请关注微信公众号&#xff1a;拾荒的小海螺 博客地址&#xff1a;http://lsk-ww.cn/ 1、简述 在Unity中&#xff0c;Camera 是一个至关重要的组件&#xff0c;用于渲染场景中的图像。无论是3D游戏还是2D游戏&#xff0c;Camera 都是必不可少的元素。通过合理配置和操作 Camer…

2024华数杯全国大学生数学建模竞赛B题思路-VLSI电路单元的自动布局-关键路径优化的多层划分算法

在粗化过程中&#xff0c;只考虑了如何匹配以使得后续划分 中有尽可能少的割边数&#xff0c;但没有将关键路径和割边的时延视为划分信息的一部分&#xff0c; 这可能导致关键路径较多地被切割&#xff0c;增加了关键路径时延&#xff0c;影响了并行度。另外&#xff0c; 初始划…

卡码网--数组篇(有序数组的平方)

系列文章目录 卡码网–数组篇(二分法) 卡码网–数组篇(移除元素) 文章目录 系列文章目录前言977.有序数组的平方 前言 代码随想录详情链接 977.有序数组的平方 力扣链接&#xff1a;https://leetcode.cn/problems/squares-of-a-sorted-array/description/ Step 1: 读题&…

Xinstall全链路数据统计,助力推广者破解社交分享难题

在数字营销的时代&#xff0c;社交分享推广已成为App运营的重要手段。然而&#xff0c;推广者们在进行社交分享推广时&#xff0c;往往面临着诸多痛点。其中&#xff0c;最关键的问题便是如何准确、高效地统计推广效果。今天&#xff0c;我们就来聊聊Xinstall这一神奇工具&…

【优秀python大屏】基于python flask的广州历史天气数据应用与可视化大屏

摘要 气象数据分析在各行各业中扮演着重要的角色&#xff0c;尤其对于农业、航空、海洋、军事、资源环境等领域。在这些领域中&#xff0c;准确的气象数据可以对预测未来的自然环境变化和采取行动来减轻负面影响的决策起到至关重要的作用。 本系统基于Python Flask框架&#…

五种IO模型(阻塞,非阻塞,多路复用[select, poll, epoll],信号驱动,异步IO)

五种IO模型&#xff08;阻塞&#xff0c;非阻塞&#xff0c;信号驱动[select, poll, epoll]&#xff0c;多路复用&#xff0c;异步IO&#xff09; 本章节代码&#xff1a;一&#xff0c;五种IO模型阻塞IO非阻塞IO多路复用&#xff08;也叫多路转接&#xff09;信号驱动异步IO例…

Solaris10(SPARC/x86)源码编译安装64位Python

Solaris10(SPARC/x86)源码编译安装64位Python 系统自带的Python版本为32位&#xff0c;需要安装64位版本Python。 solariskalami>python Python 3.3.6 (default, Mar 18 2016, 14:34:49) [GCC 5.2.0] on sunos5 Type "help", "copyright", "cred…

redis在Dokcer的安装使用

1 redis 安装和配置 # redis 是什么 开源&#xff1a;基于c编写的&#xff0c;早起版本2w3千行 基于键值对的存储系统&#xff1a;字典形式 多种数据结构&#xff1a;字符串&#xff0c;hash&#xff0c;列表&#xff0c;集合&#xff0c;有序集合 高性能&#xff0c;功能丰富…

ORB-SLAM2运行环境搭建

操作系统&#xff1a;Ubuntu20.04 1.安装Eigen3 推荐大家安装版本 3.2.10 链接&#xff1a;https://eigen.tuxfamily.org/index.php?titleMain_Page mkdir build cd build cmake .. sudo make install2.安装Pangolin 推荐安装0.5版本 链接&#xff1a;https://github.com…

【生成式AI-二-强大的AI下我们可以做什么】

强大的AI下我们可以做什么 人工智能的厉害之处我们可以作什么评估模型好坏的难度prompt engineering微调fine tune 人工智能的厉害之处 人工智能并不是忽然就爆火的&#xff0c;事实上&#xff0c;很久以前就已经有深度学习、机器学习这些概念了&#xff0c;那现在的人工智能和…

MybatisPlus常见注解及配置

什么是MybatisPlus? MybatisPlus&#xff08;简称MP&#xff09;是一个基于MyBatis的增强工具&#xff0c;它在MyBatis的基础上进行了扩展&#xff0c;旨在简化MyBatis的操作&#xff0c;提高开发效率。MybatisPlus继承了MyBatis原生的所有特性&#xff0c;并添加了一些额外的…

【C++刷题】优选算法——BFS第三辑

多源BFS问题解决&#xff1a;用 BFS 解决边权为1的多源最短路问题 解法一&#xff1a;把多源最短路问题转化为若干个单源最短路问题 解法二&#xff1a;把所有的源点当成一个“超级源点”&#xff0c;从而转化为单源最短路问题&#xff08;推荐&#xff09; 单源最短路问题的解…

Linux进程--进程查询和创建

目录 一、前言二、进程查询三、进程创建1.创建操作2.返回值疑云 一、前言 本篇文章的探讨是基于一定的进程理解的&#xff0c;在此基础上对有关进程的操作进行讲解。 二、进程查询 首先我们来认识一下进程查询的指令 ps ajx |head -1&& ps ajx |grep process |grep…

B1.5 EL0视角下的软件控制功能

快速链接: . 👉👉👉 ARMv8/ARMv9架构入门到精通-[目录] 👈👈👈 付费专栏-付费课程 【购买须知】个人博客笔记导读目录(全部) B1.5 EL0视角下的软件控制功能 以下章节描述了软件控制功能的EL0视图: 异常处理 等待中断和等待事件

Dubbo源码深度解析(二)

接着《Dubbo源码深度解析(一)》继续讲&#xff0c;上篇博客主要讲Dubbo提供的三个注解的作用&#xff0c;即&#xff1a;EnableDubbo、DubboComponentScan、EnableDubboConfig。其中后两个注解是在EnableDubbo上的&#xff0c;因此在启动类上加上EnableDubbo注解&#xff0c;等…

Java并发—volatile关键字的作用及使用场景

在这篇文章Java并发—Java内存模型以及线程安全-CSDN博客多次提及volatile关键字&#xff0c;这是一个非常重要的概念&#xff0c;主要用于多线程编程中&#xff0c;它确保了变量的可见性和禁止指令重排序&#xff0c;但不保证原子性&#xff0c;下面详细解释volatile关键字的作…