6.聊天室环境安装 - Ubuntu22.04 - elasticsearch(es)的安装和使用

news2025/3/11 14:09:31

目录

  • 介绍
  • 安装
  • 安装kibana
  • 安装ES客户端
  • 使用

介绍

Elasticsearch, 简称 ES,它是个开源分布式搜索引擎,它的特点有:分布式,零配置,自动发现,索引自动分片,索引副本机制,restful 风格接口,多数据源,自动搜索负载等。它可以近乎实时的存储、检索数据;本身扩展性很好,可以扩展到上百台服务器,处理 PB 级别的数据。es 也使用 Java 开发并使用 Lucene 作为其核心来实现所有索引和搜索的功能,但是它的目的是通过简单的 RESTful API 来隐藏 Lucene 的复杂性,从而让全文搜索变得简单。
Elasticsearch 是面向文档(document oriented)的,这意味着它可以存储整个对象或文档(document)。然而它不仅仅是存储,还会索引(index)每个文档的内容使之可以被搜索。在 Elasticsearch 中,你可以对文档(而非成行成列的数据)进行索引、搜索、排序、过滤。

安装

1.添加仓库密钥
wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo apt-key add -
2.添加镜像源仓库
echo "deb https://artifacts.elastic.co/packages/7.x/apt stable main" | sudo tee /etc/apt/sources.list.d/elasticsearch.list
3.更新软件包列表
sudo apt update
4.安装es
sudo apt-get install elasticsearch=7.17.21
5.安装ik分词器插件
sudo /usr/share/elasticsearch/bin/elasticsearch-plugin install https://get.infini.cloud/elasticsearch/analysis-ik/7.17.21
6.启动es
sudo systemctl start elasticsearch
6.5如果启动es失败
调整 ES 虚拟内存,虚拟内存默认最大映射数为 65530,无法满足 ES 系统要求,需要调整为 262144 以上
sysctl -w vm.max_map_count=262144
增加虚拟机内存配置
vim /etc/elasticsearch/jvm.options
新增如下内容:
-Xms512m
-Xmx512m
在这里插入图片描述

设置完后重启ubuntu
7.查看es服务的状态
sudo systemctl status elasticsearch.service
在这里插入图片描述
8.验证es是否安装成功
curl -X GET "http://localhost:9200/"
在这里插入图片描述
9.设置能够外部访问: 如果新配置完成默认只能在本机进行访问
vim /etc/elasticsearch/elasticsearch.yml
新增配置

network.host: 0.0.0.0
http.port: 9200
cluster.initial_master_nodes: ["node-1"]

在这里插入图片描述
重启后sudo systemctl restart elasticsearch.service
浏览器访问http://自己的IP:9200/
在这里插入图片描述

安装kibana

kibana可以支持通过网页对ES进行访问(增删查改), 这可以让我们的测试更加直观一些
1.安装kibana
sudo apt install kibana
2.配置kibana
sudo vim /etc/kibana/kibana.yml
在7行修改为server.host: "0.0.0.0"
在这里插入图片描述

在32行修改为elasticsearch.hosts: ["http://0.0.0.0:9200"]
在这里插入图片描述
3.启动kibana服务
sudo systemctl start kibana
4.验证安装
sudo systemctl status kibana
5.访问kibana
在浏览器访问kibana, http://你的ip:5601
在这里插入图片描述

安装ES客户端

1.克隆代码
git clone https://github.com/seznam/elasticlient
注意: 这里不能从github下载源码然后拖拽进来, 因为内部有git子模块, 需要去更新子模块之后, 才能去编译
如果无法始终clone不下来, 也有对应的解决方案:https://blog.csdn.net/eyuyanniniu/article/details/145807381
2.切换目录
cd elasticlient
3.安装 MicroHTTPD 库
sudo apt-get install libmicrohttpd-dev
4.更新子模块
git submodule update --init --recursive
5.编译安装代码
mkdir build
cd build
cmake ..
make
make install

6.配置环境变量
因为我们的库默认安装路径是/usr/local/lib, 编译器可能找不到这个库目录的位置
所以我们需要配置(这些文件最好都进行配置):
全局设置: /etc/profile 当前用户设置: .bash_profil或.bashrc
在文件末尾加上 export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH

使用

封装icsearch.hpp文件

#include <elasticlient/client.h>
#include <cpr/cpr.h>
#include <json/json.h>
#include <iostream>
#include <memory>
#include "logger.hpp"

//ES的二次封装, 原因: 为了简化ES的使用操作, 我们可以看到, 请求的时候, 正文很长, 我们希望只设置我们关心的参数即可, 而且能自动的构造完成
//封装四个操作: 索引创建, 数据新增, 数据查询, 数据删除

namespace wufan_im{
bool UnSerialize(const std::string& src, Json::Value& val)
{
    // 同样的Read类, 需要先构造出工厂类
    Json::CharReaderBuilder crb;
    std::unique_ptr<Json::CharReader> cr(crb.newCharReader());
    std::string err;
    bool ret = cr->parse(src.c_str(), src.c_str() + src.size(), &val, &err);
    if (ret == false) {
        std::cout << "json反序列化失败: " << err << std::endl;
        return false;
    }
    return true;
}

bool Serialize(const Json::Value& val, std::string& dst)
{
    // Writer(StreamWriter)类, 这个类就是用来序列化的, 但是这个类不能直接构造, 因为使用了工厂模式
    // 先定义Json::SreamWriter 工厂类 Json::StreamWriterBuilder
    Json::StreamWriterBuilder swb;  //构造出工厂类
    std::unique_ptr<Json::StreamWriter> sw(swb.newStreamWriter());
    // 通过Json::StreamWriter中的write接口进行序列化
    std::stringstream ss;
    int ret = sw->write(val, &ss);  //将其序列化到字符流里面
    if (ret != 0) {
        std::cout << "Json反序列化失败!\n";
        return false;
    }
    dst = ss.str();
    return true;
}

// 索引创建:
// 传两个参数, 索引名称 和 索引类型 就可以创建出索引
// 能够添加字段, 并设置字段类型, 设置分词器类型, 是否构造索引
class ESIndex{
    public:
        ESIndex(std::shared_ptr<elasticlient::Client>& client, const std::string& name, const std::string& type = "_doc")
        :_name(name), _type(type), _client(client)
        {
            Json::Value analysis;   //可以把Value当做Json里的{ }
            Json::Value analyzer;
            Json::Value ik;
            Json::Value tokenizer;
            tokenizer["tokenizer"] = "ik_max_word";
            ik["ik"] = tokenizer;
            analyzer["analyzer"] = ik;
            analysis["analysis"] = analyzer;
            _index["settings"] = analysis;
        }
        // 创建索引, 就相当于在设置表结构 - ai说的
        // 添加字段, 就相当于设置表的字段属性
        ESIndex& append(const std::string& key, const std::string& type = "text", 
        const std::string& analyzer = "ik_max_word", bool enabled = true) {
            Json::Value fields;
            fields["type"] = type;
            fields["analyzer"] = analyzer;
            if (enabled == false) fields["enabled"] = enabled;
            _properties[key] = fields;
            return *this;
        }
        bool create(const std::string& index_id = "default_index_id") {
            Json::Value mappings;
            mappings["dynamic"] = true;
            mappings["properties"] = _properties;
            _index["mappings"] = mappings;

            std::string body;
            bool ret = Serialize(_index, body);
            if (ret == false) {
                LOG_ERROR("索引序列化失败! ");
                return false;
            }
            
            LOG_DEBUG("{}", body);
            // 2. 发起搜索请求
            try{    //因为请求失败就可能会抛异常, 异常你不接住, 程序就会崩溃
                auto rsp = _client->index(_name, _type, index_id, body);
                if (rsp.status_code < 200 || rsp.status_code >= 300) {
                    LOG_ERROR("创建ES索引 {} 失败, 响应状态码异常: {}", _name, rsp.status_code);
                    return false;
                }
            } catch(std::exception& e) {
                LOG_ERROR("创建ES索引 {} 失败: {}", _name, e.what());
                return false;
            }
            return true;
        }
    private:
        std::string _name;
        std::string _type;
        Json::Value _properties;
        Json::Value _index;
        std::shared_ptr<elasticlient::Client> _client;
};

// 数据新增
class ESInsert{
    public:
        ESInsert(std::shared_ptr<elasticlient::Client>& client, const std::string& name,
                 const std::string& type = "_doc")
        :_name(name), _type(type), _client(client)
        {}
        ESInsert& append(const std::string& key, const std::string& val){
            _item[key] = val;
            return *this;
        }
        // 插入到哪个id里面 -  这个ID就相当于是每一次插入时数据的唯一标识
        bool insert(const std::string id = ""){
            std::string body;
            bool ret = Serialize(_item, body);
            if (ret == false) {
                LOG_ERROR("索引序列化失败! ");
                return false;
            }
            
            LOG_DEBUG("{}", body);
            // 2. 发起搜索请求
            try{    //因为请求失败就可能会抛异常, 异常你不接住, 程序就会崩溃
                auto rsp = _client->index(_name, _type, id, body);
                if (rsp.status_code < 200 || rsp.status_code >= 300) {
                    LOG_ERROR("新增数据 {} 失败, 响应状态码异常: {}", body, rsp.status_code);
                    return false;
                }
            } catch(std::exception& e) {
                LOG_ERROR("新增数据 {} 失败: {}", body, e.what());
                return false;
            }
            return true;
        }
    private:
        std::string _name;
        std::string _type;
        Json::Value _item;
        std::shared_ptr<elasticlient::Client> _client;
};


// 数据删除
class ESRemove{
    public:
        ESRemove(std::shared_ptr<elasticlient::Client>& client, const std::string& name, const std::string& type)
        :_name(name), _type(type), _client(client)
        {}
        bool remove(const std::string& id) {
            try{    //因为请求失败就可能会抛异常, 异常你不接住, 程序就会崩溃
                auto rsp = _client->remove(_name, _type, id);
                if (rsp.status_code < 200 || rsp.status_code >= 300) {
                    LOG_ERROR("删除数据 {} 失败, 响应状态码异常: {}", id, rsp.status_code);
                    return false;
                }
            } catch(std::exception& e) {
                LOG_ERROR("删除数据 {} 失败: {}", id, e.what());
                return false;
            }
            return true;
        }
    private:
        std::string _name;
        std::string _type;
        std::shared_ptr<elasticlient::Client> _client;
};


//数据查询
class ESSearch{
    public: //用户还会设置过滤条件,以及应该包含的字段
        ESSearch(std::shared_ptr<elasticlient::Client>& client, const std::string& name, const std::string& type = "_doc")
        :_name(name), _type(type), _client(client)
        {}
        ESSearch& append_must_not_terms(const std::string& key, const std::vector<std::string>& vals){
            Json::Value fields;
            for (const auto& val : vals) {
                fields[key].append(val);
            }
            Json::Value terms;
            terms["terms"] = fields;
            _must_not.append(terms);
            return *this;
        }
        ESSearch& append_should_match(const std::string& key, const std::string& val) {
            Json::Value field;
            field[key] = val;
            Json::Value match;
            match["match"] = field;
            _should.append(match);
            return *this;
        }
        Json::Value search() {
            Json::Value cond;
            if (_must_not.empty() == false) cond["must_not"] = _must_not;
            if (_should.empty() == false) cond["should"] = _should;
            Json::Value query;
            query["bool"] = cond;
            Json::Value root;
            root["query"] = query;
            std::string body;
            bool ret = Serialize(root, body);
            if (ret == false) {
                LOG_ERROR("索引序列化失败! ");
                return Json::Value();
            }
            LOG_DEBUG("{}", body);
            // 2. 发起搜索请求
            cpr::Response rsp;
            try{    //因为请求失败就可能会抛异常, 异常你不接住, 程序就会崩溃
                rsp = _client->search(_name, _type, body);
                if (rsp.status_code < 200 || rsp.status_code >= 300) {
                    LOG_ERROR("检索数据 {} 失败, 响应状态码异常: {}", body, rsp.status_code);
                    return Json::Value();
                }
            } catch(std::exception& e) {
                LOG_ERROR("检索数据 {} 失败: {}", body, e.what());
                return Json::Value();
            }
            //3. 需要对响应正文进行反序列化
            LOG_DEBUG("检索响应正文: [{}]", rsp.text);
            Json::Value json_res;
            ret = UnSerialize(rsp.text, json_res);
            if (ret == false) {
                LOG_ERROR("检索数据 {} 结果反序列化失败", rsp.text);
                return Json::Value();
            }
            return json_res["hits"]["hits"];
        }
    private:
        std::string _name;
        std::string _type;
        //用户还会设置过滤条件,以及应该包含的字段
        Json::Value _must_not;  //必须不包含的
        Json::Value _should;    //必须包含的, 多选一即可
        std::shared_ptr<elasticlient::Client> _client;
};
}

main.cc文件

#include "../../common/icsearch.hpp"
#include <gflags/gflags.h>

DEFINE_bool(run_mode, false, "程序的运行模式, false-调试; true-发布;");
DEFINE_string(log_file, "", "发布模式下, 用于指定日志的输出文件");
DEFINE_int32(log_level, 0, "发布模式下, 用于指定日志输出等级");

int main(int argc, char* argv[])
{
    google::ParseCommandLineFlags(&argc, &argv, true);
    wufan_im::init_logger(FLAGS_run_mode, FLAGS_log_file, FLAGS_log_level);
    std::shared_ptr<elasticlient::Client> client(new elasticlient::Client({"http://127.0.0.1:9200/"}));
    bool ret = wufan_im::ESIndex(client, "test_user")
        // 创建索引, 就相当于在设置表结构 - ai说的
        // 添加字段, 就相当于设置表的字段属性
        .append("nickname")
        .append("phone", "keyword", "standard", true) //手机号是不能进行分词的, 是一个关键字, 分词器用标准分词器, 需要构造索引
        .create();
    if (ret == false) {
        LOG_INFO("索引创建失败!");
        return -1;
    }
    LOG_INFO("索引创建成功");

    // 新增数据
    ret = wufan_im::ESInsert(client, "test_user")
        .append("nickname", "张三")
        .append("phone", "155666777")
        .insert("00001");   // 这个ID就相当于是每一次插入时数据的唯一标识
    if (ret == false) {
        LOG_ERROR("数据插入失败!");
        return -1;
    }
    // 数据的修改
    ret = wufan_im::ESInsert(client, "test_user")
        .append("nickname", "张三")
        .append("phone", "1334444555")
        .insert("00001");
    if (ret == false) {
        LOG_ERROR("数据更新失败!");
        return -1;
    }
    LOG_INFO("数据新增成功");

    Json::Value user = wufan_im::ESSearch(client, "test_user")
        .append_should_match("phone.keyword", "1334444555")     //检索的时候, 告诉ES, 这个关键词不要进行分词
        // .append_must_not_terms("nickname.keyword", {"张三"})
        .search();
    if (user.empty() || user.isArray() == false) {
        LOG_ERROR("结果为空, 或者结果不是数组类型");
        return -1;
    }
    LOG_INFO("数据检索成功");
    int sz = user.size();
    LOG_DEBUG("检索结果条目数量: {}", sz);
    for (int i = 0; i < sz; ++i) {
        LOG_INFO("nickname: {}", user[i]["_source"]["nickname"].asString());
    }

    ret = wufan_im::ESRemove(client, "test_user", "_doc").remove("00001");
    if (ret == false) {
        LOG_ERROR("删除数据失败");
        return -1;
    }
    LOG_INFO("数据删除成功");

    return 0;
}

运行程序:
在这里插入图片描述

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

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

相关文章

【python爬虫】酷狗音乐爬取练习

注意&#xff1a;本次爬取的音乐仅有1分钟试听&#xff0c;仅作学习爬虫的原理&#xff0c;完整音乐需要自行下载客户端。 一、 初步分析 登陆酷狗音乐后随机选取一首歌&#xff0c;在请求里发现一段mp3文件&#xff0c;复制网址&#xff0c;确实是我们需要的url。 复制音频的…

计算机视觉cv2入门之图像空域滤波(待补充)

空域滤波 空域滤波是指利用像素及像素领域组成的空间进行图像增强的方法。这里之所以用滤波这个词,是因为借助了频域里的概念。事实上空域滤波技术的效果与频域滤波技术的效果可以是等价的&#xff0c;而且有些原理和方法也常借助频域概念来解释。 原理和分类 空域滤波是在图…

游戏引擎学习第149天

今日回顾与计划 在今天的直播中&#xff0c;我们将继续进行游戏的开发工作&#xff0c;目标是完成资产文件&#xff08;pack file&#xff09;的测试版本。目前&#xff0c;游戏的资源&#xff08;如位图和声音文件&#xff09;是直接从磁盘加载的&#xff0c;而我们正在将其转…

PyCharm 接入 DeepSeek、OpenAI、Gemini、Mistral等大模型完整版教程(通用)!

PyCharm 接入 DeepSeek、OpenAI、Gemini、Mistral等大模型完整版教程&#xff08;通用&#xff09;&#xff01; 当我们成功接入大模型时&#xff0c;可以选中任意代码区域进行解答&#xff0c;共分为三个区域&#xff0c;分别是选中区域、提问区域以及回答区域&#xff0c;我…

升级到碳纤维齿轮是否值得?

引言&#xff1a;当齿轮开始“减肥” 在F1赛车的变速箱里&#xff0c;一个齿轮的重量减轻100克&#xff0c;就能让圈速提升0.1秒&#xff1b; 在无人机旋翼传动系统中&#xff0c;轻量化齿轮可延长续航时间15%&#xff1b; 甚至在高端机械腕表中&#xff0c;碳纤维齿轮的引入…

基于SpringBoot+Vue的瑜伽课体验课预约系统【附源码】

基于SpringBootVue的瑜伽课体验课预约系统 一、系统技术说明二、运行说明三、系统的演示四、系统的核心代码演示 一、系统技术说明 框架&#xff1a;SpringbootVue 数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09; 数据库工具&#xff1a;Navicat11 开发软…

文章被检测出是AI写的怎么办?

随着人工智能技术的飞速发展&#xff0c;AI辅助写作工具逐渐普及&#xff0c;为学生、科研人员以及创作者带来了诸多便利。然而&#xff0c;随之而来的是对学术诚信和内容原创性的担忧。当文章被检测出是AI写作时&#xff0c;应该如何应对&#xff1f;本文将探讨这一问题&#…

DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加列宽调整功能,示例Table14基础固定表头示例

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享一篇文章&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 目录 Deep…

【英伟达AI论文】多模态大型语言模型的高效长视频理解

摘要&#xff1a;近年来&#xff0c;基于视频的多模态大型语言模型&#xff08;Video-LLMs&#xff09;通过将视频处理为图像帧序列&#xff0c;显著提升了视频理解能力。然而&#xff0c;许多现有方法在视觉主干网络中独立处理各帧&#xff0c;缺乏显式的时序建模&#xff0c;…

[Lc10_hash] 总结 | 两数之和 | 字符重排 | 存在重复元素 i ii | 字母异位词分组

目录 1.介绍 2.两数之和 题解 3.面试题 01.02. 判定是否互为字符重排 题解 4.存在重复元素 题解 5.存在重复元素 II 题解 ⭕6.字母异位词分组 题解 1.介绍 哈希表是什么? 存储数据的容器前文&#xff1a;[C_] set | map | unordered_map 有什么用呢&#xff1f;…

缓存之美:Guava Cache 相比于 Caffeine 差在哪里?

大家好&#xff0c;我是 方圆。本文将结合 Guava Cache 的源码来分析它的实现原理&#xff0c;并阐述它相比于 Caffeine Cache 在性能上的劣势。为了让大家对 Guava Cache 理解起来更容易&#xff0c;我们还是在开篇介绍它的原理&#xff1a; Guava Cache 通过分段&#xff08;…

小组件适配屏幕主题色

iOS 18 新增Home screen Tint Color&#xff08;色调&#xff09;选择&#xff0c;用户可以通过以下方式自定义主屏幕颜色&#xff0c;并且小组件&#xff0c;APP 图标也会跟随改颜色。 比如说意料之外的小组件&#xff08;不兼容&#xff09; 白色部分内部应该还有其他显示内…

IO学习---->线程

1.创建两个线程&#xff0c;分支线程1拷贝文件的前一部分&#xff0c;分支线程2拷贝文件的后一部分 #include <head.h> sem_t sem; long half_size 0; // 全局变量&#xff0c;供所有线程共享void* product(void *arg) {FILE *src fopen("IO.text", "…

个人记录,Unity资源解压和管理插件

就是经典的两个AssetStudio 和 Ripper 没有什么干货&#xff0c;就是记录一下&#xff0c;内容没有很详细 AssetStudio 说错了&#xff0c;AssetStudio比较出名&#xff08;曾经&#xff09;&#xff0c;但好像堕落了 这个工具有个好处就是分类选择&#xff0c;&#xff08;…

day19-前端Web——Vue3+TS+ElementPlus

目录 1. Vue工程化1.1 介绍1.2 环境准备1.2.1 NodeJS安装双击安装包选择安装目录验证NodeJS环境变量配置npm的全局安装路径 1.3 Vue项目-创建1.4 Vue项目开发流程1.5 API风格1.6 案例 2. TS2.1 概述2.2 快速入门2.3 常用类型2.3.1 基础类型2.3.2 联合类型2.3.3 函数类型2.3.4 对…

隐私保护在 Facebook 用户身份验证中的应用

在这个数字化的时代&#xff0c;个人隐私保护成为了公众关注的焦点。社交媒体巨头 Facebook 作为全球最大的社交平台之一&#xff0c;拥有数十亿用户&#xff0c;其在用户身份验证过程中对隐私保护的重视程度直接影响着用户的安全感和信任度。本文将探讨 Facebook 在用户身份验…

【JavaWeb学习Day23】

Maven高级 分模块设计与开发 分模块设计&#xff1a;将一个大项目分成若干个子模块&#xff0c;方便项目的维护、扩展&#xff0c;也方便模块间的相互引用&#xff0c;资源共享。 策略&#xff1a; 1.策略一&#xff1a;按照功能模块拆分&#xff0c;比如&#xff1a;公共组…

个人记录的一个插件,Unity-RuntimeMonitor

没有什么干货,仅仅是个人的记录 基于GUI做的一个工具:好处就是Monitor必须,Unity天然支持实时的Monitor;唯一不好处,就是默认字体太小了,layout居中,居右也是要自行设计的。 (下面文字是有一点点写错,但意思和功能就很牛逼了;并不是都按2 x shift,而是一个 shift 添…

【NexLM 开源系列】如何封装多个大模型 API 调用

&#x1f31f; 在这系列文章中&#xff0c;我们将一起探索如何搭建一个支持大模型集成项目 NexLM 的开发过程&#xff0c;从 架构设计 到 代码实战&#xff0c;逐步搭建一个支持 多种大模型&#xff08;GPT-4、DeepSeek 等&#xff09; 的 一站式大模型集成与管理平台&#xff…

Git和GitHub基础教学

文章目录 1. 前言2. 历史3. 下载安装Git3.1 下载Git3.2 安装Git3.3 验证安装是否成功 4. 配置Git5. Git基础使用5.1 通过Git Bash使用5.1.1 创建一个新的仓库。5.1.1.1 克隆别人的仓库5.1.1.2 自己创建一个本地仓库 5.1.2 管理存档 5.2 通过Visual Studio Code使用 6. Git完成远…