是时候用 ES 拯救发际线啦
Easysearch

Easysearch

Easysearch Java SDK 2.0.x 使用指南(一)

EasysearchINFINI Labs 小助手 发表了文章 • 0 个评论 • 1305 次浏览 • 2024-12-14 17:50 • 来自相关话题

各位 Easysearch 的小伙伴们,我们前一阵刚把 easysearch-client 更新到了 2.0.2 版本!借此详细介绍下新版客户端的使用。

新版客户端和 1.0 版本相比,完全重构,抛弃了旧版客户端的一些历史包袱,从里到外都焕然一新!不管是刚入门的小白还是经验丰富的老司机,2.0.x 客户端都能让你开发效率蹭蹭往上涨!

到底有啥新东西?

  • 更轻更快: 以前的版本依赖了一堆乱七八糟的东西,现在好了,我们把那些没用的都砍掉了,客户端变得更苗条,性能也杠杠的!
  • 类型安全,告别迷糊: 常用的 Easysearch API 现在都配上了强类型的请求和响应对象,再也不用担心写错参数类型了,代码也更好看了,维护起来也更省心!
  • 同步异步,想咋用咋用: 所有 API 都支持同步和异步两种调用方式,不管是啥场景,都能轻松应对!
  • 构建查询,跟搭积木一样简单: 我们用了流式构建器和函数式编程,构建复杂查询的时候,代码写起来那叫一个流畅,看着也舒服!
  • 和 Jackson 无缝对接: 可以轻松地把你的 Java 类和客户端 API 关联起来,数据转换嗖嗖的快!

快速上手

废话不多说,咱们直接上干货!这部分教你怎么快速安装和使用 easysearch-client 2.0.2 客户端,还会演示一些基本操作。

安装

easysearch-client 2.0.2 已经上传到 Maven 中央仓库了,加到你的项目里超级方便。

最低要求: JDK 8 或者更高版本

依赖管理: 客户端内部用 Jackson 来处理对象映射。

Maven 项目

在你的 pom.xml 文件的 <dependencies> 里面加上这段:

<dependencies>
    <dependency>
        <groupId>com.infinilabs</groupId>
        <artifactId>easysearch-client</artifactId>
        <version>2.0.2</version>
    </dependency>
</dependencies>

Gradle 项目

在你的 build.gradle 文件的 dependencies 里面加上这段:

dependencies {
    implementation 'com.infinilabs:easysearch-client:2.0.2'
}

初始化客户端

下面这段代码演示了怎么初始化一个启用了安全通信加密和 security 的 Easysearch 客户端,看起来有点长,别慌,我们一步一步解释!

 public static EasysearchClient create() throws NoSuchAlgorithmException, KeyStoreException,
        KeyManagementException {

        final HttpHost[] hosts = new HttpHost[]{new HttpHost("localhost", 9200, "https")};

        final SSLContext sslContext = SSLContextBuilder.create()
            .loadTrustMaterial(null, (chains, authType) -> true).build();
        SSLIOSessionStrategy sessionStrategy = new SSLIOSessionStrategy(sslContext, NoopHostnameVerifier.INSTANCE);

        final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
        credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials("username", "passwowd"));

        RestClient restClient = RestClient.builder(hosts)
            .setHttpClientConfigCallback(httpClientBuilder ->
                httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider)
                    .setSSLStrategy(sessionStrategy)
                    .disableAuthCaching()
            ).setRequestConfigCallback(requestConfigCallback ->
            requestConfigCallback.setConnectTimeout(30000).setSocketTimeout(300000))
            .build();

        EasysearchTransport transport = new RestClientTransport(
            restClient, new JacksonJsonpMapper());
        return new EasysearchClient(transport);
    }

这段代码,简单来说,就是:

  1. 连上 Easysearch: 我们要用 HTTPS 连接到本地的 9200 端口。
  2. 搞定证书: 这里为了方便,我们信任了所有证书(注意!生产环境一定要配置好你们自己的证书)。
  3. 填上用户名密码: 这里需要填上你的用户名和密码。
  4. 设置连接参数: 设置了连接超时时间(30 秒)和读取超时时间(300 秒)。
  5. 创建客户端: 最后,我们就创建好了一个 EasysearchClient 实例,可以开始干活了!

举个栗子:批量操作

下面的例子演示了怎么用 bulk API 来批量索引数据:

 public static void bulk() throws Exception {

        String json2 = "{"
            + "    \"@timestamp\": \"2023-01-08T22:50:13.059Z\","
            + "    \"agent\": {"
            + "      \"version\": \"7.3.2\","
            + "      \"type\": \"filebeat\","
            + "      \"ephemeral_id\": \"3ff1f2c8-1f7f-48c2-b560-4272591b8578\","
            + "      \"hostname\": \"ba-0226-msa-fbl-747db69c8d-ngff6\""
            + "    }"
            + "}";

        EasysearchClient client = create();

        BulkRequest.Builder br = new BulkRequest.Builder();
        br.index("test1");
        for (int i = 0; i < 10; i++) {
            BulkOperation.Builder builder = new BulkOperation.Builder();
            IndexOperation.Builder indexBuilder = new IndexOperation.Builder();
            builder.index(indexBuilder.document(JsonData.fromJson(json2)).build());
            br.operations(builder.build());
        }

        for (int i = 0; i < 10; i++) {
            BulkOperation.Builder builder = new BulkOperation.Builder();
            IndexOperation.Builder indexBuilder = new IndexOperation.Builder();
            indexBuilder.document(JsonData.fromJson(json2)).index("test2");
            builder.index(indexBuilder.build());
            br.operations(builder.build());
        }

        for (int i = 0; i < 10; i++) {
            Map<String, Object> map = new HashMap<>();
            map.put("@timestamp", "2023-01-08T22:50:13.059Z");
            map.put("field1", "value1");
            IndexOperation.Builder indexBuilder = new IndexOperation.Builder();
            indexBuilder.document(map).index("test3");
            br.operations(new BulkOperation(indexBuilder.build()));
        }

        BulkResponse bulkResponse = client.bulk(br.build());
        if (bulkResponse.errors()) {
            for (BulkResponseItem item : bulkResponse.items()) {
                System.out.println(item.toString());
            }
        }
        client._transport().close();

    }

这个例子里,我们一口气把数据批量索引到了 test1test2test3 这三个索引里, 并且展示了三种在 bulk API 中构建 IndexOperation 的方式,虽然它们最终都能实现将文档索引到 Easysearch,但在使用场景和灵活性上还是有一些区别的:

这段代码的核心是利用 BulkRequest.Builder 来构建一个批量请求,并通过 br.operations(...) 方法添加多个操作。而每个操作,在这个例子里,都是一个 IndexOperation,也就是索引一个文档。IndexOperation 可以通过 IndexOperation.Builder 来创建。

三种方式的区别主要体现在如何构建 IndexOperation 里的 document 部分,也就是要索引的文档内容。

第一种方式:使用 JsonData.fromJson(json2) 且不指定索引。

特点:
使用 JsonData.fromJson(json2) 将一个 JSON 字符串直接转换成 JsonData 对象作为文档内容。
这里没有在 IndexOperation.Builder 上调用 index() 方法来指定索引名称。由于没有在每个 IndexOperation 中指定索引,这个索引名称将回退到 BulkRequest.Builder 上设置的索引,即 br.index("test1"),所以这 10 个文档都会被索引到 test1。
当你需要将一批相同结构的 JSON 文档索引到同一个索引时,这种方式比较简洁。

第二种方式:使用 JsonData.fromJson(json2) 并指定索引

特点:
同样使用 JsonData.fromJson(json2) 将 JSON 字符串转换成 JsonData 对象。
关键区别在于,这里在 IndexOperation.Builder 上调用了 index("test2"),为每个操作单独指定了索引名称。
这 10 个文档会被索引到 test2,即使 BulkRequest.Builder 上设置了 index("test1") 也没用,因为 IndexOperation 里的设置优先级更高。
当你需要将一批相同结构的 JSON 文档索引到不同的索引时,就需要使用这种方式来分别指定索引。

第三种方式:使用 Map<String, Object> 并指定索引

特点:
使用 Map<String, Object> 来构建文档内容,这种方式更加灵活,可以构建任意结构的文档。
同样在 IndexOperation.Builder 上调用了 index("test3") 指定了索引名称。 使用 new BulkOperation(indexBuilder.build()) 代替之前的 builder.index(indexBuilder.build()), 这是等价的。 这 10 个文档会被索引到 test3。
当你需要索引的文档结构不固定,或者你需要动态构建文档内容时,使用 Map 是最佳选择。例如,你可以根据不同的业务逻辑,往 Map 里添加不同的字段。

总结

这次 easysearch-client 2.0.x Java 客户端的更新真的很给力,强烈建议大家升级体验!相信我,用了新版客户端,你的开发效率绝对会提升一大截!


想要了解更多?

大家有啥问题或者建议,也欢迎随时反馈!

作者:张磊,极限科技(INFINI Labs)搜索引擎研发负责人,对 Elasticsearch 和 Lucene 源码比较熟悉,目前主要负责公司的 Easysearch 产品的研发以及客户服务工作。

极限科技(INFINI Labs)招聘:搜索运维工程师(Elasticsearch/Easysearch)【北京/全职】

求职招聘INFINI Labs 小助手 发表了文章 • 0 个评论 • 5648 次浏览 • 2024-09-28 11:00 • 来自相关话题

20240928-180457.png

我们是国内搜索型数据库产品厂商第一梯队的杰出代表,随着业务的快速发展,现开放岗位:搜索运维工程师( Elasticsearch/Easysearch ),如果有兴趣,请直接拉到文末,扫描二维码或将简历投递至 hello@infini.ltd。

如果您还不了解 极限科技(INFINI Labs)是谁,在做什么,需要什么样的小伙伴,那么请看下文:

我们是谁

INFINI Labs

极限科技,全称极限数据(北京)科技有限公司,是一家专注于实时搜索与数据分析的软件公司。旗下品牌极限实验室(INFINI Labs)致力于打造极致易用的数据探索与分析体验。

极限科技是一支年轻的团队,采用天然分布式的方式来进行远程协作,员工分布在全球各地,希望通过努力成为中国乃至全球企业大数据实时搜索分析产品的首选,为中国技术品牌输出添砖加瓦。

官网:https://infinilabs.cn

我们在做什么

极限科技(INFINI Labs)正在致力于以下几个核心方向:

1、开发近实时搜索引擎 INFINI Easysearch

INFINI Easysearch 是一个分布式的搜索型数据库,实现非结构化数据检索、全文检索、向量检索、地理位置信息查询、组合索引查询、多语种支持、聚合分析等。Easysearch 可以完美替代 Elasticsearch,同时添加和完善多项企业级功能。Easysearch 助您拥有简洁、高效、易用的搜索体验。详情参见:https://infinilabs.cn

2、打造下一代实时搜索引擎 INFINI Pizza

INFINI Pizza 是一个分布式混合搜索数据库系统。我们的使命是充分利用现代硬件和人工智能的潜力,为企业提供量身定制的实时智能搜索体验。我们致力于满足具有挑战性的环境中高并发和高吞吐量的需求,同时提供无缝高效的搜索功能。详情参见:https://pizza.rs

3、积极参与全球开源生态建设

通过开源项目和社区贡献,推动全球开源技术的发展,提升中国在全球开源领域的影响力。

4、提供专业服务

为客户提供包括搜索技术支持、迁移服务、定制解决方案和培训在内的全方位服务。

5、提供国产化搜索解决方案

针对中国市场的特殊需求,提供符合国产化标准的搜索产品和解决方案,帮助客户解决使用 Elasticsearch 时遇到的挑战。

极限科技(INFINI Labs)通过这些努力,旨在成为全球领先的实时搜索和数据分析解决方案提供商。

我们期待有才华、有激情的你加入我们,一起探索数据搜索的未来,共同创造无限可能!

在招岗位介绍

岗位名称

搜索运维工程师(Elasticsearch/Easysearch)

岗位职责

  1. 负责客户现场的 Elasticsearch/Easysearch/OpenSearch 搜索引擎集群的日常维护、监控和优化,确保集群的高可用性和性能稳定;
  2. 协助客户进行搜索引擎集群的部署、配置及版本升级;
  3. 排查和解决 Elasticsearch/Easysearch/OpenSearch 集群中的各种技术问题,及时响应并处理集群异常;
  4. 根据业务需求设计和实施搜索索引的调优、数据迁移和扩展方案;
  5. 负责与客户沟通,提供技术支持及相关培训,确保客户需求得到有效满足;
  6. 制定并实施搜索引擎的备份、恢复和安全策略,保障数据安全;
  7. 与内部研发团队和外部客户进行协作,推动集群性能改进和功能优化。

岗位要求

  1. 全日制本科及以上学历,5 年以上运维工作经验;
  2. 拥有 Elasticsearch/Easysearch/OpenSearch 使用经验,熟悉搜索引擎的原理、架构和相关生态工具(如 Logstash、Kibana 等);
  3. 熟悉 Linux 操作系统的使用及常见性能调优方法;
  4. 熟练掌握 Shell 或 Python 等至少一种脚本语言,能够编写自动化运维脚本;
  5. 具有优秀的问题分析与解决能力,能够快速应对突发情况;
  6. 具备良好的沟通能力和团队合作精神,能够接受 客户驻场工作;
  7. 全职,北京地区,需具备在北京长期工作的条件;

优先考虑

  • 计算机科学、信息技术或相关专业;
  • 具备丰富的大规模分布式系统运维经验;
  • 熟悉 Elasticsearch/Easysearch/OpenSearch 分片、路由、查询优化等高级功能;
  • 拥有 Elastic Certified Engineer 认证;
  • 具备大规模搜索引擎集群设计、扩展和调优经验;
  • 熟悉其他搜索引擎技术(如 Solr、Lucene)者优先 ;
  • 熟悉大数据处理相关技术(比如: Kafka 、Flink 等)者优先。

福利待遇

  • 月薪: 15K - 25K,具体根据能力而定,试用期为 3-6 个月;
  • 福利:五险一金/双休/国内法定假日/带薪年假等;

简历投递

简历投递:hello@infini.ltd(邮件标题请备注姓名+求职岗位+来自搜索客社区)
微信联系:INFINI-Labs(加微请备注求职岗位+来自搜索客社区)

欢迎有兴趣的小伙伴联系或推荐,期待您的加入!

联系我们

【第3期】INFINI Easysearch 免费认证培训开放报名

EasysearchINFINI Labs 小助手 发表了文章 • 0 个评论 • 5537 次浏览 • 2024-09-13 17:43 • 来自相关话题

20240913-144305.png

探索 Easysearch 的无限可能,与 INFINI Labs 共赴搜索技术前沿!

随着数字化转型的加速,搜索技术已成为企业数据洞察的核心。INFINI Labs 作为搜索创新技术的引领者,诚邀所有对 Easysearch 搜索引擎感兴趣的开发者、技术爱好者及合作伙伴,参加我们即将于 2024 年 10 月 19 日至 20 日举办的第 3 期 Easysearch 线上免费培训活动。这不仅是一场知识的盛宴,更是技能提升的加速器,将助您在职业道路上迈出坚实的一步!

活动亮点

  • 系统课程,全面深入:从 Easysearch 的基本概念到环境搭建,再到高级功能的实战应用,INFINI Labs 的技术专家将为您带来全面而深入的讲解,确保每位参与者都能收获满满。
  • 实战导向,解决痛点:课程设计紧贴实际需求,旨在帮助学员掌握 Easysearch 的核心技术,有效解决工作中的搜索需求和技术难题,让理论知识迅速转化为实践能力。
  • 认证证书,助力进阶:后期 INFINI Labs 将推出 Easysearch 认证考试。通过考试的学员将获得官方认证的 Easysearch 证书,为您的职业发展增添强力背书,开启职业生涯的新篇章。

培训时间

2024 年 10 月 19 日至 20 日(周六、周日)共两天,每天具体培训时间:

  • 上午 09:30 ~ 11:30
  • 下午 14:00 ~ 16:00

培训内容概览

第一阶段:初识 Easysearch

  • Easysearch 环境搭建与对比,了解其与 Elasticsearch 的差异;
  • 功能初探:身份验证、数据脱敏、权限控制等,全面掌握 Easysearch 的基础功能;
  • 容灾技术:兼容性验证、跨集群复制等,确保您的搜索服务稳定可靠;

第二阶段:Easysearch 高阶使用

  • 深度探析:性能压测、数据迁移、请求管理等,提升 Easysearch 的使用效率;
  • 高级功能:快照管理、可视化看板、告警功能等,让您的搜索服务更加智能;
  • 生态集成:Filebeat、Logstash、LangChain 等,轻松实现 Easysearch 与其他工具的集成;

参与方式

本次活动完全免费,名额有限,请尽快报名,同时微信扫码添加小助手进群(培训会议地址将在微信群公布),锁定您的学习席位!

扫码或点击 我要报名

报名

👉 立即行动:不要错过这次提升自我、与行业精英共成长的宝贵机会。让我们相聚云端,共同探索 Easysearch 的无限可能,开启技术进阶的新篇章!

参会提示

  • 培训内容涉及动手实践,请务必自备电脑(Windows 系统环境请提前安装好 Linux 虚拟机);
  • 请提前在 INFINI Labs 官网下载对应平台最新安装包(INFINI Easysearch、INFINI Gateway、INFINI Console);
  • 下载地址:https://infinilabs.cn/download

联系我们

如有任何疑问,欢迎通过微信添加 [小助手:INFINI-Labs] 与我们联系。

INFINI Labs 期待与您相约,共赴这场技术盛宴!

关于 Easysearch

Easysearch

Easysearch 是一个分布式的近实时搜索与分析引擎,基于开源的 Apache Lucene 构建。它旨在提供一个自主可控、轻量级的 Elasticsearch 可替代版本,并不断完善和支持更多的企业级功能。与 Elasticsearch 相比,Easysearch 更注重搜索业务场景的优化,同时保持其产品的简洁与易用性。

详情参见:Easysearch 介绍

关于极限科技(INFINI Labs)

INFINI Labs

极限科技,全称极限数据(北京)科技有限公司,是一家专注于实时搜索与数据分析的软件公司。旗下品牌极限实验室(INFINI Labs)致力于打造极致易用的数据探索与分析体验。

极限科技是一支年轻的团队,采用天然分布式的方式来进行远程协作,员工分布在全球各地,希望通过努力成为中国乃至全球企业大数据实时搜索分析产品的首选,为中国技术品牌输出添砖加瓦。

官网:https://infinilabs.cn

如何用 Scrapy 爬取网站数据并在 Easysearch 中进行存储检索分析

EasysearchINFINI Labs 小助手 发表了文章 • 0 个评论 • 5153 次浏览 • 2024-09-13 12:28 • 来自相关话题

做过数据分析和爬虫程序的小伙伴想必对 Scrapy 这个爬虫框架已经很熟悉了。今天给大家介绍下,如何基于 Scrapy 快速编写一个爬虫程序并利用 Easysearch 储存、检索、分析爬取的数据。我们以极限科技的官网 Blog 为数据源(https://infinilabs.cn/blog) ,做下实操演示。

1、安装 scrapy

使用 Scrapy 可以快速构建一个爬虫项目,从目标网站中获取所需的数据,并进行后续的处理和分析。

pip install scrapy

# 新建项目 infini_spiders
scrapy startproject infini_spiders

# 初始化爬虫
cd infini_spiders/spiders
scrapy genspider blog infinilabs.cn

2、爬虫编写

编写一个爬虫文件 blog.py ,它会首先访问 start_urls 指定的地址,将结果发给 parse 函数解析。通过这一步解析,我们得到了每一篇博客的地址。然后我们对每个博客的地址发送请求,将结果发给 parse_blog 函数进行解析,在这里才会真正提取每篇博客的 title、tag、url、date、content 内容。

from typing import Any, Iterable
import scrapy
from bs4 import BeautifulSoup
from scrapy.http import Response

class BlogSpider(scrapy.Spider):
    name = "blog"
    allowed_domains = ["infinilabs.cn"]
    start_urls = ["https://infinilabs.cn/blog/"]

    def parse(self, response):
        links = response.css("div.blogs a")
        yield from response.follow_all(links, self.parse_blog)

    def parse_blog(self, response):
        title = response.xpath('//div[@class="title"]/text()').extract_first()
        tags = response.xpath('//div[@class="tags"]/div[@class="tag"]/text()').extract()
        url = response.url
        author = response.xpath('//div[@class="logo"]/div[@class="name"]//text()').extract_first()
        date = response.xpath('//div[@class="date"]/text()').extract_first()
        all_text = response.xpath('//p//text() | //h3/text() | //h2/text() | //h4/text() | //ol/li//text()').extract()
        content = '\n'.join(all_text)

        yield {
            'title': title,
            'tags': tags,
            'url': url,
            'author': author,
            'date': date,
            'content': content
        }

提取完我们想要的内容后,接下来就要考虑存储了。考虑到要对内容进行检索、分析,接下来我们将内容直接存放到 Easysearch 当中。

3、安装插件

通过安装 ScrapyElasticsearch pipeline 可将 scrapy 爬取的内容存入到 Easysearch 中。

pip install ScrapyElasticSearch

修改 scrapy 自带的配置文件 settings.py ,添加以下内容。

ITEM_PIPELINES = {
    'scrapyelasticsearch.scrapyelasticsearch.ElasticSearchPipeline': 10
}

ELASTICSEARCH_SERVERS = ['http://192.168.56.3:9210']
ELASTICSEARCH_INDEX = 'scrapy'
ELASTICSEARCH_INDEX_DATE_FORMAT = '%Y-%m-%d'
ELASTICSEARCH_TYPE = '_doc'
ELASTICSEARCH_USERNAME = 'admin'
ELASTICSEARCH_PASSWORD = '9423d1d5345ed6d0db19'

ScrapyElasticSearch 会以 bulk 方式写入 Easysearch,每次批量的大小由 scrapyelasticsearch.scrapyelasticsearch.ElasticSearchPipeline 参数控制,大家可自行修改。

在上述配置中,我们会将爬到的数据存放到 scrapy-yyyy-mm-dd 索引中。

4、启动爬虫

在 infini_spiders/spiders 目录下,使用命令启动爬虫。

scrapy crawl blog

blog 就是爬虫的名字,对应到 blog.py 里面的 name 变量。运行完成后,就可以去 Easysearch 里查看数据了,当然我们还是使用 Console 进行查看。

5、查看数据

先查看下索引情况,scrapy 索引已经生成,里面有 129 篇博客。

查看详细内容,确保博客正文已经保存。

到了这一步,我们就能使用 Console 对博客进行搜索、分析了。

6、结语

这次的分享就到这里了。欢迎与我一起交流 ES 的各种问题和解决方案。

关于 Easysearch

INFINI Easysearch 是一个分布式的近实时搜索与分析引擎,核心引擎基于开源的 Apache Lucene。Easysearch 的目标是提供一个轻量级的 Elasticsearch 可替代版本,并继续完善和支持更多的企业级功能。 与 Elasticsearch 相比,Easysearch 更关注在搜索业务场景的优化和继续保持其产品的简洁与易用性。

官网文档:https://infinilabs.cn/docs/latest/easysearch

作者:杨帆
原文:https://infinilabs.cn/blog/2024/use-scrapy-to-crawl-website-data-and-store-search-analyze-in-easysearch/

Easysearch 性能测试方法概要

EasysearchINFINI Labs 小助手 发表了文章 • 0 个评论 • 2785 次浏览 • 2024-08-23 14:47 • 来自相关话题

20240813-e1ba1e73-53ad-4265-8db9-f71e56b5d626.png

INFINI Easysearch

INFINI Easysearch 是一个分布式的近实时搜索与分析引擎,核心引擎基于开源的 Apache Lucene。Easysearch 衍生自基于开源协议 Apache 2.0 的 Elasticsearch 7.10 版本,完善和支持更多的企业级功能,优化搜索业务场景,以保证更佳的数据探索与分析体验。

Easysearch 的主要特点:

  • 兼容 Elasticsearch,业务代码无需改动;可平滑迁移
  • 企业级安全;更稳定可靠
  • 企业级管理后台(多集群统一管理,实现运营标准化、自动化)
  • 信创适配(全面适配国产 CPU/OS/服务器,支持国密算法)

Easysearch 快速体验,请参阅:

Easysearch,地表最强,没有之一!

Loadgen

Loadgen 是 Elasticsearch 专属压测工具,用来对 Easysearch 或者网关进行压力测试。

Loadgen 的特点:

  • 性能强劲
  • 轻量级无依赖
  • 支持模板化参数随机
  • 支持高并发
  • 支持压测端均衡流量控制
  • 支持服务端返回值校验

当前最新版本为 1.26.1-598,下载链接如下:

https://release.infinilabs.com/loadgen/stable/

下载并解压安装包后,得到二进制文件。

查看版本信息。

$ ./loadgen-linux-amd64 -v
   __   ___  _      ___  ___   __    __
  / /  /___\/_\    /   \/ _ \ /__\/\ \ \
 / /  //  ///_\\  / /\ / /_\//_\ /  \/ /
/ /__/ \_//  _  \/ /_// /_\\//__/ /\  /
\____|___/\_/ \_/___,'\____/\__/\_\ \/

[LOADGEN] A http load generator and testing suite.
[LOADGEN] 1.26.1#598, 2024-08-14 04:50:03, 2024-12-31 10:10:10, 00f15fd86834d7ea539f6d66ee608e3915eef0e3
loadgen 1.26.1 598 2024-08-14 04:50:03 +0000 UTC 2024-12-31 10:10:10 +0000 UTC 00f15fd86834d7ea539f6d66ee608e3915eef0e3

Loadgen 测试

Loadgen 使用非常简单,下面演示如何进行查询压测。

  1. 建立索引,根据节点数调节分片数。
curl -X PUT -H "Content-Type: application/json" \
-ku admin:xxx "https://localhost:9200/loadtest" -d'
{
  "settings":{
    "number_of_shards":"3",
    "number_of_replicas":1,
    "translog":{
      "durability":"async"
    }
  }
}'
{"acknowledged":true,"shards_acknowledged":true,"index":"loadtest"}
  1. 创建 loadgen.dsl.shawnyan 配置文件,定义查询
GET loadtest/_search
{"query": {"term": {"id.keyword": {"value": $[[id]]}}}}
  1. 执行压测,-d 表示秒数,-c 表示并发数。
$ ES_ENDPOINT=https://localhost:9200 ES_USERNAME=admin ES_PASSWORD=xxx ./loadgen-linux-amd64 -run loadgen.dsl.shawnyan -d 10 -c 2
   __   ___  _      ___  ___   __    __
  / /  /___\/_\    /   \/ _ \ /__\/\ \ \
 / /  //  ///_\\  / /\ / /_\//_\ /  \/ /
/ /__/ \_//  _  \/ /_// /_\\//__/ /\  /
\____|___/\_/ \_/___,'\____/\__/\_\ \/

[LOADGEN] A http load generator and testing suite.
[LOADGEN] 1.26.1#598, 2024-08-14 04:50:03, 2024-12-31 10:10:10, 00f15fd86834d7ea539f6d66ee608e3915eef0e3
[08-19 16:43:27] [INF] [env.go:179] configuration auto reload enabled
[08-19 16:43:27] [INF] [app.go:285] initializing loadgen, pid: 30792
[08-19 16:43:27] [INF] [app.go:286] using config: /data/es/loadgen.yml
[08-19 16:43:27] [INF] [module.go:155] started plugin: statsd
[08-19 16:43:27] [INF] [module.go:161] all modules are started
[08-19 16:43:27] [INF] [instance.go:78] workspace: /data/es/data/loadgen/nodes/cr1gabqr90cng685o2s0
[08-19 16:43:27] [INF] [app.go:511] loadgen is up and running now.
[08-19 16:43:27] [INF] [main.go:403] loading config: /data/es/loadgen.dsl.shawnyan

21108 requests finished in 9.79061677s, 1.08MB sent, 3.22MB received

[Loadgen Client Metrics]
Requests/sec:           2110.63
Request Traffic/sec:    110.22KB
Total Transfer/sec:     440.00KB
Fastest Request:        680.198µs
Slowest Request:        12.409574ms
Status 200:             21108

[Latency Metrics]
10000 samples of 21108 events
Cumulative:     8.732205871s
HMean:          851.869µs
Avg.:           873.22µs
p50:            839.498µs
p75:            914.298µs
p95:            1.059197ms
p99:            1.327098ms
p999:           4.83579ms
Long 5%:        1.394411ms
Short 5%:       724.226µs
Max:            11.618475ms
Min:            680.198µs
Range:          10.938277ms
StdDev:         289.216µs
Rate/sec.:      2110.63

[Latency Distribution]
       680µs - 1.774ms ------------------------------
     1.774ms - 2.867ms -
     2.867ms - 3.961ms -
     3.961ms - 5.055ms -
     5.055ms - 6.149ms -
     6.149ms - 7.243ms -
     7.243ms - 8.336ms -
      8.336ms - 9.43ms -
     9.43ms - 10.524ms -
   10.524ms - 11.618ms -

[Estimated Server Metrics]
Requests/sec:           2155.94
Avg Req Time:           927.668µs
Transfer/sec:           449.45KB

更多内容请参阅文档:

https://infinilabs.cn/docs/latest/gateway/getting-started/benchmark/

Rally

如果对 Elasticsearch 熟悉的同学,也可尝试使用 Rally 对 Easysearch 进行测试。

Rally 是 Elasticsearch 的基准测试框架。它可以帮助您完成以下任务:

  • 安装 Elasticsearch 集群以进行基准测试
  • 跨 Elasticsearch 版本管理基准数据和规范
  • 运行基准测试并记录结果
  • 通过连接遥测设备来查找性能问题
  • 比较性能结果

安装 Rally。

[root@easysearch /]# pip3 install esrally
Requirement already satisfied: esrally in /usr/local/lib/python3.9/site-packages (2.11.0)
Requirement already satisfied: py-cpuinfo==7.0.0 in /usr/local/lib/python3.9/site-packages (from esrally) (7.0.0)
Requirement already satisfied: elastic-transport==8.4.1 in /usr/local/lib/python3.9/site-packages (from esrally) (8.4.1)
Requirement already satisfied: google-resumable-media[requests]==1.1.0 in /usr/local/lib/python3.9/site-packages (from esrally) (1.1.0)
Requirement already satisfied: urllib3==1.26.18 in /usr/local/lib/python3.9/site-packages (from esrally) (1.26.18)
Requirement already satisfied: google-auth==1.22.1 in /usr/local/lib/python3.9/site-packages (from esrally) (1.22.1)
Requirement already satisfied: thespian==3.10.1 in /usr/local/lib/python3.9/site-packages (from esrally) (3.10.1)
Requirement already satisfied: jsonschema==3.1.1 in /usr/local/lib/python3.9/site-packages (from esrally) (3.1.1)
Requirement already satisfied: markupsafe==2.0.1 in /usr/local/lib64/python3.9/site-packages (from esrally) (2.0.1)
Requirement already satisfied: yappi==1.5.1 in /usr/local/lib64/python3.9/site-packages (from esrally) (1.5.1)
Requirement already satisfied: psutil==5.9.4 in /usr/local/lib64/python3.9/site-packages (from esrally) (5.9.4)
Requirement already satisfied: certifi in /usr/local/lib/python3.9/site-packages (from esrally) (2024.7.4)
Requirement already satisfied: elasticsearch[async]==8.6.1 in /usr/local/lib/python3.9/site-packages (from esrally) (8.6.1)
Requirement already satisfied: ijson==2.6.1 in /usr/local/lib/python3.9/site-packages (from esrally) (2.6.1)
Requirement already satisfied: jinja2==3.1.4 in /usr/local/lib/python3.9/site-packages (from esrally) (3.1.4)
Requirement already satisfied: requests<2.32.0 in /usr/local/lib/python3.9/site-packages (from esrally) (2.31.0)
Requirement already satisfied: tabulate==0.8.9 in /usr/local/lib/python3.9/site-packages (from esrally) (0.8.9)
Requirement already satisfied: zstandard==0.21.0 in /usr/local/lib64/python3.9/site-packages (from esrally) (0.21.0)
Requirement already satisfied: docker==6.0.0 in /usr/local/lib/python3.9/site-packages (from esrally) (6.0.0)
Requirement already satisfied: websocket-client>=0.32.0 in /usr/local/lib/python3.9/site-packages (from docker==6.0.0->esrally) (1.8.0)
Requirement already satisfied: packaging>=14.0 in /usr/lib/python3.9/site-packages (from docker==6.0.0->esrally) (20.9)
Requirement already satisfied: aiohttp<4,>=3 in /usr/local/lib64/python3.9/site-packages (from elasticsearch[async]==8.6.1->esrally) (3.10.4)
Requirement already satisfied: pyasn1-modules>=0.2.1 in /usr/local/lib/python3.9/site-packages (from google-auth==1.22.1->esrally) (0.4.0)
Requirement already satisfied: six>=1.9.0 in /usr/lib/python3.9/site-packages (from google-auth==1.22.1->esrally) (1.15.0)
Requirement already satisfied: rsa<5,>=3.1.4 in /usr/local/lib/python3.9/site-packages (from google-auth==1.22.1->esrally) (4.9)
Requirement already satisfied: setuptools>=40.3.0 in /usr/lib/python3.9/site-packages (from google-auth==1.22.1->esrally) (53.0.0)
Requirement already satisfied: cachetools<5.0,>=2.0.0 in /usr/local/lib/python3.9/site-packages (from google-auth==1.22.1->esrally) (4.2.4)
Requirement already satisfied: google-crc32c<2.0dev,>=1.0 in /usr/local/lib64/python3.9/site-packages (from google-resumable-media[requests]==1.1.0->esrally) (1.5.0)
Requirement already satisfied: attrs>=17.4.0 in /usr/local/lib/python3.9/site-packages (from jsonschema==3.1.1->esrally) (24.2.0)
Requirement already satisfied: importlib-metadata in /usr/local/lib/python3.9/site-packages (from jsonschema==3.1.1->esrally) (8.2.0)
Requirement already satisfied: pyrsistent>=0.14.0 in /usr/local/lib64/python3.9/site-packages (from jsonschema==3.1.1->esrally) (0.20.0)
Requirement already satisfied: yarl<2.0,>=1.0 in /usr/local/lib64/python3.9/site-packages (from aiohttp<4,>=3->elasticsearch[async]==8.6.1->esrally) (1.9.4)
Requirement already satisfied: frozenlist>=1.1.1 in /usr/local/lib64/python3.9/site-packages (from aiohttp<4,>=3->elasticsearch[async]==8.6.1->esrally) (1.4.1)
Requirement already satisfied: aiosignal>=1.1.2 in /usr/local/lib/python3.9/site-packages (from aiohttp<4,>=3->elasticsearch[async]==8.6.1->esrally) (1.3.1)
Requirement already satisfied: async-timeout<5.0,>=4.0 in /usr/local/lib/python3.9/site-packages (from aiohttp<4,>=3->elasticsearch[async]==8.6.1->esrally) (4.0.3)
Requirement already satisfied: aiohappyeyeballs>=2.3.0 in /usr/local/lib/python3.9/site-packages (from aiohttp<4,>=3->elasticsearch[async]==8.6.1->esrally) (2.3.7)
Requirement already satisfied: multidict<7.0,>=4.5 in /usr/local/lib64/python3.9/site-packages (from aiohttp<4,>=3->elasticsearch[async]==8.6.1->esrally) (6.0.5)
Requirement already satisfied: pyparsing>=2.0.2 in /usr/lib/python3.9/site-packages (from packaging>=14.0->docker==6.0.0->esrally) (2.4.7)
Requirement already satisfied: pyasn1<0.7.0,>=0.4.6 in /usr/local/lib/python3.9/site-packages (from pyasn1-modules>=0.2.1->google-auth==1.22.1->esrally) (0.6.0)
Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.9/site-packages (from requests<2.32.0->esrally) (3.7)
Requirement already satisfied: charset-normalizer<4,>=2 in /usr/local/lib64/python3.9/site-packages (from requests<2.32.0->esrally) (3.3.2)
Requirement already satisfied: zipp>=0.5 in /usr/local/lib/python3.9/site-packages (from importlib-metadata->jsonschema==3.1.1->esrally) (3.20.0)
WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv
[root@easysearch /]# esrally --version
esrally 2.11.0
[root@easysearch /]#

关于 Rally 的更多内容,请参阅官方文档:

https://esrally.readthedocs.io/en/stable/

作者:少安事务所
原文:https://mp.weixin.qq.com/s/9eEH38kgsw4i150CJqyxvQ

Easysearch x 《黑神话悟空》有奖征文获奖结果公示

EasysearchINFINI Labs 小助手 发表了文章 • 0 个评论 • 2486 次浏览 • 2024-08-20 13:34 • 来自相关话题

随着《黑神话:悟空》游戏的正式发售,我们 INFINI Labs 组织的 Easysearch 有奖征文大赛也圆满落幕。本次征文活动自启动以来,收到了众多创作者的热情投稿。在此,我们衷心感谢每一位参与活动的作者,是你们的才华和热情让这次征文活动异彩纷呈。

经过专业评审团的认真评选,最终确定了以下获奖作品及作者,现予以公布:

奖项 作者 作品 奖品
一等奖 AWS 加油站 玩转 Easysearch 语法 《黑神话:悟空》数字豪华版一套
二等奖 杨帆 使用 Easysearch 打造企业内部知识问答系统 《黑神话:悟空》数字标准版一套
二等奖 李家兴 从 Elasticsearch 到 Easysearch:国产搜索型数据库的崛起与未来展望 《黑神话:悟空》数字标准版一套
三等奖 严少安 Easysearch,地表最强,没有之一! INFINI Labs 咖啡杯 / 指甲剪套装
三等奖 张磊 Easysearch 新特性:写入限流功能介绍 INFINI Labs 咖啡杯 / 指甲剪套装
三等奖 keep 如何在 MacOS 环境下快速安装部署 Easysearch INFINI Labs 咖啡杯 / 指甲剪套装

恭喜以上获奖作者,你们的作品不仅展现了 Easysearch 的强大功能,也为社区成员提供了宝贵的学习资源。我们将会通过小助手微信联系各位获奖者,安排奖品的发放。

同时,我们也要感谢所有参与本次征文活动的作者,你们的每一篇 Easysearch 投稿都是对社区的一份贡献。我们期待在未来的活动中再次与大家相遇。

请继续关注 INFINI Labs,我们将持续为大家带来更多优质的产品和精彩的活动。再次感谢大家的参与和支持!

如有疑问或想加入 Easysearch 用户交流群请联系我们小助手!

小助手微信

附征文活动原文:

天命人, 你在吗?快拿走你的《黑神话:悟空》游戏,去开启神话冒险!

关于极限科技(INFINI Labs)

INFINI Labs

极限科技,全称极限数据(北京)科技有限公司,是一家专注于实时搜索与数据分析的软件公司。旗下品牌极限实验室(INFINI Labs)致力于打造极致易用的数据探索与分析体验。

极限科技是一支年轻的团队,采用天然分布式的方式来进行远程协作,员工分布在全球各地,希望通过努力成为中国乃至全球企业大数据实时搜索分析产品的首选,为中国技术品牌输出添砖加瓦。

官网:https://infinilabs.cn

如何在 MacOS 环境下快速安装部署 Easysearch

EasysearchINFINI Labs 小助手 发表了文章 • 0 个评论 • 2689 次浏览 • 2024-08-17 14:56 • 来自相关话题

1、什么是 Easysearch

Easysearch 是极限科技研发的一个分布式的近实时搜索与分析引擎,核心引擎基于开源的 Apache Lucene。 同时也是一款具备自主可控的分布式近实时搜索型数据库产品,具备高性能、高可用、弹性伸缩、高安全性等特性,具备支持丰富的个性化搜索及聚合分析能力,可部署在物理机、虚拟机、容器、私有云和公有云,能承载 PB 级别的海量业务数据,为金融核心系统、运营商、制造业和政企业务系统提供安全、稳定、可靠的快速检索和实时数据探索分析能力,可满足不同业务场景的各项复杂需求。

2、前期准备

在安装 Easysearch 之前,确保您的 MacOS 系统符合以下要求:

  • MacOS 操作系统版本应为最新或推荐稳定版本。
  • 确保系统上已安装 Java 运行环境,因为 Easysearch 是基于 Java 开发的。

3、下载 Easysearch

打开浏览器,访问 Easysearch 官方下载页面

图片10.png

找到 MacOS 版本安装包,然后根据自己电脑 CPU 架构选择对应的 Easysearch 安装包。我自己的电脑是 Intel X86 架构,直接选择默认的 amd64,点击下载即可。如果你的电脑是 Apple 的自己的 M 系列芯片,请选择 arm64 版本安装包。

4、安装 Easysearch

打开终端(Terminal)并导航到下载目录,找到 Easysearch 的压缩包,然后双击解压到您选择的目录。或者使用以下命令解压文件:

unzip ./easysearch-1.8.3-265-mac-amd64.zip

5、启动 Easysearch

  1. 执行初始化脚本

由于 Easysearch 默认自带了安全模块,所以在启动之前需要先执行初始化脚本,脚本里会自动帮我们处理好 Easysearch 安全证书、下载基本的 plugins 插件以及初始用户名和密码等,方便省心。

cd ./easysearch-1.8.3-265-mac-amd64 && bin/initialize.sh

图片11.png

执行过程中遇到 [y/N] 询问,输入 y 即可。最后执行完初始化脚本之后,我们可以在输出的 log 日志中看到 easysearch 的访问用户名和密码,需要注意的是,这个用户名和密码需要自己保存好。 如下图所示:

图片12.png

  1. 启动 Easysearch: 使用以下命令启动 Easysearch:
./bin/easysearch

启动后,Easysearch 将在终端中输出运行日志,您可以在此查看启动过程中的详细信息。

6、验证安装

  1. 检查运行状态

打开浏览器,访问 https://localhost:9200,输入上面提到的用户名密码,如果您看到类似以下的 JSON 响应,说明 Easysearch 已成功启动:

图片13.png

  1. 检查集群健康状况

在浏览器中输入 https:/localhost:9200/_cluster/health?pretty 或者在终端中执行以下命令来检查集群的健康状况:

curl -ku admin:4395c2f67208ca5ad7de https://localhost:9200/_cluster/health?pretty"

这将返回集群的详细健康信息,status 为 green 表示集群状态正常。如下图所示:

图片14.png

7、总结

通过上述步骤,可以轻松地在 MacOS 环境下安装和部署 Easysearch,享受它带来的强大功能和便捷体验。Easysearch 作为 Elasticsearch 的替代产品,不仅在功能上保持了高效和稳定,还进一步优化了搜索业务场景,使其更适合企业级应用。现在,您可以进一步配置集群,开始索引数据,并探索 Easysearch 提供的强大搜索和分析功能。建议参考 官网文档,深入了解并实践更多高级功能。

关于 Easysearch 有奖征文活动

黑神话悟空

无论你是 Easysearch 的老用户,还是第一次听说这个名字,只要你对 INFINI Labs 旗下的 Easysearch 产品感兴趣,或者是希望了解 Easysearch,都可以参加这次活动。

详情查看:Easysearch 征文活动

作者:Keep simple
原文:https://blog.csdn.net/weixin_48688147/article/details/141238374

Easysearch、Elasticsearch、Amazon OpenSearch 快照兼容对比

EasysearchINFINI Labs 小助手 发表了文章 • 2 个评论 • 2596 次浏览 • 2024-07-29 11:54 • 来自相关话题

在当今的数据驱动时代,搜索引擎的快照功能在数据保护和灾难恢复中至关重要。本文将对 Easysearch、Elasticsearch 和 Amazon OpenSearch 的快照兼容性进行比较,分析它们在快照创建、恢复、存储格式和跨平台兼容性等方面的特点,帮助大家更好地理解这些搜索引擎的差异,从而选择最适合自己需求的解决方案。

启动集群

Easysearch

服务器一般情况下默认参数都是很低的,而 Easysearch/Elasticsearch 是内存大户,所以就需要进行系统调优。

sysctl -w vm.max_map_count=262144

vm.max_map_count 是一个 Linux 内核参数,用于控制单个进程可以拥有的最大内存映射区域(VMA,Virtual Memory Areas)的数量。内存映射区域是指通过内存映射文件或匿名内存映射创建的虚拟内存区域。

这个参数在一些应用程序中非常重要,尤其是那些需要大量内存映射的应用程序,比如 Elasticsearch。Elasticsearch 使用内存映射文件来索引和搜索数据,这可能需要大量的内存映射区域。如果 vm.max_map_count 设置得太低,Elasticsearch 可能无法正常工作,并会出现错误信息。

调整 vm.max_map_count 参数的一些常见原因:

  1. 支持大型数据集: 应用程序(如 Elasticsearch)在处理大型数据集时可能需要大量内存映射区域。增加 vm.max_map_count 可以确保这些应用程序有足够的内存映射区域来处理数据。

  2. 防止内存错误: 如果 vm.max_map_count 设置得太低,当应用程序尝试创建超过限制的内存映射时,会出现错误,导致应用程序崩溃或无法正常工作。

  3. 优化性能: 适当地设置 vm.max_map_count 可以优化应用程序的性能,确保内存映射操作顺利进行。

检查当前的 vm.max_map_count 值:

sysctl vm.max_map_count

或者查看 /proc/sys/vm/max_map_count 文件:

cat /proc/sys/vm/max_map_count

Elasticsearch 官方建议将 vm.max_map_count 设置为至少 262144。对于其他应用程序。

Easysearch 具体安装步骤见 INFINI Easysearch 尝鲜 Hands on

Amazon OpenSearch

使用 Amazon Web Services 控制台进行创建。

Elasticsearch

使用如下 docker compose 部署一个三节点的 ES 集群:

version: "2.2"
services:
  es01:
    image: docker.elastic.co/elasticsearch/elasticsearch:7.10.2
    container_name: es01
    environment:
      - node.name=es01
      - cluster.name=es-docker-cluster
      - discovery.seed_hosts=es02,es03
      - cluster.initial_master_nodes=es01,es02,es03
      - bootstrap.memory_lock=true
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
    ulimits:
      memlock:
        soft: -1
        hard: -1
    volumes:
      - data01:/usr/share/elasticsearch/data
    ports:
      - 9200:9200
    networks:
      - elastic
  es02:
    image: docker.elastic.co/elasticsearch/elasticsearch:7.10.2
    container_name: es02
    environment:
      - node.name=es02
      - cluster.name=es-docker-cluster
      - discovery.seed_hosts=es01,es03
      - cluster.initial_master_nodes=es01,es02,es03
      - bootstrap.memory_lock=true
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
    ulimits:
      memlock:
        soft: -1
        hard: -1
    volumes:
      - data02:/usr/share/elasticsearch/data
    networks:
      - elastic
  es03:
    image: docker.elastic.co/elasticsearch/elasticsearch:7.10.2
    container_name: es03
    environment:
      - node.name=es03
      - cluster.name=es-docker-cluster
      - discovery.seed_hosts=es01,es02
      - cluster.initial_master_nodes=es01,es02,es03
      - bootstrap.memory_lock=true
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
    ulimits:
      memlock:
        soft: -1
        hard: -1
    volumes:
      - data03:/usr/share/elasticsearch/data
    networks:
      - elastic

volumes:
  data01:
    driver: local
  data02:
    driver: local
  data03:
    driver: local

networks:
  elastic:
    driver: bridge

由于这个 docker compose 没有关于 kibana 的配置,所以我们还是用 Console 添加原生的 Elasticsearch 集群!

集群信息

快照还原的步骤

快照前的准备

插件安装

本次测试选择把索引快照备份到 Amazon S3,所以需要使用 S3 repository plugin,这个插件添加了对使用 Amazon S3 作为快照/恢复存储库的支持。

Easysearch 和 OpenSearch 集群自带了这个插件,所以无需额外安装。

对于自己部署的三节点 Elasticsearch 则需要进入每一个节点运行安装命令然后再重启集群,建议使用自动化运维工具来做这步,安装命令如下:

sudo bin/elasticsearch-plugin install repository-s3

如果不再需要这个插件,可以这样删除。

sudo bin/elasticsearch-plugin remove repository-s3

由于需要和 Amazon Web Services 打交道,所以我们需要设置 IAM 凭证,这个插件可以从 EC2 IAM instance profile,ECS task role 以及 EKS 的 Service account 读取相应的凭证。

对于托管的 Amazon OpenSearch 来说,我们无法在托管的 EC2 上绑定我们的凭证,所以需要新建一个 OpenSearchSnapshotRole,然后通过当前的用户把这个角色传递给服务,也就是我们说的 IAM:PassRole。

创建 OpenSearchSnapshotRole,策略如下:

{
  "Version": "2012-10-17",
  "Statement": [{
      "Action": [
        "s3:ListBucket"
      ],
      "Effect": "Allow",
      "Resource": [
        "arn:aws:s3:::bucket-name"
      ]
    },
    {
      "Action": [
        "s3:GetObject",
        "s3:PutObject",
        "s3:DeleteObject"
      ],
      "Effect": "Allow",
      "Resource": [
        "arn:aws:s3:::bucket-name/*"
      ]
    }
  ]
}

信任关系如下:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "es.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

然后在我们的 IAM user 上加上 PassRole 的权限,这样我们就可以把 OpenSearchSnapshotRole 传递给 OpenSearch 集群。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "iam:PassRole",
      "Resource": "arn:aws:iam::123456789012:role/OpenSearchSnapshotRole"
    }
  ]
}

注册存储库

在源集群执行注册

PUT /_snapshot/snapshot-repo-name
{
  "type": "s3",
  "settings": {
    "bucket": "<bucket-name>",
    "base_path": "<bucket-prefix>",

在目标集群同样执行这个语句,为了防止覆盖源集群存储库的数据,将 "readonly": true 添加到"settings" PUT 请求中,这样就只有一个集群具有对存储库的写入权限。

PUT /_snapshot/snapshot-repo-name
{
  "type": "s3",
  "settings": {
    "bucket": "<bucket-name>",
    "base_path": "<bucket-prefix>",
    "readonly": true,

对于 OpenSearch 来说,还需要执行 passrole,所以还需要添加role_arn这个字段,由于 IAM:PassRole 需要对 HTTP 请求做 signV4 日签名,所以这部常常使用 Postman 来完成。把角色传递过去之后,接下来的快照还原操作就可以在 OpenSearch Dashboard 中进行操作了。

需要注意的是,需要在 auth 这里输入 AccessKey,SecretKey,AWS Region,Service Name(es)来做 SignV4 的签名。

请求体如下:

{
  "type": "s3",
  "settings": {
    "bucket": "<bucket-name>",
    "base_path": "<bucket-prefix>",
    "readonly": true,
    "role_arn": "arn:aws:iam::123456789012:role/OpenSearchSnapshotRole"
  }
}
  • 查看所有注册的存储库
    • GET _snapshot:这个命令返回所有已注册的快照存储库列表及其基本信息。
GET _snapshot
{
  "es_repository": {
    "type": "s3",
    "settings": {
      "bucket": "your-s3-bucket-name",
      "region": "your-s3-bucket-region"
    }
  }
}
  • 查看特定存储库的详细信息GET _snapshot/es_repository:这个命令返回名为es_repository的存储库的详细配置信息,包括存储桶名称、区域和其他设置。
GET _snapshot/es_repository
{
  "es_repository": {
    "type": "s3",
    "settings": {
      "bucket": "your-s3-bucket-name",
      "region": "your-s3-bucket-region",
      "access_key": "your-access-key",
      "secret_key": "your-secret-key"
    }
  }
}
  • 查看特定存储库中的快照GET _cat/snapshots/es_repository?v:这个命令返回es_repository存储库中的所有快照及其详细信息,包括快照 ID、状态、开始时间、结束时间、持续时间、包含的索引数量、成功和失败的分片数量等。
GET _cat/snapshots/es_repository?v
id                     status start_epoch start_time end_epoch end_time duration indices successful_shards failed_shards total_shards
snapshot_1             SUCCESS 1628884800 08:00:00   1628888400 09:00:00 1h       3       10                0             10
snapshot_2             SUCCESS 1628971200 08:00:00   1628974800 09:00:00 1h       3       10                0             10

创建索引快照

# PUT _snapshot/my_repository/<my_snapshot_{now/d}>
PUT _snapshot/my_repository/my_snapshot
{
  "indices": "my-index,logs-my_app-default",
}

根据快照的大小不同,完成快照可能需要一些时间。默认情况下,create snapshot API 只会异步启动快照过程,该过程在后台运行。要更改为同步调用,可以将 wait_for_completion 查询参数设置为 true

PUT _snapshot/my_repository/my_snapshot?wait_for_completion=true

另外还可以使用 clone snapshot API 克隆现有的快照。要监控当前正在运行的快照,可以使用带有 _current 请求路径参数的 get snapshot API。

GET _snapshot/my_repository/_current

如果要获取参与当前运行快照的每个分片的完整详细信息,可以使用 get snapshot status API。

GET _snapshot/_status

成功创建快照之后,就可以在 S3 上看到备份的数据块文件,这个是正确的快照层级结构:

需要注意的是, "base_path": ""这里最好不要加/,虽然不影响同集群迁移,这个会为我们在不同厂商的搜索引擎中迁移遇到问题,可能是这样的,所以需要注意。

所以在 Open Search 中还原 Elasticsearch 就遇到了这个问题:

{
  "error": {
    "root_cause": [
      {
        "type": "snapshot_missing_exception",
        "reason": "[easy_repository:2/-jOQ0oucQDGF3hJMNz-vKQ] is missing"
      }
    ],
    "type": "snapshot_missing_exception",
    "reason": "[easy_repository:2/-jOQ0oucQDGF3hJMNz-vKQ] is missing",
    "caused_by": {
      "type": "no_such_file_exception",
      "reason": "Blob object [11111/indices/7fv2zAi4Rt203JfsczUrBg/meta-YGnzxZABRBxW-2vqcmci.dat] not found: The specified key does not exist. (Service: S3, Status Code: 404, Request ID: R71DDHX4XXM0434T, Extended Request ID: d9M/HWvPvMFdPhB6KX+wYCW3ZFqeFo9EoscWPkulOXWa+TnovAE5PlemtuVzKXjlC+rrgskXAus=)"
    }
  },
  "status": 404
}

恢复索引快照

POST _snapshot/my_repository/my_snapshot_2099.05.06/_restore
{
  "indices": "my-index,logs-my_app-default",
}

各个集群的还原

  1. Elasticsearch 7.10.2 的快照可以还原到 Easysearch 和 Amazon OpenSearch

  2. 从 Easysearch 1.8.2 还原到 Elasticsearch 7.10.2 报错如下:
{
  "error": {
    "root_cause": [
      {
        "type": "snapshot_restore_exception",
        "reason": "[s3_repository:1/a2qV4NYIReqvgW6BX_nxxw] cannot restore index [my_indexs] because it cannot be upgraded"
      }
    ],
    "type": "snapshot_restore_exception",
    "reason": "[s3_repository:1/a2qV4NYIReqvgW6BX_nxxw] cannot restore index [my_indexs] because it cannot be upgraded",
    "caused_by": {
      "type": "illegal_state_exception",
      "reason": "The index [[my_indexs/ALlTCIr0RJqtP06ouQmf0g]] was created with version [1.8.2] but the minimum compatible version is [6.0.0-beta1]. It should be re-indexed in Elasticsearch 6.x before upgrading to 7.10.2."
    }
  },
  "status": 500
}
  1. 从 Amazon OpenSearch 2.1.3 还原到 Elasticsearch 7.10.2 报错如下(无论是否开启兼容模式):
{
  "error": {
    "root_cause": [
      {
        "type": "snapshot_restore_exception",
        "reason": "[aos:2/D-oyYSscSdCbZFcmPZa_yg] the snapshot was created with Elasticsearch version [36.34.78-beta2] which is higher than the version of this node [7.10.2]"
      }
    ],
    "type": "snapshot_restore_exception",
    "reason": "[aos:2/D-oyYSscSdCbZFcmPZa_yg] the snapshot was created with Elasticsearch version [36.34.78-beta2] which is higher than the version of this node [7.10.2]"
  },
  "status": 500
}
  1. 从 Easysearch 1.8.2 还原到 Amazon OpenSearch2.13 报错如下(无论是否开启兼容模式):
{
  "error": {
    "root_cause": [
      {
        "type": "snapshot_restore_exception",
        "reason": "[easy_repository:2/LE18AWHlRJu9rpz9BJatUQ] cannot restore index [my_indexs] because it cannot be upgraded"
      }
    ],
    "type": "snapshot_restore_exception",
    "reason": "[easy_repository:2/LE18AWHlRJu9rpz9BJatUQ] cannot restore index [my_indexs] because it cannot be upgraded",
    "caused_by": {
      "type": "illegal_state_exception",
      "reason": "The index [[my_indexs/VHOo7yfDTRa48uhQvquFzQ]] was created with version [1.8.2] but the minimum compatible version is OpenSearch 1.0.0 (or Elasticsearch 7.0.0). It should be re-indexed in OpenSearch 1.x (or Elasticsearch 7.x) before upgrading to 2.13.0."
    }
  },
  "status": 500
}
  1. Amazon OpenSearch 还原到 Easysearch 同样失败
{
  "error": {
    "root_cause": [
      {
        "type": "snapshot_restore_exception",
        "reason": "[aoss:2/D-oyYSscSdCbZFcmPZa_yg] cannot restore index [aos] because it cannot be upgraded"
      }
    ],
    "type": "snapshot_restore_exception",
    "reason": "[aoss:2/D-oyYSscSdCbZFcmPZa_yg] cannot restore index [aos] because it cannot be upgraded",
    "caused_by": {
      "type": "illegal_state_exception",
      "reason": "The index [[aos/864WjTAXQCaxJ829V5ktaw]] was created with version [36.34.78-beta2] but the minimum compatible version is [6.0.0]. It should be re-indexed in Easysearch 6.x before upgrading to 1.8.2."
    }
  },
  "status": 500
}
  1. Elasticsearch 8.14.3 迁移到 Amazon OpenSearch 或者 Elasticsearch 都是有这个报错:
{
  "error": {
    "root_cause": [
      {
        "type": "parsing_exception",
        "reason": "Failed to parse object: unknown field [uuid] found",
        "line": 1,
        "col": 25
      }
    ],
    "type": "repository_exception",
    "reason": "[snap] Unexpected exception when loading repository data",
    "caused_by": {
      "type": "parsing_exception",
      "reason": "Failed to parse object: unknown field [uuid] found",
      "line": 1,
      "col": 25
    }
  },
  "status": 500
}

这是由于 Elasticsearch 8 在创建快照的时候会默认加上一个 UUID 的字段,所以我们低版本的 Easysearch、Amazon OpenSearch 中会找不到这个字段,在执行GET _cat/snapshots/snap?v的时候就报错,及时在注册存储库的时候显示加上 UUID 的字段也无事无补。

{
  "snapshot-repo-name": {
    "type": "s3",
    "uuid": "qlJ0uqErRmW6aww2Fyt4Fg",
    "settings": {
    "bucket": "<bucket-name>",
    "base_path": "<bucket-prefix>",
    }
  },

以下是兼容性对比,每行第一列代表源集群,第一行代表目标集群:

快照兼容对比 Easysearch 1.8.2 Elasticsearch 7.10.2 OpenSearch 2.13
Easysearch 1.8.2 兼容 不兼容 不兼容
Elasticsearch 7.10.2 兼容 兼容 兼容
OpenSearch 2.13 不兼容 不兼容 兼容

Elasticsearch 的兼容列表官方的列表如下:

参考文献

  1. 开始使用 Elastic Stack 和 Docker Compose:第 1 部分
    https://www.elastic.co/cn/blog/getting-started-with-the-elastic-stack-and-docker-compose

  2. Docker Compose 部署多节点 Elasticsearch
    https://www.elastic.co/guide/en/elasticsearch/reference/7.10/docker.html#docker-compose-file

  3. repository-s3 教程
    https://www.elastic.co/guide/en/elasticsearch/reference/8.14/repository-s3.html
    https://www.elastic.co/guide/en/elasticsearch/plugins/7.10/repository-s3.html

  4. snapshot-restore
    https://www.elastic.co/guide/en/elasticsearch/reference/7.10/snapshot-restore.html

  5. 在亚马逊 OpenSearch 服务中创建索引快照
    https://docs.amazonaws.cn/zh_cn/opensearch-service/latest/developerguide/managedomains-snapshots.html#managedomains-snapshot-restore

  6. 教程:迁移至 Amazon OpenSearch Service
    https://docs.amazonaws.cn/zh_cn/opensearch-service/latest/developerguide/migration.html

关于 Easysearch 有奖征文活动

黑神话悟空

无论你是 Easysearch 的老用户,还是第一次听说这个名字,只要你对 INFINI Labs 旗下的 Easysearch 产品感兴趣,或者是希望了解 Easysearch,都可以参加这次活动。

详情查看:Easysearch 征文活动

作者:韩旭,亚马逊云技术支持,亚马逊云科技技领云博主,目前专注于云计算开发和大数据领域。

原文:https://infinilabs.cn/blog/2024/comparison-of-snapshot-compatibility-between-easysearch-elasticsearch-and-opensearch/

使用 Easysearch 打造企业内部知识问答系统

EasysearchINFINI Labs 小助手 发表了文章 • 0 个评论 • 2461 次浏览 • 2024-07-29 11:08 • 来自相关话题

大家可能都有这样的经历,刚入职一家企业时,同事往往会给你分享一些文档资料,有可能是产品信息、规章制度等等。这些文档有的过于冗长,很难第一时间找到想要的内容。有的已经有了新版本,但员工使用的还是老版本。

基于这种背景,我们可以利用 Easysearch 加 LLM 实现一个内部知识的 QA 问答系统。这个系统将利用 LangChain 框架调用本地部署的大模型和 Easysearch,实现理解员工的提问,并基于最新的文档,给出精准答案。

开发框架

整个框架分为四个部分:

  • 数据源:数据可以有很多种,可以是非结构化的,比如 PDF、docx、txt 等。也可以是结构化的数据,甚至代码也行。在本次示例中,我们使用 PDF 的非结构化数据。
  • 大模型应用:应用与大模型交互,生成我们需要的答案。
  • 大模型:系统执行相关任务需要用到的大模型,可以有多个。
  • Q&A 场景:基于大模型为引擎的 QA 场景,使用 web 框架,构建一个交互界面。

数据准备

本次我们使用的资料是 "INFINI 产品安装手册.pdf" ,文档部分内容展示如下:

首先我们使用 LangChain 的 document_loaders 来加载文件。document_loaders 集成了数百种数据源格式,可以很方便的加载数据。我们的数据的 pdf 格式的,导入 PyPDFLoader 类来进行处理。代码如下:

import os

# 导入 Document Loaders
from langchain_community.document_loaders import PyPDFLoader

# Load Pdf
base_dir = '.\\easysearch' # 文档的存放目录
docs = []
for file in os.listdir(base_dir):
    file_path = os.path.join(base_dir, file)
    if file.endswith('.pdf'):
        loader = PyPDFLoader(file_path)
        documents.extend(loader.load())

上面的代码将 pdf 文件的内容存储在 docs 这个列表中,以便后续进行处理。

文本分割

一个文件的文本内容可能很大,无法适应许多模型的上下文窗口,也不利于检索和存储。因此,通常我们会将文本内容分割成更小的块,这将帮助我们在运行时只检索文档中最相关的部分。LangChain 提供了工具来进行处理文本分割,非常方便。 我们将把文档分割成 1000 个字符的块,每个块之间有 200 个重叠字符。这种重叠有助于减少将语句与相关的重要上下文分离的可能性。

# 2.将Documents切分成块
from langchain.text_splitter import RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=20)
chunked_documents = text_splitter.split_documents(docs)

上面的代码将 docs 的内容按 1000 字符大小进行切分,存储在 chunked_documents 中,以便后续进行处理。
注意,实际运行中,切分及重叠的大小,都会影响应用效果,需自行调试。

向量库 Easysearch

接下来,我们将这些文本块转换成向量的形式,并存储在一个向量数据库中。在本示例中,我们使用 mxbai-embed-large 模型来生成向量,然后将向量和原始内容存入 easysearch 。

本地部署模型,我使用的是 ollama ,大家可以使用自己喜欢的工具。

# 3. 定义embedding模型
from langchain_community.embeddings import OllamaEmbeddings
ollama_emb = OllamaEmbeddings(
    model="mxbai-embed-large",
)

# 4. 定义 easysearch 集群的信息,以及存放向量的索引名称 infini
from langchain_community.vectorstores import EcloudESVectorStore
ES_URL = "https://192.168.56.3:9200"
USER = "admin"
PASSWORD = "e5ac1b537785ae27c187"
indexname = "infini"

docsearch = EcloudESVectorStore.from_documents(
    chunked_documents,
    ollama_emb,
    es_url=ES_URL,
    user=USER,
    password=PASSWORD,
    index_name=indexname,
    verify_certs=False,
)

通过上面的步骤,我们成功将文本块转换成了向量,并存入到了 easysearch 集群的 infini 索引中。 我们看看 infini 索引内容是怎样的 text 字段存放了文本块的原始内容,vector 字段存放着对应的向量表示。

检索及生成答案

在这一步,我们会定义一个生成式大模型。然后创建一个 RetrievalQA 链,它是一个检索式问答模型,用于生成问题的答案。
在 RetrievalQA 链中有下面两大重要组成部分。

  • LLM 是大模型,负责回答问题。
  • retriever(vectorstore.as_retriever())负责根据用户的问题检索相关的信息。先是找最近似的“向量块”,再把”向量块“对应的“文档块”作为知识信息,和问题一起传递进入大模型。之所以要先检索,是因为从互联网信息训练而来的大模型不可能拥有一个私营企业的内部知识。
# 5. Retrieval 准备模型和Retrieval链
import logging
# MultiQueryRetriever工具
from langchain.retrievers.multi_query import MultiQueryRetriever
# RetrievalQA链
from langchain.chains import RetrievalQA

# # 设置Logging
logging.basicConfig()
logging.getLogger('langchain.retrievers.multi_query').setLevel(logging.INFO)

# # 实例化一个大模型工具
from langchain_community.chat_models import ChatOllama
llm = ChatOllama(model="qwen2:latest")

from langchain.prompts import PromptTemplate
my_template = PromptTemplate(
    input_variables=["question"],
    template="""You are an AI language model assistant. Your task is
    to generate 3 different versions of the given user
    question in Chinese to retrieve relevant documents from a vector  database.
    By generating multiple perspectives on the user question,
    your goal is to help the user overcome some of the limitations
    of distance-based similarity search. Provide these alternative
    questions separated by newlines. Original question: {question}""",
)

# # 实例化一个MultiQueryRetriever
retriever_from_llm = MultiQueryRetriever.from_llm(retriever=docsearch.as_retriever(), llm=llm,prompt=my_template,include_original=True)

# # 实例化一个RetrievalQA链
qa_chain = RetrievalQA.from_chain_type(llm,retriever=retriever_from_llm)

这里我们使用 ollama 在本地部署一个 qwen2 大模型,负责问题改写和生成答案。

启动 qwen2 大模型:ollama run qwen2

我们获取到用户问题后,先通过 MultiQueryRetriever 类调用大模型 qwen2 进行改写,生成 3 个同样语义的问题,然后再调用 easyearch 进行向量检索,搜索相关内容。

最后把所有相关内容,合并、去重后,与原始问题一起提交给大模型 qwen2,进行答案生成。

虽然这里使用的是向量检索,但实际上我们可以同时使用全文检索和向量检索。这也是使用 easysearch 作为检索库的优势之一。

前端展示

这一步我们创建一个 Flask 应用(需要安装 Flask 包)来接收用户的问题,并生成相应的答案,最后通过 index.html 对答案进行渲染和呈现。

在这个步骤中,我们使用了之前创建的 RetrievalQA 链来获取相关的文档和生成答案。然后,将这些信息返回给用户,显示在网页上。

# 6. Q&A系统的UI实现
from flask import Flask, request, render_template
app = Flask(__name__) # Flask APP

@app.route('/', methods=['GET', 'POST'])
def home():
    if request.method == 'POST':

        # 接收用户输入作为问题
        question = request.form.get('question')

        # RetrievalQA链 - 读入问题,生成答案
        result = qa_chain({"query": question})

        # 把大模型的回答结果返回网页进行渲染
        return render_template('index.html', result=result)

    return render_template('index.html')

if __name__ == "__main__":
    app.run(host='0.0.0.0',debug=True,port=5000)

效果演示

我们模仿用户进行提问。 Q&A 系统进行回答,回答速度取决于本地的计算资源。 内容校验,在原始文档内用 ctrl+F 搜索关键字 LOGGING_ES_ENDPOINT 得到如下内容。 嗯,回答的还不错,达到预期目的。如果还有其他要求,可修改 my_template 中的提示词或者替换成别的大模型也是可以的。

小结

通过这次示例,我们演示了如何基于 LangChain 和 easysearch 以及大模型,快速开发出一个内部知识问答系统。怎么样,是不是觉得整个流程特别简单易懂?

如有任何问题,请随时联系我,期待与您交流!

关于 Easysearch 有奖征文活动

黑神话悟空

无论你是 Easysearch 的老用户,还是第一次听说这个名字,只要你对 INFINI Labs 旗下的 Easysearch 产品感兴趣,或者是希望了解 Easysearch,都可以参加这次活动。

详情查看:Easysearch 征文活动

【第1期】2024 搜索客 Meetup | Easysearch 结合大模型实现 RAG

活动searchkit 发表了文章 • 0 个评论 • 2944 次浏览 • 2024-07-25 16:57 • 来自相关话题

2024 搜索客社区 Meetup 首期线上活动正式启动,本次活动由 搜索客社区、极限科技(INFINI Labs)联合举办,诚邀广大搜索技术开发者和爱好者参加交流学习。

活动时间:2024 年 7 月 31 日 19:00-20:00 (周三)
活动形式:微信视频号(极限实验室)直播
报名方式:关注或扫码海报中的二维码进行预约

活动海报

活动简介

在这个人工智能飞速发展的时代,ChatGPT 和 GPT-4 的出现无疑为人类带来了前所未有的震撼。我们不禁思考:通用人工智能的奇点是否真的即将来临?而最前沿的 AI 技术与最实用的落地应用之间的距离,又该如何缩短?

为了深入探讨这些问题,我们特别邀请到了极限科技(INFINI Labs)高级解决方案架构师、《老杨玩搜索》栏目 B 站 UP 主——杨帆先生,为我们带来一场主题为 “Easysearch 结合大模型实现 RAG” 的精彩演讲。

嘉宾介绍

杨帆,拥有十余年金融行业服务工作经验,熟悉 Linux、数据库、网络等领域。目前主要从事 Easysearch、Elasticsearch 等搜索引擎的技术支持工作,服务国内私有化部署的客户。他的丰富经验和深刻见解,将为我们揭开 AI 技术与实际应用之间的神秘面纱。

演讲主题

《Easysearch 结合大模型实现 RAG》

主题摘要

在本次演讲中,杨帆将跟大家分享和探讨以下几个方面:

  1. LangChain 简介:LangChain 的作用是什么?它由哪些组件构成,优势是什么。
  2. RAG 的背景及其局限性:RAG 出现以前的我们是如何获取信息的,RAG 解决了什么问题?它就是最终的答案了吗?
  3. LangChain 下的 RAG 工作流:在 LangChain 的框架下,实现 RAG 的步骤是怎样的。
  4. RAG Demo:使用 ollama 部署本地模型,利用 LangChain 集成 Easysearch 和 LLM , 开发 QA 问答系统

活动亮点

  • 前沿技术分享: 深入了解当前 AI 领域的最新动态和发展趋势。
  • 实战经验交流: 学习如何在实际工作中应用这些先进技术。
  • 互动问答环节: 与演讲嘉宾直接对话,解答你的疑惑。

参与有奖

本次直播活动中设置了随机抽奖环节,奖品为 INFINI Labs 周边纪念品,包括 T 恤、鸭舌帽、咖啡杯、指甲刀套件等等(图片仅供参考,款式、颜色与尺码随机)。

抽奖礼品

活动交流

活动交流群二维码 7 天内(8 月 1 日前)有效,如过期请添加小助手微信拉群。活动最新消息也会在群内及时同步,欢迎大家参与,记得先预约,精彩内容不错过!

活动交流

讲师招募

讲师招募

搜索客社区 Meetup 讲师持续招募中...

这是一个由搜索客社区精心组织策划的线下线上技术交流活动,我们诚挚邀请各位技术大咖、行业精英踊跃提交演讲议题。Meetup 活动将聚焦 AI 与搜索领域的最新动态,以及数据实时搜索分析、向量检索、技术实践与案例分析、日志分析、安全等领域的深度探讨。详情参见:http://cfp.searchkit.cn 。我们热切期待您的精彩分享!

关于 搜索客(SearchKit)社区

搜索客社区由 Elasticsearch 中文社区进行全新的品牌升级,以新的 Slogan:“搜索人自己的社区” 为宣言。汇集搜索领域最新动态、精选干货文章、精华讨论、文档资料、翻译与版本发布等,为广大搜索领域从业者提供更为丰富便捷的学习和交流平台。社区官网:https://searchkit.cn

Easysearch 有奖征文活动推荐

黑神话悟空

无论你是 Easysearch 的老用户,还是第一次听说这个名字,只要你对 INFINI Labs 旗下的 Easysearch 产品感兴趣,或者是希望了解 Easysearch,都可以参加这次活动。

详情查看:Easysearch 征文活动

Easysearch 新特性:写入限流功能介绍

EasysearchINFINI Labs 小助手 发表了文章 • 0 个评论 • 2726 次浏览 • 2024-07-17 14:52 • 来自相关话题

背景

在 Easysearch 的各种使用场景中,高写入吞吐量的场景占了很大一部分,由此也带来了一些使用上的问题,很多用户由于使用经验不足,对集群的写入压测进行的不够充分,不能很好的规划集群的写入量。

导致经常发生以下问题:

  • 写入吞吐量过大对内存影响巨大,引发节点 OOM,节点掉线问题。
  • 对 CPU 和内存的占用严重影响了其他的查询业务的响应。
  • 以及磁盘 IO 负载增加,挤占集群的网络带宽等问题。

之前就有某金融保险类客户遇到了因业务端写入量突然猛增导致数据节点不停的 Full GC,进而掉入了不停的掉线,上线,又掉线的恶性循环中。当时只能建议用户增加一个类似“挡板”的服务,在数据进入到集群之前进行拦截,对客户端写入进行干预限流:

这样做虽然有效,但是也增加了整个系统的部署复杂性,提高了运维成本。

根据客户的实际场景,Easysearch 从 1.8.0 版本开始引入了节点和 Shard 级别的限流功能,不用依赖第三方就可以限制写入压力,并在 1.8.2 版本增加了索引级别的写入限流。 注意:所有写入限流都是针对各数据节点的 Primary Shard 写入进行限流的,算上副本的话吞吐量要乘以 2。

限流示意图:

下面是限流前后相同数据节点的吞吐量和 CPU 对比:

测试环境:

ip       name   http          port version role master
10.0.0.3 node-3 10.0.0.3:9209 9303 1.8.0   dimr -
10.0.0.3 node-4 10.0.0.3:9210 9304 1.8.0   im   -
10.0.0.3 node-2 10.0.0.3:9208 9302 1.8.0   dimr -
10.0.0.3 node-1 10.0.0.3:9207 9301 1.8.0   dimr *

测试索引配置:

PUT test_0
{
  "settings": {
    "number_of_replicas": 1,
    "number_of_shards": 3
  }
}

压测工具:采用极限科技的 INFINI Loadgen 压测,这款压测工具使用简单,可以方便对任何支持 Rest 接口的库进行压测。

压测命令:

 ./loadgen-linux-amd64 -d 180 -c 10 -config loadgen-easy-1.8.yml

压测 180 秒,10 个并发,每个 bulk 请求 5000 条。

节点级别限流

通过 INFINI Console 监控指标可以看到,限流之前的某个数据节点,CPU 占用 10%,每秒写入 40000 条左右:

在 Cluster Settings 里配置,启用节点级别限流,限制每个节点的每秒最大写入 10000 条,并在默认的 1 秒间隔内进行重试,超过默认间隔后直接拒绝。

PUT _cluster/settings
{
  "transient": {
    "cluster.throttle.node.write": true,
    "cluster.throttle.node.write.max_requests": 10000,
    "cluster.throttle.node.write.action": "retry"
  }
}

限流后,CPU 占用降低了约 50%,算上副本一共 20000 条每秒:

Shard 级别限流

设置每个分片最大写入条数为 2000 条每秒

PUT _cluster/settings
{
  "transient": {
    "cluster.throttle.shard.write": true,
    "cluster.throttle.shard.write.max_requests": 2000,
    "cluster.throttle.shard.write.action": "retry"
  }
}

集群级别的监控,同样是只针对主 Shard。

从 Console 的监控指标可以看出,索引 test_0 的 Primary indexing 维持在 6000 左右,正好是 3 个主分片限制的 2000 的写入之和。

再看下数据节点监控,Total Shards 表示主分片和副本分片的写入总和即 4000,单看主分片的话,正好是 2000.

索引级别限流

有时,集群中可能某个索引的写入吞吐过大而影响了其他业务,也可以针对特定的索引配置写入限制。 可以在索引的 Settings 里设置当前索引每秒写入最大条数为 6000:

PUT test_0
{
  "settings": {
    "number_of_replicas": 1,
    "number_of_shards": 3,
    "index.throttle.write.max_requests": 6000,
    "index.throttle.write.action": "retry",
    "index.throttle.write.enable": true
  }
}

下图索引的 Primary indexing 在 6000 左右,表示索引的所有主分片的写入速度限制在了 6000。

总结

通过本次测试对比,可以看出限流的好处:

  1. 有效控制写入压力: 写入限流功能能够有效限制每个节点和每个 Shard 的写入吞吐量,防止因写入量过大而导致系统资源被过度消耗的问题。

  2. 降低系统资源占用: 在限流前,某数据节点的 CPU 占用率约为 10%。限流后,CPU 占用率显著降低至约 5%,减少了约 50%。这表明在高并发写入场景下,写入限流功能显著降低了系统的 CPU 负载。

  3. 提高系统稳定性: 通过控制写入吞吐量,避免了频繁的 Full GC 和节点掉线问题,从而提升了系统的整体稳定性和可靠性。

  4. 保障查询业务性能: 写入限流功能减少了写入操作对 CPU 和内存的占用,确保其他查询业务的响应性能不受影响。

综上所述,写入限流功能在高并发写入场景下表现出色,不仅有效控制了写入压力,还显著降低了系统资源占用,从而提高了系统的稳定性和查询业务的性能。

关于 Easysearch 有奖征文活动

黑神话悟空

无论你是 Easysearch 的老用户,还是第一次听说这个名字,只要你对 INFINI Labs 旗下的 Easysearch 产品感兴趣,或者是希望了解 Easysearch,都可以参加这次活动。

详情查看:Easysearch 征文活动

作者:张磊

原文:https://infinilabs.cn/blog/2024/easysearch-new-feature-write-throttling-introduction/

【搜索客社区日报】第1859期 (2024-07-15)

社区日报searchkit 发表了文章 • 0 个评论 • 2463 次浏览 • 2024-07-17 14:50 • 来自相关话题

1. Easysearch 新特性:写入限流功能介绍 https://infinilabs.cn/blog/202 ... tion/ 2. 中文大模型基准测评2024年上半年报告 https://report.oschina.net/api ... o.pdf 3. ClickHouse 24.6 版本发布说明 https://mp.weixin.qq.com/s/JrAikqoUMjHHuaLEHZptew 4. 斯坦福年度《人工智能指数报告》的十条重要结论 https://cn.weforum.org/agenda/ ... t-cn/ 5. 面壁智能首席科学家刘知远:大模型的“摩尔定律”是模型知识密度持续增强  https://www.tsinghua.edu.cn/info/1182/112713.htm 编辑:Muse 更多资讯:http://news.searchkit.cn

【搜索客社区日报】第1858期 (2024-07-12)

社区日报Fred2000 发表了文章 • 0 个评论 • 3051 次浏览 • 2024-07-12 14:05 • 来自相关话题

1、中文大模型基准测评上半年报告:GPT-4o 排名第一、通义千问 “国服最强” https://www.oschina.net/news/301339 2、高级 RAG 检索策略之流程与模块化 https://mp.weixin.qq.com/s/WeAcAevUPemPKhQLhId3Vg 3、下一代 RAG 技术来了!微软正式开源 GraphRAG:大模型行业将迎来新的升级? https://www.infoq.cn/article/sqaUMyNg6B8OrCcwg4vo 4、电商场景下 ES 搜索引擎的稳定性治理实践 https://mp.weixin.qq.com/s/fAgAgWWYJbbfcGGx1BpLsw 5、玩转 Easysearch 语法 https://infinilabs.cn/blog/202 ... ntax/ 编辑:Fred  更多资讯:http://news.searchkit.cn
1、中文大模型基准测评上半年报告:GPT-4o 排名第一、通义千问 “国服最强” https://www.oschina.net/news/301339 2、高级 RAG 检索策略之流程与模块化 https://mp.weixin.qq.com/s/WeAcAevUPemPKhQLhId3Vg 3、下一代 RAG 技术来了!微软正式开源 GraphRAG:大模型行业将迎来新的升级? https://www.infoq.cn/article/sqaUMyNg6B8OrCcwg4vo 4、电商场景下 ES 搜索引擎的稳定性治理实践 https://mp.weixin.qq.com/s/fAgAgWWYJbbfcGGx1BpLsw 5、玩转 Easysearch 语法 https://infinilabs.cn/blog/202 ... ntax/ 编辑:Fred  更多资讯:http://news.searchkit.cn

玩转 Easysearch 语法

EasysearchINFINI Labs 小助手 发表了文章 • 0 个评论 • 2926 次浏览 • 2024-07-11 12:11 • 来自相关话题

什么是 Easysearch

Elasticsearch 是一个基于 Apache Lucene 的开源分布式搜索和分析引擎,它被广泛应用于全文搜索、结构化搜索和分析等多种场景中。作为 Elasticsearch 的国产化替代方案,Easysearch 不仅保持了与原生 Elasticsearch 的高度兼容性,还在功能、性能、稳定性和扩展性方面进行了全面提升。对于开发团队来说,从 Elasticsearch 切换到 Easysearch 不需要做任何业务代码的调整,确保了无缝衔接和平滑迁移。

Easysearch 是基于 Elasticsearch 7.10.2 开源版本二次开发,所以支持 Elasticsearch 原始的 Query DSL 语法,基本的 SQL 语法,并且兼容现有 Elasticsearch 的 SDK,使得应用无需修改代码即可进行迁移。其平滑的迁移特性,如基于网关的无缝跨版本迁移与升级,提供了随时安全回退的能力。

在之前的文章中,我们已经介绍了 Easysearch 的搭建可视化工具的使用,今天我们将探讨 Easysearch 集群的基本概念和常用的 API。

Easysearch 集群的核心概念

Easysearch 集群由以下几个核心概念构成:

  1. 节点(Node):集群中的单个服务器,负责存储数据并参与集群的索引和搜索功能。
  2. 集群(Cluster):由一个或多个节点组成,拥有唯一的集群名,协同完成数据索引和查询任务。
  3. 索引(Index):存储相关数据的容器,类似于关系数据库中的数据库,一个索引包含多个文档。
  4. 文档(Document):索引中的基本数据单位,相当于关系数据库中的行。
  5. 字段(Field):文档中的一个属性,相当于数据库中的列。
  6. 分片(Shard):为了提高性能和扩展性,索引可以被分割成多个分片,每个分片是索引的一个部分。
  7. 副本(Replica):分片的副本,用于提高数据的可靠性和在节点出现故障时的可用性。

通过多个 API,例如 _cluster/health_cluster/stats,用户可以轻松查看集群的健康状态和详细信息,这些信息对于维护和优化 Easysearch 集群至关重要。

无论是在性能的提升,还是在功能的兼容性方面,Easysearch 都为用户提供了一个强大的搜索引擎平台,让从 Elasticsearch 到 Easysearch 的迁移变得无缝且高效。掌握其核心概念和 API 的使用,将帮助开发者更好地利用这些工具来构建和优化他们的搜索解决方案。

查看集群信息

在 Easysearch 中,可以通过多个 API 来查看集群的各种信息,包括集群的健康状况、节点信息和索引状态。以下是一些常用的查看集群信息的 API 和示例:

查看集群健康状况

_cluster/health API 可以查看集群的健康状态,包括集群是否处于正常状态、节点数量、分片状态等。

GET /_cluster/health

示例响应:

{
  "cluster_name": "my_cluster",
  "status": "green",
  "timed_out": false,
  "number_of_nodes": 3,
  "number_of_data_nodes": 3,
  "active_primary_shards": 5,
  "active_shards": 10,
  "relocating_shards": 0,
  "initializing_shards": 0,
  "unassigned_shards": 0,
  "delayed_unassigned_shards": 0,
  "number_of_pending_tasks": 0,
  "number_of_in_flight_fetch": 0,
  "task_max_waiting_in_queue_millis": 0,
  "active_shards_percent_as_number": 100.0
}

查看集群状态

_cluster/stats API 可以查看集群的详细状态,包括索引、节点、分片等信息。

GET /_cluster/stats

示例响应:

{
  "cluster_name": "my_cluster",
  "status": "green",
  "indices": {
    "count": 10,
    "shards": {
      "total": 20,
      "primaries": 10,
      "replication": 1.0,
      "index": {
        "shards": {
          "min": 1,
          "max": 5,
          "avg": 2.0
        }
      }
    }
  },
  "nodes": {
    "count": {
      "total": 3,
      "data": 3,
      "coordinating_only": 0,
      "master": 1,
      "ingest": 2
    },
    "os": {
      "available_processors": 12,
      "allocated_processors": 12
    },
    "process": {
      "cpu": {
        "percent": 10
      },
      "open_file_descriptors": {
        "min": 100,
        "max": 300,
        "avg": 200
      }
    }
  }
}

查看节点信息

_nodes API 可以查看集群中节点的详细信息,包括节点角色、IP 地址、内存使用情况等。

GET /_nodes

示例响应:

{
  "cluster_name": "my_cluster",
  "nodes": {
    "node_id_1": {
      "name": "node_1",
      "transport_address": "192.168.1.1:9300",
      "host": "192.168.1.1",
      "ip": "192.168.1.1",
      "roles": ["master", "data", "ingest"],
      "os": {
        "available_processors": 4,
        "allocated_processors": 4
      },
      "process": {
        "cpu": {
          "percent": 10
        },
        "open_file_descriptors": 200
      }
    },
    "node_id_2": {
      "name": "node_2",
      "transport_address": "192.168.1.2:9300",
      "host": "192.168.1.2",
      "ip": "192.168.1.2",
      "roles": ["data"],
      "os": {
        "available_processors": 4,
        "allocated_processors": 4
      },
      "process": {
        "cpu": {
          "percent": 15
        },
        "open_file_descriptors": 150
      }
    }
  }
}

查看索引状态

_cat/indices API 可以查看集群中所有索引的状态,包括文档数、存储大小、分片数等信息。

GET /_cat/indices?v

示例响应:

health status index   uuid                   pri rep docs.count docs.deleted store.size pri.store.size
green  open   index_1 SxNUd84vRl6QH5P7g0T4Vg   1   1          0            0       230b           230b
green  open   index_2 NxEYib4yToCnA1PpQ8P4Xw   5   1        100            1      10mb           5mb

这些 API 可以帮助你全面了解 Easysearch 集群的状态和健康状况,从而更好地管理和维护集群。

增删改查操作

在 Easysearch 中,增删改查操作是管理数据和索引的基本功能。以下是如何使用这些操作的详细示例。

创建索引

创建一个新的索引,并指定分片和副本的数量:

PUT /my_index
{
  "settings": {
    "number_of_shards": 3,
    "number_of_replicas": 2
  }
}

删除索引

删除一个不再需要的索引:

DELETE /my_index

添加文档

通过 POST 或 PUT 请求向索引中添加文档:

POST /my_index/_doc/1
{
  "name": "John Doe",
  "age": 30,
  "occupation": "Engineer"
}
PUT /my_index/_doc/1
{
  "name": "John Doe",
  "age": 30,
  "occupation": "Engineer"
}

POSTPUT 方法用于不同的操作,尽管它们都可以用于添加或更新文档,但它们的行为有所不同。

POST /my_index/_doc/1 方法用于创建或替换一个文档。如果指定的文档 ID 已经存在,POST 请求将更新整个文档(不会合并字段)。如果文档 ID 不存在,它将创建一个新的文档。


POST /my_index/_doc/1
{
  "name": "John Doe",
  "age": 30,
  "occupation": "Engineer"
}

PUT /my_index/_doc/1 方法通常用于创建一个新的文档,或者完全替换一个已存在的文档。与 POST 类似,如果指定的文档 ID 已经存在,PUT 请求将替换整个文档。

PUT /my_index/_doc/1
{
  "name": "John Doe",
  "age": 30,
  "occupation": "Engineer"
}

1.使用场景:

  • POST:更适合用于添加或部分更新文档,即使文档 ID 已经存在。
  • PUT:更适合用于创建或完全替换文档。

2.ID 自动生成:

  • POST 请求可以不提供文档 ID,此时 Easysearch 会自动生成一个文档 ID。
  • PUT 请求必须提供文档 ID,如果未提供,则会返回错误。

3.部分更新:

  • POST 请求可以用于部分更新(通过 _update API)。
  • PUT 请求用于完全替换文档,不支持部分更新。

如果文档 ID 已经存在,POSTPUT 都会覆盖整个文档,并且效果是一样的。但是,通常 POST 用于提交数据,而 PUT 用于上传和替换资源。

1.使用 POST 方法添加或更新文档:

POST /my_index/_doc/1
{
  "name": "John Doe",
  "age": 30,
  "occupation": "Engineer"
}

2.使用 PUT 方法添加或更新文档:

PUT /my_index/_doc/1
{
  "name": "John Doe",
  "age": 30,
  "occupation": "Engineer"
}

在这两个示例中,结果都是在索引 my_index 中创建或更新文档 ID 为 1 的文档。无论使用 POST 还是 PUT,如果文档 ID 已存在,都会覆盖原有的文档内容。

新建文档

使用 _create 方法新建文档,如果文档已经存在则返回错误:

PUT /my_index/_create/1
{
  "a": 1
}

如果尝试新建已存在的文档,将会出现如下错误:

{
  "error": {
    "root_cause": [
      {
        "type": "version_conflict_engine_exception",
        "reason": "[1]: version conflict, document already exists (current version [1])",
        "index_uuid": "1xWdHLTaTm6l6HbqACaIEA",
        "shard": "0",
        "index": "my_index"
      }
    ],
    "type": "version_conflict_engine_exception",
    "reason": "[1]: version conflict, document already exists (current version [1])",
    "index_uuid": "1xWdHLTaTm6l6HbqACaIEA",
    "shard": "0",
    "index": "my_index"
  },
  "status": 409
}

获取文档

通过 ID 获取文档的详细信息:

GET /my_index/_doc/1

更新文档

更新文档的特定字段,保留原有字段:

POST /my_index/_update/1
{
  "doc": {
    "age": 31
  }
}

删除文档

通过 ID 删除指定的文档:

DELETE /my_index/_doc/1

查询所有文档

查询索引中的所有文档:

GET /my_index/_search
{
  "query": {
    "match_all": {}
  }
}

这个是 《老杨玩搜索》中总结的图,可以作为“小抄”来记忆:

批量操作 (_bulk API)

_bulk API 用于在一次请求中执行多个索引、删除和更新操作,这对于批量处理大规模数据非常有用,可以显著提高性能和效率。以下是 _bulk API 的基本使用示例:

POST /my_index/_bulk
{ "index": { "_id": "1" } }
{ "name": "John Doe", "age": 30, "occupation": "Engineer" }
{ "index": { "_id": "2" } }
{ "name": "Jane Doe", "age": 25, "occupation": "Designer" }
{ "update": { "_id": "1" } }
{ "doc": { "age": 31 } }

_bulk API 的请求体由多个操作和文档组成。每个操作行包含一个动作描述行和一个可选的源文档行。动作描述行指明了操作的类型(例如,index、create、delete、update)以及操作的元数据。源文档行则包含了实际的数据。

每个操作之间需要用换行符分隔,并且请求体最后必须以换行符结尾。

POST /_bulk
{ "index": { "_index": "a", "_id": "1" } }
{ "name": "John Doe", "age": 30, "occupation": "Engineer" }
{ "index": { "_index": "b", "_id": "2" } }
{ "name": "Jane Doe", "age": 25, "occupation": "Designer" }
{ "update": { "_index": "a", "_id": "1" } }
{ "doc": { "age": 31 } }

分词器

在 Easysearch 中,分词器(Analyzer)用于将文本分解为词项(terms),是全文搜索和文本分析的基础。分词器通常由字符过滤器(Character Filters)、分词器(Tokenizer)和词项过滤器(Token Filters)组成。以下是关于分词器的详细介绍:

1.字符过滤器(Character Filters):在分词之前对文本进行预处理。例如,去除 HTML 标签,替换字符等。

2.分词器(Tokenizer):将文本分解为词项(tokens)。这是分词过程的核心。

3.词项过滤器(Token Filters):对词项进行处理,如小写化、去除停用词、词干提取等。

只有 text 字段支持全文检索,返回的结果根据相似度打分,我们一起看下

POST /index/_mapping
{
  "properties": {
    "content": {
      "type": "text",
      "analyzer": "ik_max_word",
      "search_analyzer": "ik_smart"
    }
  }
}

.POST /index/_mapping

  • 这个部分表示要向名为 index 的索引添加或更新映射设置。

2.“properties”

  • properties 定义了索引中文档的字段结构。在这个例子中,定义了一个名为 content 的字段。

3.“content”

  • 定义了名为 content 的字段。

4.“type”: “text”

type 字段指定 content 字段的数据类型为 texttext 类型适用于需要分词和全文搜索的字段。

5.“analyzer”: “ik_max_word”

analyzer 字段指定索引时使用的分词器为ik_max_wordik_max_word 是 IK 分词器中的一种,它会尽可能多地将文本分解为更多的词项。

6.“search_analyzer”: “ik_smart”

search_analyzer 字段指定搜索时使用的分词器为ik_smartik_smart 是 IK 分词器中的另一种,它会更智能地进行分词,以提高搜索的准确性。

当然,在设置这个 mapping 的时候可以使用同样的分词器,也可以使用不同的分词器。这里介绍下 IK 分词器:

  • IK 分词器是一种中文分词器,适用于中文文本的分词。IK 分词器有两种分词模式:ik_max_wordik_smart
    • ik_max_word:将文本尽可能多地切分成词项,适用于需要更高召回率的场景。
    • ik_smart:进行最智能的分词,适用于需要更高精度的搜索场景。

这个 DSL 的设置意味着,在向这个索引添加或更新文档时,content 字段的文本会使用ik_max_word 分词器进行分词处理,以确保文本被尽可能多地切分成词项。而在搜索时,content 字段的文本会使用ik_smart 分词器进行分词处理,以提高搜索的准确性和相关性。

以下是关于 standard,ik_smart,ik_max_word 这几个分词器的对比:

GET /_analyze
{
  "tokenizer": "standard",
  "text": "我,机器人"
}

GET /_analyze
{
  "tokenizer": "ik_smart",
  "text": "我,机器人"
}

GET /_analyze
{
  "tokenizer": "ik_max_word",
  "text": "我,机器人"
}

结果如下:

# GET /_analyze (standard)
{
  "tokens": [
    {
      "token": "我",
      "start_offset": 0,
      "end_offset": 1,
      "type": "<IDEOGRAPHIC>",
      "position": 0
    },
    {
      "token": "机",
      "start_offset": 2,
      "end_offset": 3,
      "type": "<IDEOGRAPHIC>",
      "position": 1
    },
    {
      "token": "器",
      "start_offset": 3,
      "end_offset": 4,
      "type": "<IDEOGRAPHIC>",
      "position": 2
    },
    {
      "token": "人",
      "start_offset": 4,
      "end_offset": 5,
      "type": "<IDEOGRAPHIC>",
      "position": 3
    }
  ]
}
# GET /_analyze(ik_smart)
{
  "tokens": [
    {
      "token": "我",
      "start_offset": 0,
      "end_offset": 1,
      "type": "CN_CHAR",
      "position": 0
    },
    {
      "token": "机器人",
      "start_offset": 2,
      "end_offset": 5,
      "type": "CN_WORD",
      "position": 1
    }
  ]
}
# GET /_analyze (ik_max_word)
{
  "tokens": [
    {
      "token": "我",
      "start_offset": 0,
      "end_offset": 1,
      "type": "CN_CHAR",
      "position": 0
    },
    {
      "token": "机器人",
      "start_offset": 2,
      "end_offset": 5,
      "type": "CN_WORD",
      "position": 1
    },
    {
      "token": "机器",
      "start_offset": 2,
      "end_offset": 4,
      "type": "CN_WORD",
      "position": 2
    },
    {
      "token": "人",
      "start_offset": 4,
      "end_offset": 5,
      "type": "CN_CHAR",
      "position": 3
    }
  ]
}

如果使用了不存在的分词器会出现这个错误。

{
  "error": {
    "root_cause": [
      {
        "type": "illegal_argument_exception",
        "reason": "failed to find global tokenizer under [simple]"
      }
    ],
    "type": "illegal_argument_exception",
    "reason": "failed to find global tokenizer under [simple]"
  },
  "status": 400
}

精确搜索/正则表达式搜索/通配符

在 Easysearch 中,精确搜索、正则表达式搜索和通配符搜索是三种不同的搜索方式,各有其应用场景和特点:

1.精确搜索 (Term Query)

  • 精确搜索用于查找与搜索词完全匹配的文档。
  • 不进行分词处理,通常用于关键字、ID、标签等字段的精确匹配。
  • 适用于结构化数据或不需要分词的字段(如数字、日期、布尔值等)。
{
  "query": {
    "term": {
      "status": "active"
    }
  }
}

2.正则表达式搜索 (Regexp Query)

  • 正则表达式搜索用于基于正则表达式模式匹配的文档搜索。
  • 支持复杂的字符串匹配模式,但性能可能较低,特别是当数据量较大时。
  • 适用于需要灵活且复杂匹配条件的搜索。
{
  "query": {
    "regexp": {
      "content": "Easysearch .*powerful"
    }
  }
}

3.通配符搜索 (Wildcard Query)

  • 通配符搜索用于通过通配符模式匹配文档。
  • 支持 ?(匹配单个字符)和 *(匹配零个或多个字符)。
  • 性能相对较差,因为通配符搜索可能需要扫描大量数据。
{
  "query": {
    "wildcard": {
      "username": "john*"
    }
  }
}
  • 精确搜索:用于需要绝对匹配特定词语或不需要分词的字段。例如,查找特定用户 ID 或状态。
  • 正则表达式搜索:用于需要复杂字符串模式匹配的场景,但要谨慎使用,避免性能问题。
  • 通配符搜索:用于简单模式匹配,但同样需要注意性能影响,尽量避免在大数据集上频繁使用。

接下来看这个例子,我们将使用批量导入数据,然后进行几种不同类型的查询,包括精确查询、通配符查询和正则表达式查询。

POST /users/_bulk
{ "index": { "_index": "users", "_id": 1 }}
{ "username": "john_doe", "status": "active", "email": "john.doe@example.com", "bio": "John loves Easysearch  and open-source technologies." }
{ "index": { "_index": "users", "_id": 2 }}
{ "username": "jane_doe", "status": "inactive", "email": "jane.doe@example.com", "bio": "Jane is a data scientist working with big data." }
{ "index": { "_index": "users", "_id": 3 }}
{ "username": "john_smith", "status": "active", "email": "john.smith@example.com", "bio": "John enjoys hiking and nature." }
{ "index": { "_index": "users", "_id": 4 }}
{ "username": "alice_jones", "status": "active", "email": "alice.jones@example.com", "bio": "Alice is a software engineer specialized in JavaScript." }
{ "index": { "_index": "users", "_id": 5 }}
{ "username": "bob_jones", "status": "inactive", "email": "bob.jones@example.com", "bio": "Bob is an AI enthusiast and machine learning expert." }

1.精确查询:查询状态为 “active” 的用户。

GET /users/_search
{
  "query": {
    "term": {
      "status": "active"
    }
  }
}

2.通配符查询:查询 bio 字段中包含 “John” 开头的词。

GET /users/_search
{
  "query": {
    "wildcard": {
      "bio": "John*"
    }
  }
}

3.正则表达式查询:查询用户名以 “john” 开头的用户

GET /users/_search
{
  "query": {
    "regexp": {
      "username": "john.*"
    }
  }
}

通过这些例子,你可以看到如何在 Easysearch 中使用批量导入数据,然后使用各种查询方法来检索特定条件的数据。这些查询方法可以帮助你高效地搜索和分析数据,以满足不同的业务需求。

这里同样是《老杨玩搜索》中总结的“小抄”来方便记忆:

多字段查询

在 Easysearch 中,多字段查询允许您在多个字段上同时执行搜索,以获取更精确的结果。最常用的多字段查询类型是 multi_match 查询。multi_match 查询是 match 查询的扩展,能够在多个字段中搜索指定的关键词。

multi_match 查询支持多种匹配模式,如 best_fieldsmost_fieldscross_fieldsphrasephrase_prefix。以下是各模式的简要介绍:

  • best_fields:默认模式,选择匹配度最高的字段。
  • most_fields:计算每个字段的匹配度,然后将匹配度相加。
  • cross_fields:将多个字段视为一个字段进行匹配,适用于分析文本被分散到多个字段的情况。
  • phrase:短语匹配,确保词项顺序与查询相同。
  • phrase_prefix:短语前缀匹配,允许词项的部分匹配。

我们先导入一些示例数据到一个索引 documents 中:

POST /documents/_bulk
{ "index": { "_id": 1 } }
{ "title": "Easysearch  Guide", "content": "This is an introductory guide to Easysearch ." }
{ "index": { "_id": 2 } }
{ "title": "Advanced Easysearch ", "content": "This guide covers advanced topics in Easysearch ." }
{ "index": { "_id": 3 } }
{ "title": "Easysearch  in Action", "content": "Practical guide to Easysearch  usage." }
{ "index": { "_id": 4 } }
{ "title": "Learning Easysearch ", "content": "Beginner's guide to learning Easysearch ." }

我们将使用 multi_match 查询在 titlecontent 字段中同时搜索关键词。

1.基本 multi_match 查询

POST /documents/_search
{
  "query": {
    "multi_match": {
      "query": "guide",
      "fields": ["title", "content"]
    }
  }
}

2.指定匹配模式为 best_fields

POST /documents/_search
{
  "query": {
    "multi_match": {
      "query": "guide",
      "fields": ["title", "content"],
      "type": "best_fields"
    }
  }
}

3.指定匹配模式为 most_fields

POST /documents/_search
{
  "query": {
    "multi_match": {
      "query": "guide",
      "fields": ["title", "content"],
      "type": "most_fields"
    }
  }
}

4.使用 cross_fields 模式

POST /documents/_search
{
  "query": {
    "multi_match": {
      "query": "Easysearch  guide",
      "fields": ["title", "content"],
      "type": "cross_fields"
    }
  }
}

5.短语匹配 (phrase)

POST /documents/_search
{
  "query": {
    "multi_match": {
      "query": "introductory guide",
      "fields": ["title", "content"],
      "type": "phrase"
    }
  }
}

6.短语前缀匹配 (phrase_prefix)

POST /documents/_search
{
  "query": {
    "multi_match": {
      "query": "introductory gui",
      "fields": ["title", "content"],
      "type": "phrase_prefix"
    }
  }
}
  • query:要搜索的关键词或短语。
  • fields:要搜索的字段列表,可以包含一个或多个字段。
  • type:指定匹配模式,默认为 best_fields。

使用 multi_match 查询,您可以在多个字段上同时执行搜索,获得更精确和全面的结果。通过指定不同的匹配模式,您可以调整查询行为以满足特定的搜索需求。无论是基本关键词匹配、短语匹配还是跨字段匹配,multi_match 查询都提供了强大的功能来处理复杂的搜索场景。

除此之外,还可以使用 boost 参数用于调整特定字段的权重,从而影响搜索结果的相关性评分。multi_match 查询支持为不同字段设置不同的 boost 值,以便在搜索结果中优先显示某些字段的匹配项。

布尔查询

布尔查询是 Easysearch 中非常强大且灵活的一种查询方式,它允许用户通过组合多个查询条件来实现复杂的搜索需求。布尔查询使用 bool 查询类型,可以包含以下几种子句:mustfiltermust_notshould。每种子句都有其特定的用途和语义。

1.must

  • 包含在 must 数组中的查询条件必须匹配,类似于逻辑上的 AND 操作。
  • 如果有多个条件,所有条件都必须满足,文档才会被包含在结果集中。

2.filter

  • 包含在 filter 数组中的查询条件必须匹配,但它不会影响评分。
  • filter 子句通常用于对性能要求较高的过滤操作,因为它不计算相关性评分。

3.must_not

  • 包含在 must_not 数组中的查询条件必须不匹配,类似于逻辑上的 NOT 操作。
  • 如果有任何一个条件匹配,文档就会被排除在结果集之外。

4.should

  • 包含在 should 数组中的查询条件至少匹配一个。
  • 如果布尔查询中没有 must 子句,则至少要匹配一个 should 子句。
  • should 子句在计算相关性评分时也有影响。

5.minimum_should_match

  • 指定 should 子句中至少需要满足的条件数量。

首先,我们需要创建一个名为 books 的索引,并定义它的映射(mappings)。映射用于指定每个字段的数据类型。在这个例子中,类别书名字段都被定义为 keyword 类型,这是因为我们需要进行精确匹配查询。

PUT /books
{
  "mappings": {
    "properties": {
      "类别": { "type": "keyword" },
      "书名": { "type": "keyword" }
    }
  }
}

接下来,我们使用批量操作(bulk API)将一些示例数据导入到 books 索引中。这些数据包括不同类别的书籍。

POST /books/_bulk
{ "index": { "_id": 1 } }
{ "类别": "文学", "书名": "我的阿勒泰" }
{ "index": { "_id": 2 } }
{ "类别": "文学", "书名": "平凡的世界" }
{ "index": { "_id": 3 } }
{ "类别": "科学", "书名": "时间简史" }
{ "index": { "_id": 4 } }
{ "类别": "文学", "书名": "百年孤独" }
{ "index": { "_id": 5 } }
{ "类别": "文学", "书名": "红楼梦" }

现在,我们使用布尔查询来搜索类别为“文学”并且书名为“我的阿勒泰”的文档。这里使用的是 must子句,表示查询结果必须满足所有条件。

POST /books/_search
{
  "query": {
    "bool": {
      "must": [
        { "term": { "类别": "文学" } },
        { "term": { "书名": "我的阿勒泰" } }
      ]
    }
  }
}

我们还可以使用 filter 子句来执行相同的查询。filter 子句用于过滤文档,且不会影响文档的相关性评分。这在不需要计算相关性评分时可以提高查询性能。

POST /books/_search
{
  "query": {
    "bool": {
      "filter": [
        { "term": { "类别": "文学" } },
        { "term": { "书名": "我的阿勒泰" } }
      ]
    }
  }
}

当我们执行上述查询时,期望返回的结果是 books 索引中类别为“文学”且书名为“我的阿勒泰”的文档。无论是使用 must 还是 filter 子句,结果应该都是:

{
  "hits": {
    "total": {
      "value": 1,
      "relation": "eq"
    },
    "hits": [
      {
        "_index": "books",
        "_id": "1",
        "_source": {
          "类别": "文学",
          "书名": "我的阿勒泰"
        }
      }
    ]
  }
}

POST /_search
{
  "query": {
    "bool": {
      "must": [
        { "term": { "user.id": "kimchy" } }
      ],
      "filter": [
        { "term": { "tags": "production" } }
      ],
      "must_not": [
        {
          "range": {
            "age": { "gte": 10, "lte": 20 }
          }
        }
      ],
      "should": [
        { "term": { "tags": "env1" } },
        { "term": { "tags": "deployed" } }
      ],
      "minimum_should_match": 1,
      "boost": 1.0
    }
  }
}
  • must 子句:必须匹配的条件,文档必须包含 user.idkimchy
  • filter 子句:过滤条件,文档必须包含 tagsproduction ,但不会影响评分。
  • must_not子句:不匹配的条件,文档的 age 字段不能在 10 到 20 之间。
  • should 子句:可选匹配条件,至少需要匹配一个 should 子句中的条件。这里要求 tags 字段匹配 env1deployed
  • minimum_should_match:至少需要匹配一个 should 子句中的条件。
  • boost:提升查询的整体评分。

为了展示这个 DSL ,我们需要创建一个索引并导入一些数据。假设我们要在 Easysearch 中创建一个索引 users ,并插入一些测试数据。

创建索引

PUT /users
{
  "mappings": {
    "properties": {
      "user.id": { "type": "keyword" },
      "tags": { "type": "keyword" },
      "age": { "type": "integer" }
    }
  }
}

批量导入数据

POST /users/_bulk
{ "index": { "_id": 1 } }
{ "user.id": "kimchy", "tags": ["production", "env1"], "age": 25 }
{ "index": { "_id": 2 } }
{ "user.id": "kimchy", "tags": ["production"], "age": 15 }
{ "index": { "_id": 3 } }
{ "user.id": "kimchy", "tags": ["deployed"], "age": 30 }
{ "index": { "_id": 4 } }
{ "user.id": "kimchy", "tags": ["test"], "age": 35 }
{ "index": { "_id": 5 } }
{ "user.id": "other", "tags": ["production"], "age": 25 }

接下来执行布尔查询:

POST /users/_search
{
  "query": {
    "bool": {
      "must": [
        { "term": { "user.id": "kimchy" } }
      ],
      "filter": [
        { "term": { "tags": "production" } }
      ],
      "must_not": [
        {
          "range": {
            "age": { "gte": 10, "lte": 20 }
          }
        }
      ],
      "should": [
        { "term": { "tags": "env1" } },
        { "term": { "tags": "deployed" } }
      ],
      "minimum_should_match": 1,
      "boost": 1.0
    }
  }
}

根据以上查询,预期返回的结果应该符合以下条件:

  1. user.id必须是 kimchy(由 must 子句决定)。
  2. tags 必须包含 production (由 filter 子句决定)。
  3. age 字段不在 10 到 20 之间(由 must_not 子句决定)。
  4. tags字段中至少包含 env1deployed 中的一个(由 should 子句和 minimum_should_match 参数决定)。
{
  "took": 1,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 1,
      "relation": "eq"
    },
    "max_score": 1.3769134,
    "hits": [
      {
        "_index": "users",
        "_type": "_doc",
        "_id": "1",
        "_score": 1.3769134,
        "_source": {
          "user.id": "kimchy",
          "tags": ["production", "env1"],
          "age": 25
        }
      }
    ]
  }
}

SQL 搜索

Easysearch 直接支持 SQL 查询,无需额外安装插件,同时兼容 Elasticsearch 的 SQL 调用方式,还可以直接编写原生 SQL 查询。

以下是一些测试 SQL 语句的示例:

SELECT * FROM my_index;

SELECT * FROM my_index LIMIT 2;

SELECT * FROM my_index ORDER BY name;

SELECT name AS full_name, age FROM my_index WHERE age > 25;

SELECT name AS full_name, age FROM my_index WHERE age = 25;

SELECT * FROM my_index WHERE age IS NULL;

SELECT DISTINCT age FROM my_index;

SELECT MIN(age), MAX(age), AVG(age) FROM my_index;

SELECT age, COUNT(*) AS CNT FROM my_index GROUP BY age;

使用 Easysearch 执行 SQL 查询

Easysearch 提供了对直接使用 SQL 查询的支持。以下是如何在 Easysearch 中通过 POST 请求使用 _sql 端点进行查询的示例:

执行 SQL 查询非常简单,只需通过 POST 请求发送 SQL 查询即可。以下是一个示例:

POST /_sql
{
  "query": "SELECT name AS full_name, age FROM my_index WHERE age > 25"
}

你也可以规定返回 JSON 格式:

POST /_sql?format=json
{
  "query": "SELECT name AS full_name, age FROM my_index WHERE age > 25"
}

和 Elasticsearch 一样,Easysearch 允许你通过 POST 请求直接在集群上运行 SQL 查询,并返回查询结果。以下是一些常见的 SQL 查询示例及其对应的 POST 请求:

1.查询所有文档

POST /_sql
{
  "query": "SELECT * FROM my_index"
}

2.限制返回文档数

POST /_sql
{
  "query": "SELECT * FROM my_index LIMIT 2"
}

3.按字段排序

POST /_sql
{
  "query": "SELECT * FROM my_index ORDER BY name"
}

4.筛选条件查询

POST /_sql
{
  "query": "SELECT name AS full_name, age FROM my_index WHERE age > 25"
}

5.精确值查询

POST /_sql
{
  "query": "SELECT name AS full_name, age FROM my_index WHERE age = 25"
}

6.查询空值

POST /_sql
{
  "query": "SELECT * FROM my_index WHERE age IS NULL"
}

7.查询唯一值

POST /_sql
{
  "query": "SELECT DISTINCT age FROM my_index"
}

8.聚合函数查询

POST /_sql
{
  "query": "SELECT MIN(age), MAX(age), AVG(age) FROM my_index"
}

9.分组统计

POST /_sql
{
  "query": "SELECT age, COUNT(*) AS CNT FROM my_index GROUP BY age"
}

多表操作的 SQL 语句

以下是多表操作的 SQL 语句及其解释:

1.子查询

SELECT * FROM `table1` t1 WHERE t1.id IN (SELECT id FROM `table2`)

这个查询从 table1 中选择所有字段的记录,其中这些记录的 idtable2 表中也存在。

2.内连接

SELECT * FROM `table1` t1 JOIN `table2` t2 ON t1.id = t2.id

这个查询进行内连接,从 table1table2 中选择所有字段的记录,前提是 table1table2id 相等。

3.左连接

SELECT * FROM `table1` t1 LEFT JOIN `table2` t2 ON t1.id = t2.id

这个查询进行左连接,从 table1table2 中选择所有字段的记录,即使 table2 中没有匹配的记录,也会返回 table1 中的所有记录,未匹配到的部分会用 NULL 填充。

4.右连接

SELECT * FROM `table1` t1 RIGHT JOIN `table2` t2 ON t1.id = t2.id

这个查询进行右连接,从 table1table2 中选择所有字段的记录,即使 table1 中没有匹配的记录,也会返回 table2 中的所有记录,未匹配到的部分会用 NULL 填充。

假设我们有两个索引 table1table2,对应于 SQL 中的两个表。

创建索引 table1

PUT /`table1`
{
  "mappings": {
    "properties": {
      "id": { "type": "integer" },
      "name": { "type": "text" }
    }
  }
}

创建索引 table2

PUT /`table2`
{
  "mappings": {
    "properties": {
      "id": { "type": "integer" },
      "value": { "type": "text" }
    }
  }
}

导入数据到 table1

POST /`table1`/_bulk
{ "index": { "_id": 1 } }
{ "id": 1, "name": "Alice" }
{ "index": { "_id": 2 } }
{ "id": 2, "name": "Bob" }
{ "index": { "_id": 3 } }
{ "id": 3, "name": "Charlie" }
{ "index": { "_id": 4 } }
{ "id": 4, "name": "David" }

导入数据到 table2

POST /`table2`/_bulk
{ "index": { "_id": 1 } }
{ "id": 1, "value": "Value1" }
{ "index": { "_id": 2 } }
{ "id": 2, "value": "Value2" }
{ "index": { "_id": 5 } }
{ "id": 5, "value": "Value5" }
{ "index": { "_id": 6 } }
{ "id": 6, "value": "Value6" }

导入数据后,可以使用 SQL 来执行这些查询:

1.子查询:

POST /_sql
{
  "query": "SELECT * FROM `table1` WHERE id IN (SELECT id FROM `table2`)"
}

2.内连接:

POST /_sql
{
  "query": "SELECT * FROM `table1` t1 JOIN `table2` t2 ON t1.id = t2.id"
}

3.左连接:

POST /_sql
{
  "query": "SELECT * FROM `table1` t1 LEFT JOIN `table2` t2 ON t1.id = t2.id"
}

4.右连接:

POST /_sql
{
  "query": "SELECT * FROM `table1` t1 RIGHT JOIN `table2` t2 ON t1.id = t2.id"
}

效果如下:

SQL 全文检索

matchmatch_phrase 是 Easysearch 中用于全文搜索的查询类型,它们在处理文本匹配方面有不同的用途:

1.match 查询:

  • match 查询用于对文档进行全文搜索。
  • 它将搜索关键词进行分词,并对这些分词后的词项进行搜索。
  • 适用于查询单个或多个字段,可以进行布尔操作(如 “AND”, “OR”)。
  • 例如,搜索 “Easysearch is powerful” 会被分词为 "Easysearch ", “is”, “powerful” 三个词,然后对这三个词进行搜索,文档中包含这些词的都会被认为是匹配的。
{
  "query": {
    "match": {
      "content": "Easysearch  is powerful"
    }
  }
}

2.match_phrase 查询:

  • match_phrase 查询用于短语搜索。
  • 它要求搜索的短语必须在文档中出现且词的顺序相同,词之间的间隔也必须与查询中的短语相同。
  • 适用于需要精确匹配短语的场景。
  • 例如,搜索 “Easysearch is powerful” 时,只有包含这个确切短语的文档才会被认为是匹配的。
{
  "query": {
    "match_phrase": {
      "content": "Easysearch  is powerful"
    }
  }
}

总结来说,match 更灵活,用于一般的关键词搜索,而 match_phrase 则用于需要精确匹配短语的搜索。

SQL 全文检索示例

我们先造一些数据,然后使用 SQL 来进行全文检索。

批量导入数据:

POST /table3/_bulk
{ "index": { "_id": 1 } }
{ "id": 1, "test": "The quick brown fox jumps over the lazy dog" }
{ "index": { "_id": 2 } }
{ "id": 2, "test": "Foxes are wild animals" }
{ "index": { "_id": 3 } }
{ "id": 3, "test": "Jump high to catch the ball" }
{ "index": { "_id": 4 } }
{ "id": 4, "test": "Some animals can jump very high" }
{ "index": { "_id": 5 } }
{ "id": 5, "test": "The lazy dog sleeps all day" }
{ "index": { "_id": 6 } }
{ "id": 6, "test": "The foxes jump all day" }

执行全文检索的 SQL 查询:

SELECT * FROM table3;

SELECT * FROM table3 WHERE match(test, 'jump');

SELECT * FROM table3 WHERE match_phrase(test, 'foxes jump');

总结

随着数据量的不断增加,高效的数据搜索和分析变得尤为重要。Elasticsearch 以其强大的全文搜索能力和灵活的数据处理能力成为行业标准。Easysearch 作为 Elasticsearch 的优化版本,不仅继承了其强大的功能,还在性能和安全性上做了进一步的提升,为企业提供了一个高效、稳定且易于迁移的搜索引擎解决方案。通过深入了解这些技术和实践其应用,开发者和企业能够更好地利用这些工具来应对现代数据挑战,推动业务的持续发展和创新。

关于 Easysearch 有奖征文活动

黑神话悟空

无论你是 Easysearch 的老用户,还是第一次听说这个名字,只要你对 INFINI Labs 旗下的 Easysearch 产品感兴趣,或者是希望了解 Easysearch,都可以参加这次活动。

详情查看:Easysearch 征文活动

作者:韩旭,亚马逊云技术支持,亚马逊云科技技领云博主,目前专注于云计算开发和大数据领域。

原文:https://infinilabs.cn/blog/2024/mastering-easysearch-syntax/

Easysearch 数据可视化和管理平台:INFINI Console 使用介绍

EasysearchINFINI Labs 小助手 发表了文章 • 0 个评论 • 2837 次浏览 • 2024-07-10 16:26 • 来自相关话题

上次在《INFINI Easysearch 尝鲜 Hands on》中,我们部署了两个节点的 Easysearch,并设置了 Console 进行集群监控。今天,我们将介绍 INFINI Console 的使用。

Dashboard

INFINI Console 是一个功能强大的数据管理和分析平台,其仪表盘页面提供了直观简洁的界面,使用户能够快速了解系统状态并进行管理操作。本文将详细介绍仪表盘页面的各项功能。

仪表盘顶部显示系统的实时告警、通知和待办事项的数量,当前数据显示:

  • 告警:0 条
  • 通知:0 条
  • 待办:0 条

在仪表盘的中心区域,用户可以看到几项关键的系统概览信息:

  • 集群数量:当前有 3 个集群正在运行。
  • 节点数量:系统中有 16 个节点。
  • 主机数量:共有 3 台主机。
  • 已用存储:系统已使用存储空间为 2.0GB。

仪表盘页面还提供了几个常用操作的快速入口,方便用户迅速访问常用功能:

  • 集群注册:用户可以通过此入口快速注册新的集群。
  • 数据探索:用户可以访问数据探索工具,对系统中的数据进行分析和查询。
  • 告警管理:提供对告警信息的管理功能,用户可以查看和处理告警。
  • 安全管理:安全管理入口帮助用户维护系统的安全设置和策略。

仪表盘右侧显示了集群的动态信息,包括最近的操作日志。例如:

  • 2024-07-03 22:43:43,index medcl 在 cluster infiniLabs 中的状态更新。
  • 2024-07-03 22:06:43,index medcl 在 cluster infiniLabs 中被创建。

集群管理页面

集群管理页面主要分为几个部分:顶部的功能选项卡、中部的集群列表、以及右侧的筛选和排序选项。

页面顶部的功能选项卡包括以下几项:

  • Clusters (集群):显示当前系统中的所有集群。
  • Nodes (节点):显示集群中的节点详细信息。
  • Indices (索引):显示集群中的索引信息。
  • Hosts (主机):显示系统中的主机信息。

集群列表展示了每个集群的详细信息,包括:

  • 集群名称:每个集群的名称,如 “infinilabs”、“mycluster”、“INFINI_SYSTEM (JeanGrey)”。
  • 集群健康状态:以颜色条的形式显示最近 14 天的集群健康状态(绿色表示健康,黄色表示有警告)。
  • 节点数量:集群中包含的节点数量。
  • 索引数量:集群中的索引数量。
  • 分片数量:集群中的分片数量。
  • 文档数量:集群中存储的文档数量。
  • 磁盘使用率:集群的磁盘使用情况。
  • JVM 堆内存使用率:集群的 JVM 堆内存使用情况。
  • 索引速率:当前集群的索引速率(每秒索引数)。
  • 搜索速率:当前集群的搜索速率(每秒搜索数)。

页面右侧提供了丰富的筛选和排序选项,可以根据以下条件筛选和排序集群:

  • 健康状态 (Health Status):根据集群的健康状态筛选,如绿色(健康)和黄色(警告)。
  • 分布 (Distribution):根据集群的分布类型筛选,如 “easysearch” 和 “elasticsearch”。
  • 版本 (Version):根据集群使用的软件版本筛选,如 Easysearch 1.8.2 和 Elasticsearch 7.10.2。
  • 区域 (Region):根据集群所在的区域筛选,如 “china” 和 “default”。
  • 标签 (Tags):根据自定义标签进行筛选。

接下来分别介绍节点、索引和主机层面的信息,这些监控指标与集群层面大同小异。

节点监控

索引监控

主机监控

包括了常规的 CPU、内存、磁盘、网络的监控。

监控指标页面

监控报表页面提供了对集群运行状况的详细监控和分析功能。用户可以选择最近 15 分钟、1 小时、24 小时等不同时间范围查看数据,并手动点击刷新按钮更新数据,以获取最新的监控信息。

概览信息

显示当前集群的基本状态,包括:

  • 集群名称:如 “infinilabs”。
  • 在线时长:如 “3 天”。
  • 集群版本:如 “1.8.2”。
  • 健康状态:如 “green”。
  • 节点数:如 “2”。
  • 索引数:如 “38”。
  • 主/总分片:如 “38/76”。
  • 未分配分片:如 “0”。
  • 文档数:如 “656,803”。
  • 存储空间:如 “1007.2MB/385.4GB”。
  • JVM 内存:如 “1023.0MB/2.0GB”。

监控报表页面还提供了多个性能指标的图表,包括:

索引吞吐 (doc/s)

  • Total Indexing:总索引吞吐量。
  • Primary Indexing:主分片的索引吞吐量。

查询吞吐 (query/s)

  • Total Query:总查询吞吐量。

索引延迟 (ms)

  • Indexing Latency:索引延迟时间。
  • Delete Latency:删除操作的延迟时间。

查询延迟 (ms)

  • Query Latency:查询延迟时间。
  • Fetch Latency:获取操作的延迟时间。
  • Scroll Latency:滚动操作的延迟时间。

点击“Advance”可以查看更多监控指标:

节点级别性能监控

包括 CPU、负载、JVM 内存、剩余使用空间及磁盘空间、集群启动时间和索引读写情况。

索引级别监控

包括集群内索引的数量、状态、主分片和副本分片数量、文档条数和占用空间。

集群动态页面

提供集群中各类事件和活动的详细记录和监控功能。

别名管理

别名管理页面提供了对索引别名的管理功能,使用户可以方便地管理和配置 Elasticsearch/EasySearch 的索引别名。

创建别名

可以通过 DSL 创建别名。例如,创建一个名为 my_index_alias 的别名指向 my_index

POST /_aliases
{
  "actions": [
    {
      "add": {
        "index": "my_index",
        "alias": "my_index_alias"
      }
    }
  ]
}

删除别名

删除一个别名同样可以通过 REST API 实现:

POST /_aliases
{
  "actions": [
    {
      "remove": {
        "index": "my_index",
        "alias": "my_index_alias"
      }
    }
  ]
}

索引轮换

索引轮换是一种常用的索引管理策略,特别适用于日志和时间序列数据的场景。通过索引轮换,用户可以在索引达到一定条件(如大小或文档数量)时,创建一个新的索引来继续存储数据,而旧的索引可以继续用于查询。

  1. 设置写别名:创建一个指向当前写入索引的别名,例如 current_write_index。
  2. 定义索引轮换条件:可以基于索引的大小、文档数量或时间来定义轮换条件。
  3. 索引并更新写别名指向这个新索引。

创建初始索引并设置写别名:

PUT /my_index-000001
{
  "aliases": {
    "current_write_index": {}
  }
}

使用 /_rollover API 定义轮换条件并执行轮换:

POST /current_write_index/_rollover
{
  "conditions": {
    "max_age": "7d",
    "max_docs": 1000000
  },
  "settings": {
    "number_of_shards": 1
  },
  "aliases": {
    "current_write_index": {}
  }
}

通过这种方式,查询操作可以透明地访问所有历史数据,而写操作总是指向最新的索引。

在 INFINI Console 中提供了可视化创建索引及别名的方式。页面右上角提供了新建按钮,用户可以通过点击该按钮创建新的索引别名,填写别名名称、关联索引、索引路由、搜索路由和过滤查询等配置。

平台监控

展示了多个关键指标的监控图表,包括:

  • 健康状态 (Health):显示系统当前的健康状态。如果没有数据,则显示“暂无数据”。
  • 引擎分布 (Engines):展示系统中不同搜索引擎的分布情况,例如 EasySearch 和 Elasticsearch 的比例。图表显示当前 EasySearch 占 67%,Elasticsearch 占 33%。
  • 提供商 (Providers):显示系统中使用的云服务提供商信息。在示例中,所有资源都托管在 AWS 上。
  • JDK 版本 (JDK):显示系统中使用的 JDK 版本信息。在示例中,所有节点都使用 JDK 版本 11.0.20。
  • 磁盘使用情况 (Disk Utilization) - Top 10:显示磁盘使用率最高的前 10 个节点。在示例中,easysearch-node1 和 easysearch-node2 的磁盘使用率均为 4%。
  • JVM 使用情况 (JVM Utilization) - Top 10:展示 JVM 使用率最高的前 10 个节点。在示例中,infinilabs 集群的 easysearch-node1 和 easysearch-node2 节点的 JVM 使用情况有详细的时间序列数据,显示了不同时间点的使用率变化。

我们还能够看到更多指标:

数据探索

在数据探索里,可以根据时间、字段等条件对索引或者视图下的数据进行搜索查询和分析,类似 Kibana 的 Discover。

这里可以看到集群的警报,目前集群运行良好,没有任何警报。

内部会预设一些警报规则,如下:

点进去一个请求,比如磁盘的警告,可以针对不同的使用量设置不同的警告级别和通知。

这里针对警报设置警报,可以看到现在支持很多平台,Discord、飞书、邮件、微信、Slack 以及钉钉。

点击进去可以查看,对于社交软件而言,其实是使用 Webhook 进行通知,除此之外也支持配置邮件服务器和自定义的 Webhook 进行通知。

开发工具

Console 的开发工具相当于 Kibana DevTool 的升级版,使用上基本没有大的区别,除了支持 DSL 之外,还支持多集群 Tab 切换、常用命令快速 Load、SQL 查询等。

集群连接凭证管理

可以看到连接这三个集群的凭证管理,目前都是有效的。

后台用户授权

可以添加用户以及修改 Console 管理界面的密码。目前设置了 admin 账号。

审计日志

追踪对集群的操作,捕获查看集群监控信息以及集群索引的操作。

结论

INFINI Console 的仪表盘页面集成了系统的关键信息和快捷操作入口,使用户可以高效地管理和监控系统。通过详细的概览信息、实时的告警通知、快速的功能入口和动态日志,用户能够对系统的运行状态一目了然,并快速响应各种管理需求。这个设计不仅提升了用户的工作效率,还确保了系统的安全和稳定运行。

INFINI Console 的集群管理页面提供了对系统集群的全面监控和管理功能。通过详细的集群信息展示、便捷的功能选项卡切换以及丰富的筛选和排序功能,用户可以高效地管理和监控系统中的集群状态。这不仅提升了运维效率,还确保了系统的稳定运行和高效管理。

INFINI Console 的节点管理页面提供了对集群节点的全面监控和管理功能。通过详细的节点信息展示、便捷的功能选项卡切换以及丰富的筛选和搜索功能,用户可以高效地管理和监控系统中的节点状态,从而提升运维效率,确保系统的稳定运行和高效管理。

INFINI Console 的监控报表页面提供了对集群运行状况的全面监控和分析功能。通过详细的概览信息和多个性能指标图表,用户可以高效地监控和管理集群的运行状态。这不仅提升了系统运维效率,还确保了集群的稳定运行和高效管理。

通过这些功能,INFINI Console 为用户提供了全面的系统管理工具,帮助他们高效地应对各种运维挑战,确保系统的高效、安全、稳定运行。

关于 Easysearch 有奖征文活动

黑神话悟空

无论你是 Easysearch 的老用户,还是第一次听说这个名字,只要你对 INFINI Labs 旗下的 Easysearch 产品感兴趣,或者是希望了解 Easysearch,都可以参加这次活动。

详情查看:Easysearch 征文活动

作者:韩旭,亚马逊云技术支持,亚马逊云科技技领云博主,目前专注于云计算开发和大数据领域。

原文:https://blog.csdn.net/weixin_38781498/article/details/140077785

【 INFINI Workshop 北京站】1月18日一起动手实验玩转 Easysearch

活动liaosy 发表了文章 • 0 个评论 • 2480 次浏览 • 2023-12-15 16:22 • 来自相关话题

与 INFINI Labs 的技术专家面对面,第一时间了解极限实验室的发布最新产品和功能特性,通过动手实战,快速掌握最前沿的搜索技术,并用于实际项目中。欢迎大家扫描海报二维码免费报名参加。

活动时间:2024-01-18 13:30~17:30

活动地点:北京市海淀区 Wework 辉煌时代大厦 3 楼 3E 会议室

分享议题

  • Easysearch 总体介绍及搭建实战
  • 基于 INFINI Console 实现跨版本、跨引擎统一管控
  • Elasticsearch -> Easysearch 在线迁移实操

参会提示

  • 请务必自备电脑(Windows 系统环境请提前安装好 Linux 虚拟机)
  • 请提前在 INFINI Labs 官网下载对应平台最新安装包(INFINI Easysearch、INFINI Gateway、INFINI Console)
  • 下载地址:https://www.infinilabs.com/download
  • 如有任何疑问可添加 INFINI Labs 小助手(微信号: INFINI-Labs)进行联系

20231214-095304-qrcode.jpeg

【INFINI Workshop 上海站】7 月 27 日一起动手实验玩转 Easysearch

资讯动态liaosy 发表了文章 • 1 个评论 • 2515 次浏览 • 2023-07-07 16:30 • 来自相关话题

【 INFINI Workshop 上海站】7 月 27 日下午 和 INFINI Labs 的技术专家面对面,第一时间了解极限实验室的发布最新产品和功能特性,通过动手实战,快速掌握最前沿的搜索技术,并用于实际项目中。欢迎大家免费报名参加。 活动时间:2023-07-27 13:30~17:30 活动地点:上海静安区武宁南路1号 WeWork 越商大厦 3 楼 3A 会议室 (注意:活动地址已更新,已报名小伙伴无需重新报名。) ​ 分享议题 • Easysearch 总体介绍及搭建实战 • 基于 INFINI Console 实现跨版本、跨引擎统一管控 • Elasticsearch -> Easysearch 在线迁移实操 参会提示请务必自备电脑(Windows 系统环境请提前安装好 Linux 虚拟机) • 请提前在 INFINI Labs 官网下载对应平台最新安装包(INFINI Easysearch、INFINI Gateway、INFINI Console) • 下载地址:https://www.infinilabs.com/download 名额有限,对 ES 国产化感兴趣的朋友们速度报名(扫描海报中的二维码或者点击 链接 即可免费报名)。   如有任何疑问可添加 INFINI Labs 小助手(微信号: INFINI-Labs)进行联系。
飞书20230719-130323.png

Easysearch Java SDK 2.0.x 使用指南(一)

EasysearchINFINI Labs 小助手 发表了文章 • 0 个评论 • 1305 次浏览 • 2024-12-14 17:50 • 来自相关话题

各位 Easysearch 的小伙伴们,我们前一阵刚把 easysearch-client 更新到了 2.0.2 版本!借此详细介绍下新版客户端的使用。

新版客户端和 1.0 版本相比,完全重构,抛弃了旧版客户端的一些历史包袱,从里到外都焕然一新!不管是刚入门的小白还是经验丰富的老司机,2.0.x 客户端都能让你开发效率蹭蹭往上涨!

到底有啥新东西?

  • 更轻更快: 以前的版本依赖了一堆乱七八糟的东西,现在好了,我们把那些没用的都砍掉了,客户端变得更苗条,性能也杠杠的!
  • 类型安全,告别迷糊: 常用的 Easysearch API 现在都配上了强类型的请求和响应对象,再也不用担心写错参数类型了,代码也更好看了,维护起来也更省心!
  • 同步异步,想咋用咋用: 所有 API 都支持同步和异步两种调用方式,不管是啥场景,都能轻松应对!
  • 构建查询,跟搭积木一样简单: 我们用了流式构建器和函数式编程,构建复杂查询的时候,代码写起来那叫一个流畅,看着也舒服!
  • 和 Jackson 无缝对接: 可以轻松地把你的 Java 类和客户端 API 关联起来,数据转换嗖嗖的快!

快速上手

废话不多说,咱们直接上干货!这部分教你怎么快速安装和使用 easysearch-client 2.0.2 客户端,还会演示一些基本操作。

安装

easysearch-client 2.0.2 已经上传到 Maven 中央仓库了,加到你的项目里超级方便。

最低要求: JDK 8 或者更高版本

依赖管理: 客户端内部用 Jackson 来处理对象映射。

Maven 项目

在你的 pom.xml 文件的 <dependencies> 里面加上这段:

<dependencies>
    <dependency>
        <groupId>com.infinilabs</groupId>
        <artifactId>easysearch-client</artifactId>
        <version>2.0.2</version>
    </dependency>
</dependencies>

Gradle 项目

在你的 build.gradle 文件的 dependencies 里面加上这段:

dependencies {
    implementation 'com.infinilabs:easysearch-client:2.0.2'
}

初始化客户端

下面这段代码演示了怎么初始化一个启用了安全通信加密和 security 的 Easysearch 客户端,看起来有点长,别慌,我们一步一步解释!

 public static EasysearchClient create() throws NoSuchAlgorithmException, KeyStoreException,
        KeyManagementException {

        final HttpHost[] hosts = new HttpHost[]{new HttpHost("localhost", 9200, "https")};

        final SSLContext sslContext = SSLContextBuilder.create()
            .loadTrustMaterial(null, (chains, authType) -> true).build();
        SSLIOSessionStrategy sessionStrategy = new SSLIOSessionStrategy(sslContext, NoopHostnameVerifier.INSTANCE);

        final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
        credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials("username", "passwowd"));

        RestClient restClient = RestClient.builder(hosts)
            .setHttpClientConfigCallback(httpClientBuilder ->
                httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider)
                    .setSSLStrategy(sessionStrategy)
                    .disableAuthCaching()
            ).setRequestConfigCallback(requestConfigCallback ->
            requestConfigCallback.setConnectTimeout(30000).setSocketTimeout(300000))
            .build();

        EasysearchTransport transport = new RestClientTransport(
            restClient, new JacksonJsonpMapper());
        return new EasysearchClient(transport);
    }

这段代码,简单来说,就是:

  1. 连上 Easysearch: 我们要用 HTTPS 连接到本地的 9200 端口。
  2. 搞定证书: 这里为了方便,我们信任了所有证书(注意!生产环境一定要配置好你们自己的证书)。
  3. 填上用户名密码: 这里需要填上你的用户名和密码。
  4. 设置连接参数: 设置了连接超时时间(30 秒)和读取超时时间(300 秒)。
  5. 创建客户端: 最后,我们就创建好了一个 EasysearchClient 实例,可以开始干活了!

举个栗子:批量操作

下面的例子演示了怎么用 bulk API 来批量索引数据:

 public static void bulk() throws Exception {

        String json2 = "{"
            + "    \"@timestamp\": \"2023-01-08T22:50:13.059Z\","
            + "    \"agent\": {"
            + "      \"version\": \"7.3.2\","
            + "      \"type\": \"filebeat\","
            + "      \"ephemeral_id\": \"3ff1f2c8-1f7f-48c2-b560-4272591b8578\","
            + "      \"hostname\": \"ba-0226-msa-fbl-747db69c8d-ngff6\""
            + "    }"
            + "}";

        EasysearchClient client = create();

        BulkRequest.Builder br = new BulkRequest.Builder();
        br.index("test1");
        for (int i = 0; i < 10; i++) {
            BulkOperation.Builder builder = new BulkOperation.Builder();
            IndexOperation.Builder indexBuilder = new IndexOperation.Builder();
            builder.index(indexBuilder.document(JsonData.fromJson(json2)).build());
            br.operations(builder.build());
        }

        for (int i = 0; i < 10; i++) {
            BulkOperation.Builder builder = new BulkOperation.Builder();
            IndexOperation.Builder indexBuilder = new IndexOperation.Builder();
            indexBuilder.document(JsonData.fromJson(json2)).index("test2");
            builder.index(indexBuilder.build());
            br.operations(builder.build());
        }

        for (int i = 0; i < 10; i++) {
            Map<String, Object> map = new HashMap<>();
            map.put("@timestamp", "2023-01-08T22:50:13.059Z");
            map.put("field1", "value1");
            IndexOperation.Builder indexBuilder = new IndexOperation.Builder();
            indexBuilder.document(map).index("test3");
            br.operations(new BulkOperation(indexBuilder.build()));
        }

        BulkResponse bulkResponse = client.bulk(br.build());
        if (bulkResponse.errors()) {
            for (BulkResponseItem item : bulkResponse.items()) {
                System.out.println(item.toString());
            }
        }
        client._transport().close();

    }

这个例子里,我们一口气把数据批量索引到了 test1test2test3 这三个索引里, 并且展示了三种在 bulk API 中构建 IndexOperation 的方式,虽然它们最终都能实现将文档索引到 Easysearch,但在使用场景和灵活性上还是有一些区别的:

这段代码的核心是利用 BulkRequest.Builder 来构建一个批量请求,并通过 br.operations(...) 方法添加多个操作。而每个操作,在这个例子里,都是一个 IndexOperation,也就是索引一个文档。IndexOperation 可以通过 IndexOperation.Builder 来创建。

三种方式的区别主要体现在如何构建 IndexOperation 里的 document 部分,也就是要索引的文档内容。

第一种方式:使用 JsonData.fromJson(json2) 且不指定索引。

特点:
使用 JsonData.fromJson(json2) 将一个 JSON 字符串直接转换成 JsonData 对象作为文档内容。
这里没有在 IndexOperation.Builder 上调用 index() 方法来指定索引名称。由于没有在每个 IndexOperation 中指定索引,这个索引名称将回退到 BulkRequest.Builder 上设置的索引,即 br.index("test1"),所以这 10 个文档都会被索引到 test1。
当你需要将一批相同结构的 JSON 文档索引到同一个索引时,这种方式比较简洁。

第二种方式:使用 JsonData.fromJson(json2) 并指定索引

特点:
同样使用 JsonData.fromJson(json2) 将 JSON 字符串转换成 JsonData 对象。
关键区别在于,这里在 IndexOperation.Builder 上调用了 index("test2"),为每个操作单独指定了索引名称。
这 10 个文档会被索引到 test2,即使 BulkRequest.Builder 上设置了 index("test1") 也没用,因为 IndexOperation 里的设置优先级更高。
当你需要将一批相同结构的 JSON 文档索引到不同的索引时,就需要使用这种方式来分别指定索引。

第三种方式:使用 Map<String, Object> 并指定索引

特点:
使用 Map<String, Object> 来构建文档内容,这种方式更加灵活,可以构建任意结构的文档。
同样在 IndexOperation.Builder 上调用了 index("test3") 指定了索引名称。 使用 new BulkOperation(indexBuilder.build()) 代替之前的 builder.index(indexBuilder.build()), 这是等价的。 这 10 个文档会被索引到 test3。
当你需要索引的文档结构不固定,或者你需要动态构建文档内容时,使用 Map 是最佳选择。例如,你可以根据不同的业务逻辑,往 Map 里添加不同的字段。

总结

这次 easysearch-client 2.0.x Java 客户端的更新真的很给力,强烈建议大家升级体验!相信我,用了新版客户端,你的开发效率绝对会提升一大截!


想要了解更多?

大家有啥问题或者建议,也欢迎随时反馈!

作者:张磊,极限科技(INFINI Labs)搜索引擎研发负责人,对 Elasticsearch 和 Lucene 源码比较熟悉,目前主要负责公司的 Easysearch 产品的研发以及客户服务工作。

极限科技(INFINI Labs)招聘:搜索运维工程师(Elasticsearch/Easysearch)【北京/全职】

求职招聘INFINI Labs 小助手 发表了文章 • 0 个评论 • 5648 次浏览 • 2024-09-28 11:00 • 来自相关话题

20240928-180457.png

我们是国内搜索型数据库产品厂商第一梯队的杰出代表,随着业务的快速发展,现开放岗位:搜索运维工程师( Elasticsearch/Easysearch ),如果有兴趣,请直接拉到文末,扫描二维码或将简历投递至 hello@infini.ltd。

如果您还不了解 极限科技(INFINI Labs)是谁,在做什么,需要什么样的小伙伴,那么请看下文:

我们是谁

INFINI Labs

极限科技,全称极限数据(北京)科技有限公司,是一家专注于实时搜索与数据分析的软件公司。旗下品牌极限实验室(INFINI Labs)致力于打造极致易用的数据探索与分析体验。

极限科技是一支年轻的团队,采用天然分布式的方式来进行远程协作,员工分布在全球各地,希望通过努力成为中国乃至全球企业大数据实时搜索分析产品的首选,为中国技术品牌输出添砖加瓦。

官网:https://infinilabs.cn

我们在做什么

极限科技(INFINI Labs)正在致力于以下几个核心方向:

1、开发近实时搜索引擎 INFINI Easysearch

INFINI Easysearch 是一个分布式的搜索型数据库,实现非结构化数据检索、全文检索、向量检索、地理位置信息查询、组合索引查询、多语种支持、聚合分析等。Easysearch 可以完美替代 Elasticsearch,同时添加和完善多项企业级功能。Easysearch 助您拥有简洁、高效、易用的搜索体验。详情参见:https://infinilabs.cn

2、打造下一代实时搜索引擎 INFINI Pizza

INFINI Pizza 是一个分布式混合搜索数据库系统。我们的使命是充分利用现代硬件和人工智能的潜力,为企业提供量身定制的实时智能搜索体验。我们致力于满足具有挑战性的环境中高并发和高吞吐量的需求,同时提供无缝高效的搜索功能。详情参见:https://pizza.rs

3、积极参与全球开源生态建设

通过开源项目和社区贡献,推动全球开源技术的发展,提升中国在全球开源领域的影响力。

4、提供专业服务

为客户提供包括搜索技术支持、迁移服务、定制解决方案和培训在内的全方位服务。

5、提供国产化搜索解决方案

针对中国市场的特殊需求,提供符合国产化标准的搜索产品和解决方案,帮助客户解决使用 Elasticsearch 时遇到的挑战。

极限科技(INFINI Labs)通过这些努力,旨在成为全球领先的实时搜索和数据分析解决方案提供商。

我们期待有才华、有激情的你加入我们,一起探索数据搜索的未来,共同创造无限可能!

在招岗位介绍

岗位名称

搜索运维工程师(Elasticsearch/Easysearch)

岗位职责

  1. 负责客户现场的 Elasticsearch/Easysearch/OpenSearch 搜索引擎集群的日常维护、监控和优化,确保集群的高可用性和性能稳定;
  2. 协助客户进行搜索引擎集群的部署、配置及版本升级;
  3. 排查和解决 Elasticsearch/Easysearch/OpenSearch 集群中的各种技术问题,及时响应并处理集群异常;
  4. 根据业务需求设计和实施搜索索引的调优、数据迁移和扩展方案;
  5. 负责与客户沟通,提供技术支持及相关培训,确保客户需求得到有效满足;
  6. 制定并实施搜索引擎的备份、恢复和安全策略,保障数据安全;
  7. 与内部研发团队和外部客户进行协作,推动集群性能改进和功能优化。

岗位要求

  1. 全日制本科及以上学历,5 年以上运维工作经验;
  2. 拥有 Elasticsearch/Easysearch/OpenSearch 使用经验,熟悉搜索引擎的原理、架构和相关生态工具(如 Logstash、Kibana 等);
  3. 熟悉 Linux 操作系统的使用及常见性能调优方法;
  4. 熟练掌握 Shell 或 Python 等至少一种脚本语言,能够编写自动化运维脚本;
  5. 具有优秀的问题分析与解决能力,能够快速应对突发情况;
  6. 具备良好的沟通能力和团队合作精神,能够接受 客户驻场工作;
  7. 全职,北京地区,需具备在北京长期工作的条件;

优先考虑

  • 计算机科学、信息技术或相关专业;
  • 具备丰富的大规模分布式系统运维经验;
  • 熟悉 Elasticsearch/Easysearch/OpenSearch 分片、路由、查询优化等高级功能;
  • 拥有 Elastic Certified Engineer 认证;
  • 具备大规模搜索引擎集群设计、扩展和调优经验;
  • 熟悉其他搜索引擎技术(如 Solr、Lucene)者优先 ;
  • 熟悉大数据处理相关技术(比如: Kafka 、Flink 等)者优先。

福利待遇

  • 月薪: 15K - 25K,具体根据能力而定,试用期为 3-6 个月;
  • 福利:五险一金/双休/国内法定假日/带薪年假等;

简历投递

简历投递:hello@infini.ltd(邮件标题请备注姓名+求职岗位+来自搜索客社区)
微信联系:INFINI-Labs(加微请备注求职岗位+来自搜索客社区)

欢迎有兴趣的小伙伴联系或推荐,期待您的加入!

联系我们

【第3期】INFINI Easysearch 免费认证培训开放报名

EasysearchINFINI Labs 小助手 发表了文章 • 0 个评论 • 5537 次浏览 • 2024-09-13 17:43 • 来自相关话题

20240913-144305.png

探索 Easysearch 的无限可能,与 INFINI Labs 共赴搜索技术前沿!

随着数字化转型的加速,搜索技术已成为企业数据洞察的核心。INFINI Labs 作为搜索创新技术的引领者,诚邀所有对 Easysearch 搜索引擎感兴趣的开发者、技术爱好者及合作伙伴,参加我们即将于 2024 年 10 月 19 日至 20 日举办的第 3 期 Easysearch 线上免费培训活动。这不仅是一场知识的盛宴,更是技能提升的加速器,将助您在职业道路上迈出坚实的一步!

活动亮点

  • 系统课程,全面深入:从 Easysearch 的基本概念到环境搭建,再到高级功能的实战应用,INFINI Labs 的技术专家将为您带来全面而深入的讲解,确保每位参与者都能收获满满。
  • 实战导向,解决痛点:课程设计紧贴实际需求,旨在帮助学员掌握 Easysearch 的核心技术,有效解决工作中的搜索需求和技术难题,让理论知识迅速转化为实践能力。
  • 认证证书,助力进阶:后期 INFINI Labs 将推出 Easysearch 认证考试。通过考试的学员将获得官方认证的 Easysearch 证书,为您的职业发展增添强力背书,开启职业生涯的新篇章。

培训时间

2024 年 10 月 19 日至 20 日(周六、周日)共两天,每天具体培训时间:

  • 上午 09:30 ~ 11:30
  • 下午 14:00 ~ 16:00

培训内容概览

第一阶段:初识 Easysearch

  • Easysearch 环境搭建与对比,了解其与 Elasticsearch 的差异;
  • 功能初探:身份验证、数据脱敏、权限控制等,全面掌握 Easysearch 的基础功能;
  • 容灾技术:兼容性验证、跨集群复制等,确保您的搜索服务稳定可靠;

第二阶段:Easysearch 高阶使用

  • 深度探析:性能压测、数据迁移、请求管理等,提升 Easysearch 的使用效率;
  • 高级功能:快照管理、可视化看板、告警功能等,让您的搜索服务更加智能;
  • 生态集成:Filebeat、Logstash、LangChain 等,轻松实现 Easysearch 与其他工具的集成;

参与方式

本次活动完全免费,名额有限,请尽快报名,同时微信扫码添加小助手进群(培训会议地址将在微信群公布),锁定您的学习席位!

扫码或点击 我要报名

报名

👉 立即行动:不要错过这次提升自我、与行业精英共成长的宝贵机会。让我们相聚云端,共同探索 Easysearch 的无限可能,开启技术进阶的新篇章!

参会提示

  • 培训内容涉及动手实践,请务必自备电脑(Windows 系统环境请提前安装好 Linux 虚拟机);
  • 请提前在 INFINI Labs 官网下载对应平台最新安装包(INFINI Easysearch、INFINI Gateway、INFINI Console);
  • 下载地址:https://infinilabs.cn/download

联系我们

如有任何疑问,欢迎通过微信添加 [小助手:INFINI-Labs] 与我们联系。

INFINI Labs 期待与您相约,共赴这场技术盛宴!

关于 Easysearch

Easysearch

Easysearch 是一个分布式的近实时搜索与分析引擎,基于开源的 Apache Lucene 构建。它旨在提供一个自主可控、轻量级的 Elasticsearch 可替代版本,并不断完善和支持更多的企业级功能。与 Elasticsearch 相比,Easysearch 更注重搜索业务场景的优化,同时保持其产品的简洁与易用性。

详情参见:Easysearch 介绍

关于极限科技(INFINI Labs)

INFINI Labs

极限科技,全称极限数据(北京)科技有限公司,是一家专注于实时搜索与数据分析的软件公司。旗下品牌极限实验室(INFINI Labs)致力于打造极致易用的数据探索与分析体验。

极限科技是一支年轻的团队,采用天然分布式的方式来进行远程协作,员工分布在全球各地,希望通过努力成为中国乃至全球企业大数据实时搜索分析产品的首选,为中国技术品牌输出添砖加瓦。

官网:https://infinilabs.cn

如何用 Scrapy 爬取网站数据并在 Easysearch 中进行存储检索分析

EasysearchINFINI Labs 小助手 发表了文章 • 0 个评论 • 5153 次浏览 • 2024-09-13 12:28 • 来自相关话题

做过数据分析和爬虫程序的小伙伴想必对 Scrapy 这个爬虫框架已经很熟悉了。今天给大家介绍下,如何基于 Scrapy 快速编写一个爬虫程序并利用 Easysearch 储存、检索、分析爬取的数据。我们以极限科技的官网 Blog 为数据源(https://infinilabs.cn/blog) ,做下实操演示。

1、安装 scrapy

使用 Scrapy 可以快速构建一个爬虫项目,从目标网站中获取所需的数据,并进行后续的处理和分析。

pip install scrapy

# 新建项目 infini_spiders
scrapy startproject infini_spiders

# 初始化爬虫
cd infini_spiders/spiders
scrapy genspider blog infinilabs.cn

2、爬虫编写

编写一个爬虫文件 blog.py ,它会首先访问 start_urls 指定的地址,将结果发给 parse 函数解析。通过这一步解析,我们得到了每一篇博客的地址。然后我们对每个博客的地址发送请求,将结果发给 parse_blog 函数进行解析,在这里才会真正提取每篇博客的 title、tag、url、date、content 内容。

from typing import Any, Iterable
import scrapy
from bs4 import BeautifulSoup
from scrapy.http import Response

class BlogSpider(scrapy.Spider):
    name = "blog"
    allowed_domains = ["infinilabs.cn"]
    start_urls = ["https://infinilabs.cn/blog/"]

    def parse(self, response):
        links = response.css("div.blogs a")
        yield from response.follow_all(links, self.parse_blog)

    def parse_blog(self, response):
        title = response.xpath('//div[@class="title"]/text()').extract_first()
        tags = response.xpath('//div[@class="tags"]/div[@class="tag"]/text()').extract()
        url = response.url
        author = response.xpath('//div[@class="logo"]/div[@class="name"]//text()').extract_first()
        date = response.xpath('//div[@class="date"]/text()').extract_first()
        all_text = response.xpath('//p//text() | //h3/text() | //h2/text() | //h4/text() | //ol/li//text()').extract()
        content = '\n'.join(all_text)

        yield {
            'title': title,
            'tags': tags,
            'url': url,
            'author': author,
            'date': date,
            'content': content
        }

提取完我们想要的内容后,接下来就要考虑存储了。考虑到要对内容进行检索、分析,接下来我们将内容直接存放到 Easysearch 当中。

3、安装插件

通过安装 ScrapyElasticsearch pipeline 可将 scrapy 爬取的内容存入到 Easysearch 中。

pip install ScrapyElasticSearch

修改 scrapy 自带的配置文件 settings.py ,添加以下内容。

ITEM_PIPELINES = {
    'scrapyelasticsearch.scrapyelasticsearch.ElasticSearchPipeline': 10
}

ELASTICSEARCH_SERVERS = ['http://192.168.56.3:9210']
ELASTICSEARCH_INDEX = 'scrapy'
ELASTICSEARCH_INDEX_DATE_FORMAT = '%Y-%m-%d'
ELASTICSEARCH_TYPE = '_doc'
ELASTICSEARCH_USERNAME = 'admin'
ELASTICSEARCH_PASSWORD = '9423d1d5345ed6d0db19'

ScrapyElasticSearch 会以 bulk 方式写入 Easysearch,每次批量的大小由 scrapyelasticsearch.scrapyelasticsearch.ElasticSearchPipeline 参数控制,大家可自行修改。

在上述配置中,我们会将爬到的数据存放到 scrapy-yyyy-mm-dd 索引中。

4、启动爬虫

在 infini_spiders/spiders 目录下,使用命令启动爬虫。

scrapy crawl blog

blog 就是爬虫的名字,对应到 blog.py 里面的 name 变量。运行完成后,就可以去 Easysearch 里查看数据了,当然我们还是使用 Console 进行查看。

5、查看数据

先查看下索引情况,scrapy 索引已经生成,里面有 129 篇博客。

查看详细内容,确保博客正文已经保存。

到了这一步,我们就能使用 Console 对博客进行搜索、分析了。

6、结语

这次的分享就到这里了。欢迎与我一起交流 ES 的各种问题和解决方案。

关于 Easysearch

INFINI Easysearch 是一个分布式的近实时搜索与分析引擎,核心引擎基于开源的 Apache Lucene。Easysearch 的目标是提供一个轻量级的 Elasticsearch 可替代版本,并继续完善和支持更多的企业级功能。 与 Elasticsearch 相比,Easysearch 更关注在搜索业务场景的优化和继续保持其产品的简洁与易用性。

官网文档:https://infinilabs.cn/docs/latest/easysearch

作者:杨帆
原文:https://infinilabs.cn/blog/2024/use-scrapy-to-crawl-website-data-and-store-search-analyze-in-easysearch/

Easysearch 性能测试方法概要

EasysearchINFINI Labs 小助手 发表了文章 • 0 个评论 • 2785 次浏览 • 2024-08-23 14:47 • 来自相关话题

20240813-e1ba1e73-53ad-4265-8db9-f71e56b5d626.png

INFINI Easysearch

INFINI Easysearch 是一个分布式的近实时搜索与分析引擎,核心引擎基于开源的 Apache Lucene。Easysearch 衍生自基于开源协议 Apache 2.0 的 Elasticsearch 7.10 版本,完善和支持更多的企业级功能,优化搜索业务场景,以保证更佳的数据探索与分析体验。

Easysearch 的主要特点:

  • 兼容 Elasticsearch,业务代码无需改动;可平滑迁移
  • 企业级安全;更稳定可靠
  • 企业级管理后台(多集群统一管理,实现运营标准化、自动化)
  • 信创适配(全面适配国产 CPU/OS/服务器,支持国密算法)

Easysearch 快速体验,请参阅:

Easysearch,地表最强,没有之一!

Loadgen

Loadgen 是 Elasticsearch 专属压测工具,用来对 Easysearch 或者网关进行压力测试。

Loadgen 的特点:

  • 性能强劲
  • 轻量级无依赖
  • 支持模板化参数随机
  • 支持高并发
  • 支持压测端均衡流量控制
  • 支持服务端返回值校验

当前最新版本为 1.26.1-598,下载链接如下:

https://release.infinilabs.com/loadgen/stable/

下载并解压安装包后,得到二进制文件。

查看版本信息。

$ ./loadgen-linux-amd64 -v
   __   ___  _      ___  ___   __    __
  / /  /___\/_\    /   \/ _ \ /__\/\ \ \
 / /  //  ///_\\  / /\ / /_\//_\ /  \/ /
/ /__/ \_//  _  \/ /_// /_\\//__/ /\  /
\____|___/\_/ \_/___,'\____/\__/\_\ \/

[LOADGEN] A http load generator and testing suite.
[LOADGEN] 1.26.1#598, 2024-08-14 04:50:03, 2024-12-31 10:10:10, 00f15fd86834d7ea539f6d66ee608e3915eef0e3
loadgen 1.26.1 598 2024-08-14 04:50:03 +0000 UTC 2024-12-31 10:10:10 +0000 UTC 00f15fd86834d7ea539f6d66ee608e3915eef0e3

Loadgen 测试

Loadgen 使用非常简单,下面演示如何进行查询压测。

  1. 建立索引,根据节点数调节分片数。
curl -X PUT -H "Content-Type: application/json" \
-ku admin:xxx "https://localhost:9200/loadtest" -d'
{
  "settings":{
    "number_of_shards":"3",
    "number_of_replicas":1,
    "translog":{
      "durability":"async"
    }
  }
}'
{"acknowledged":true,"shards_acknowledged":true,"index":"loadtest"}
  1. 创建 loadgen.dsl.shawnyan 配置文件,定义查询
GET loadtest/_search
{"query": {"term": {"id.keyword": {"value": $[[id]]}}}}
  1. 执行压测,-d 表示秒数,-c 表示并发数。
$ ES_ENDPOINT=https://localhost:9200 ES_USERNAME=admin ES_PASSWORD=xxx ./loadgen-linux-amd64 -run loadgen.dsl.shawnyan -d 10 -c 2
   __   ___  _      ___  ___   __    __
  / /  /___\/_\    /   \/ _ \ /__\/\ \ \
 / /  //  ///_\\  / /\ / /_\//_\ /  \/ /
/ /__/ \_//  _  \/ /_// /_\\//__/ /\  /
\____|___/\_/ \_/___,'\____/\__/\_\ \/

[LOADGEN] A http load generator and testing suite.
[LOADGEN] 1.26.1#598, 2024-08-14 04:50:03, 2024-12-31 10:10:10, 00f15fd86834d7ea539f6d66ee608e3915eef0e3
[08-19 16:43:27] [INF] [env.go:179] configuration auto reload enabled
[08-19 16:43:27] [INF] [app.go:285] initializing loadgen, pid: 30792
[08-19 16:43:27] [INF] [app.go:286] using config: /data/es/loadgen.yml
[08-19 16:43:27] [INF] [module.go:155] started plugin: statsd
[08-19 16:43:27] [INF] [module.go:161] all modules are started
[08-19 16:43:27] [INF] [instance.go:78] workspace: /data/es/data/loadgen/nodes/cr1gabqr90cng685o2s0
[08-19 16:43:27] [INF] [app.go:511] loadgen is up and running now.
[08-19 16:43:27] [INF] [main.go:403] loading config: /data/es/loadgen.dsl.shawnyan

21108 requests finished in 9.79061677s, 1.08MB sent, 3.22MB received

[Loadgen Client Metrics]
Requests/sec:           2110.63
Request Traffic/sec:    110.22KB
Total Transfer/sec:     440.00KB
Fastest Request:        680.198µs
Slowest Request:        12.409574ms
Status 200:             21108

[Latency Metrics]
10000 samples of 21108 events
Cumulative:     8.732205871s
HMean:          851.869µs
Avg.:           873.22µs
p50:            839.498µs
p75:            914.298µs
p95:            1.059197ms
p99:            1.327098ms
p999:           4.83579ms
Long 5%:        1.394411ms
Short 5%:       724.226µs
Max:            11.618475ms
Min:            680.198µs
Range:          10.938277ms
StdDev:         289.216µs
Rate/sec.:      2110.63

[Latency Distribution]
       680µs - 1.774ms ------------------------------
     1.774ms - 2.867ms -
     2.867ms - 3.961ms -
     3.961ms - 5.055ms -
     5.055ms - 6.149ms -
     6.149ms - 7.243ms -
     7.243ms - 8.336ms -
      8.336ms - 9.43ms -
     9.43ms - 10.524ms -
   10.524ms - 11.618ms -

[Estimated Server Metrics]
Requests/sec:           2155.94
Avg Req Time:           927.668µs
Transfer/sec:           449.45KB

更多内容请参阅文档:

https://infinilabs.cn/docs/latest/gateway/getting-started/benchmark/

Rally

如果对 Elasticsearch 熟悉的同学,也可尝试使用 Rally 对 Easysearch 进行测试。

Rally 是 Elasticsearch 的基准测试框架。它可以帮助您完成以下任务:

  • 安装 Elasticsearch 集群以进行基准测试
  • 跨 Elasticsearch 版本管理基准数据和规范
  • 运行基准测试并记录结果
  • 通过连接遥测设备来查找性能问题
  • 比较性能结果

安装 Rally。

[root@easysearch /]# pip3 install esrally
Requirement already satisfied: esrally in /usr/local/lib/python3.9/site-packages (2.11.0)
Requirement already satisfied: py-cpuinfo==7.0.0 in /usr/local/lib/python3.9/site-packages (from esrally) (7.0.0)
Requirement already satisfied: elastic-transport==8.4.1 in /usr/local/lib/python3.9/site-packages (from esrally) (8.4.1)
Requirement already satisfied: google-resumable-media[requests]==1.1.0 in /usr/local/lib/python3.9/site-packages (from esrally) (1.1.0)
Requirement already satisfied: urllib3==1.26.18 in /usr/local/lib/python3.9/site-packages (from esrally) (1.26.18)
Requirement already satisfied: google-auth==1.22.1 in /usr/local/lib/python3.9/site-packages (from esrally) (1.22.1)
Requirement already satisfied: thespian==3.10.1 in /usr/local/lib/python3.9/site-packages (from esrally) (3.10.1)
Requirement already satisfied: jsonschema==3.1.1 in /usr/local/lib/python3.9/site-packages (from esrally) (3.1.1)
Requirement already satisfied: markupsafe==2.0.1 in /usr/local/lib64/python3.9/site-packages (from esrally) (2.0.1)
Requirement already satisfied: yappi==1.5.1 in /usr/local/lib64/python3.9/site-packages (from esrally) (1.5.1)
Requirement already satisfied: psutil==5.9.4 in /usr/local/lib64/python3.9/site-packages (from esrally) (5.9.4)
Requirement already satisfied: certifi in /usr/local/lib/python3.9/site-packages (from esrally) (2024.7.4)
Requirement already satisfied: elasticsearch[async]==8.6.1 in /usr/local/lib/python3.9/site-packages (from esrally) (8.6.1)
Requirement already satisfied: ijson==2.6.1 in /usr/local/lib/python3.9/site-packages (from esrally) (2.6.1)
Requirement already satisfied: jinja2==3.1.4 in /usr/local/lib/python3.9/site-packages (from esrally) (3.1.4)
Requirement already satisfied: requests<2.32.0 in /usr/local/lib/python3.9/site-packages (from esrally) (2.31.0)
Requirement already satisfied: tabulate==0.8.9 in /usr/local/lib/python3.9/site-packages (from esrally) (0.8.9)
Requirement already satisfied: zstandard==0.21.0 in /usr/local/lib64/python3.9/site-packages (from esrally) (0.21.0)
Requirement already satisfied: docker==6.0.0 in /usr/local/lib/python3.9/site-packages (from esrally) (6.0.0)
Requirement already satisfied: websocket-client>=0.32.0 in /usr/local/lib/python3.9/site-packages (from docker==6.0.0->esrally) (1.8.0)
Requirement already satisfied: packaging>=14.0 in /usr/lib/python3.9/site-packages (from docker==6.0.0->esrally) (20.9)
Requirement already satisfied: aiohttp<4,>=3 in /usr/local/lib64/python3.9/site-packages (from elasticsearch[async]==8.6.1->esrally) (3.10.4)
Requirement already satisfied: pyasn1-modules>=0.2.1 in /usr/local/lib/python3.9/site-packages (from google-auth==1.22.1->esrally) (0.4.0)
Requirement already satisfied: six>=1.9.0 in /usr/lib/python3.9/site-packages (from google-auth==1.22.1->esrally) (1.15.0)
Requirement already satisfied: rsa<5,>=3.1.4 in /usr/local/lib/python3.9/site-packages (from google-auth==1.22.1->esrally) (4.9)
Requirement already satisfied: setuptools>=40.3.0 in /usr/lib/python3.9/site-packages (from google-auth==1.22.1->esrally) (53.0.0)
Requirement already satisfied: cachetools<5.0,>=2.0.0 in /usr/local/lib/python3.9/site-packages (from google-auth==1.22.1->esrally) (4.2.4)
Requirement already satisfied: google-crc32c<2.0dev,>=1.0 in /usr/local/lib64/python3.9/site-packages (from google-resumable-media[requests]==1.1.0->esrally) (1.5.0)
Requirement already satisfied: attrs>=17.4.0 in /usr/local/lib/python3.9/site-packages (from jsonschema==3.1.1->esrally) (24.2.0)
Requirement already satisfied: importlib-metadata in /usr/local/lib/python3.9/site-packages (from jsonschema==3.1.1->esrally) (8.2.0)
Requirement already satisfied: pyrsistent>=0.14.0 in /usr/local/lib64/python3.9/site-packages (from jsonschema==3.1.1->esrally) (0.20.0)
Requirement already satisfied: yarl<2.0,>=1.0 in /usr/local/lib64/python3.9/site-packages (from aiohttp<4,>=3->elasticsearch[async]==8.6.1->esrally) (1.9.4)
Requirement already satisfied: frozenlist>=1.1.1 in /usr/local/lib64/python3.9/site-packages (from aiohttp<4,>=3->elasticsearch[async]==8.6.1->esrally) (1.4.1)
Requirement already satisfied: aiosignal>=1.1.2 in /usr/local/lib/python3.9/site-packages (from aiohttp<4,>=3->elasticsearch[async]==8.6.1->esrally) (1.3.1)
Requirement already satisfied: async-timeout<5.0,>=4.0 in /usr/local/lib/python3.9/site-packages (from aiohttp<4,>=3->elasticsearch[async]==8.6.1->esrally) (4.0.3)
Requirement already satisfied: aiohappyeyeballs>=2.3.0 in /usr/local/lib/python3.9/site-packages (from aiohttp<4,>=3->elasticsearch[async]==8.6.1->esrally) (2.3.7)
Requirement already satisfied: multidict<7.0,>=4.5 in /usr/local/lib64/python3.9/site-packages (from aiohttp<4,>=3->elasticsearch[async]==8.6.1->esrally) (6.0.5)
Requirement already satisfied: pyparsing>=2.0.2 in /usr/lib/python3.9/site-packages (from packaging>=14.0->docker==6.0.0->esrally) (2.4.7)
Requirement already satisfied: pyasn1<0.7.0,>=0.4.6 in /usr/local/lib/python3.9/site-packages (from pyasn1-modules>=0.2.1->google-auth==1.22.1->esrally) (0.6.0)
Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.9/site-packages (from requests<2.32.0->esrally) (3.7)
Requirement already satisfied: charset-normalizer<4,>=2 in /usr/local/lib64/python3.9/site-packages (from requests<2.32.0->esrally) (3.3.2)
Requirement already satisfied: zipp>=0.5 in /usr/local/lib/python3.9/site-packages (from importlib-metadata->jsonschema==3.1.1->esrally) (3.20.0)
WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv
[root@easysearch /]# esrally --version
esrally 2.11.0
[root@easysearch /]#

关于 Rally 的更多内容,请参阅官方文档:

https://esrally.readthedocs.io/en/stable/

作者:少安事务所
原文:https://mp.weixin.qq.com/s/9eEH38kgsw4i150CJqyxvQ

Easysearch x 《黑神话悟空》有奖征文获奖结果公示

EasysearchINFINI Labs 小助手 发表了文章 • 0 个评论 • 2486 次浏览 • 2024-08-20 13:34 • 来自相关话题

随着《黑神话:悟空》游戏的正式发售,我们 INFINI Labs 组织的 Easysearch 有奖征文大赛也圆满落幕。本次征文活动自启动以来,收到了众多创作者的热情投稿。在此,我们衷心感谢每一位参与活动的作者,是你们的才华和热情让这次征文活动异彩纷呈。

经过专业评审团的认真评选,最终确定了以下获奖作品及作者,现予以公布:

奖项 作者 作品 奖品
一等奖 AWS 加油站 玩转 Easysearch 语法 《黑神话:悟空》数字豪华版一套
二等奖 杨帆 使用 Easysearch 打造企业内部知识问答系统 《黑神话:悟空》数字标准版一套
二等奖 李家兴 从 Elasticsearch 到 Easysearch:国产搜索型数据库的崛起与未来展望 《黑神话:悟空》数字标准版一套
三等奖 严少安 Easysearch,地表最强,没有之一! INFINI Labs 咖啡杯 / 指甲剪套装
三等奖 张磊 Easysearch 新特性:写入限流功能介绍 INFINI Labs 咖啡杯 / 指甲剪套装
三等奖 keep 如何在 MacOS 环境下快速安装部署 Easysearch INFINI Labs 咖啡杯 / 指甲剪套装

恭喜以上获奖作者,你们的作品不仅展现了 Easysearch 的强大功能,也为社区成员提供了宝贵的学习资源。我们将会通过小助手微信联系各位获奖者,安排奖品的发放。

同时,我们也要感谢所有参与本次征文活动的作者,你们的每一篇 Easysearch 投稿都是对社区的一份贡献。我们期待在未来的活动中再次与大家相遇。

请继续关注 INFINI Labs,我们将持续为大家带来更多优质的产品和精彩的活动。再次感谢大家的参与和支持!

如有疑问或想加入 Easysearch 用户交流群请联系我们小助手!

小助手微信

附征文活动原文:

天命人, 你在吗?快拿走你的《黑神话:悟空》游戏,去开启神话冒险!

关于极限科技(INFINI Labs)

INFINI Labs

极限科技,全称极限数据(北京)科技有限公司,是一家专注于实时搜索与数据分析的软件公司。旗下品牌极限实验室(INFINI Labs)致力于打造极致易用的数据探索与分析体验。

极限科技是一支年轻的团队,采用天然分布式的方式来进行远程协作,员工分布在全球各地,希望通过努力成为中国乃至全球企业大数据实时搜索分析产品的首选,为中国技术品牌输出添砖加瓦。

官网:https://infinilabs.cn

如何在 MacOS 环境下快速安装部署 Easysearch

EasysearchINFINI Labs 小助手 发表了文章 • 0 个评论 • 2689 次浏览 • 2024-08-17 14:56 • 来自相关话题

1、什么是 Easysearch

Easysearch 是极限科技研发的一个分布式的近实时搜索与分析引擎,核心引擎基于开源的 Apache Lucene。 同时也是一款具备自主可控的分布式近实时搜索型数据库产品,具备高性能、高可用、弹性伸缩、高安全性等特性,具备支持丰富的个性化搜索及聚合分析能力,可部署在物理机、虚拟机、容器、私有云和公有云,能承载 PB 级别的海量业务数据,为金融核心系统、运营商、制造业和政企业务系统提供安全、稳定、可靠的快速检索和实时数据探索分析能力,可满足不同业务场景的各项复杂需求。

2、前期准备

在安装 Easysearch 之前,确保您的 MacOS 系统符合以下要求:

  • MacOS 操作系统版本应为最新或推荐稳定版本。
  • 确保系统上已安装 Java 运行环境,因为 Easysearch 是基于 Java 开发的。

3、下载 Easysearch

打开浏览器,访问 Easysearch 官方下载页面

图片10.png

找到 MacOS 版本安装包,然后根据自己电脑 CPU 架构选择对应的 Easysearch 安装包。我自己的电脑是 Intel X86 架构,直接选择默认的 amd64,点击下载即可。如果你的电脑是 Apple 的自己的 M 系列芯片,请选择 arm64 版本安装包。

4、安装 Easysearch

打开终端(Terminal)并导航到下载目录,找到 Easysearch 的压缩包,然后双击解压到您选择的目录。或者使用以下命令解压文件:

unzip ./easysearch-1.8.3-265-mac-amd64.zip

5、启动 Easysearch

  1. 执行初始化脚本

由于 Easysearch 默认自带了安全模块,所以在启动之前需要先执行初始化脚本,脚本里会自动帮我们处理好 Easysearch 安全证书、下载基本的 plugins 插件以及初始用户名和密码等,方便省心。

cd ./easysearch-1.8.3-265-mac-amd64 && bin/initialize.sh

图片11.png

执行过程中遇到 [y/N] 询问,输入 y 即可。最后执行完初始化脚本之后,我们可以在输出的 log 日志中看到 easysearch 的访问用户名和密码,需要注意的是,这个用户名和密码需要自己保存好。 如下图所示:

图片12.png

  1. 启动 Easysearch: 使用以下命令启动 Easysearch:
./bin/easysearch

启动后,Easysearch 将在终端中输出运行日志,您可以在此查看启动过程中的详细信息。

6、验证安装

  1. 检查运行状态

打开浏览器,访问 https://localhost:9200,输入上面提到的用户名密码,如果您看到类似以下的 JSON 响应,说明 Easysearch 已成功启动:

图片13.png

  1. 检查集群健康状况

在浏览器中输入 https:/localhost:9200/_cluster/health?pretty 或者在终端中执行以下命令来检查集群的健康状况:

curl -ku admin:4395c2f67208ca5ad7de https://localhost:9200/_cluster/health?pretty"

这将返回集群的详细健康信息,status 为 green 表示集群状态正常。如下图所示:

图片14.png

7、总结

通过上述步骤,可以轻松地在 MacOS 环境下安装和部署 Easysearch,享受它带来的强大功能和便捷体验。Easysearch 作为 Elasticsearch 的替代产品,不仅在功能上保持了高效和稳定,还进一步优化了搜索业务场景,使其更适合企业级应用。现在,您可以进一步配置集群,开始索引数据,并探索 Easysearch 提供的强大搜索和分析功能。建议参考 官网文档,深入了解并实践更多高级功能。

关于 Easysearch 有奖征文活动

黑神话悟空

无论你是 Easysearch 的老用户,还是第一次听说这个名字,只要你对 INFINI Labs 旗下的 Easysearch 产品感兴趣,或者是希望了解 Easysearch,都可以参加这次活动。

详情查看:Easysearch 征文活动

作者:Keep simple
原文:https://blog.csdn.net/weixin_48688147/article/details/141238374

Easysearch、Elasticsearch、Amazon OpenSearch 快照兼容对比

EasysearchINFINI Labs 小助手 发表了文章 • 2 个评论 • 2596 次浏览 • 2024-07-29 11:54 • 来自相关话题

在当今的数据驱动时代,搜索引擎的快照功能在数据保护和灾难恢复中至关重要。本文将对 Easysearch、Elasticsearch 和 Amazon OpenSearch 的快照兼容性进行比较,分析它们在快照创建、恢复、存储格式和跨平台兼容性等方面的特点,帮助大家更好地理解这些搜索引擎的差异,从而选择最适合自己需求的解决方案。

启动集群

Easysearch

服务器一般情况下默认参数都是很低的,而 Easysearch/Elasticsearch 是内存大户,所以就需要进行系统调优。

sysctl -w vm.max_map_count=262144

vm.max_map_count 是一个 Linux 内核参数,用于控制单个进程可以拥有的最大内存映射区域(VMA,Virtual Memory Areas)的数量。内存映射区域是指通过内存映射文件或匿名内存映射创建的虚拟内存区域。

这个参数在一些应用程序中非常重要,尤其是那些需要大量内存映射的应用程序,比如 Elasticsearch。Elasticsearch 使用内存映射文件来索引和搜索数据,这可能需要大量的内存映射区域。如果 vm.max_map_count 设置得太低,Elasticsearch 可能无法正常工作,并会出现错误信息。

调整 vm.max_map_count 参数的一些常见原因:

  1. 支持大型数据集: 应用程序(如 Elasticsearch)在处理大型数据集时可能需要大量内存映射区域。增加 vm.max_map_count 可以确保这些应用程序有足够的内存映射区域来处理数据。

  2. 防止内存错误: 如果 vm.max_map_count 设置得太低,当应用程序尝试创建超过限制的内存映射时,会出现错误,导致应用程序崩溃或无法正常工作。

  3. 优化性能: 适当地设置 vm.max_map_count 可以优化应用程序的性能,确保内存映射操作顺利进行。

检查当前的 vm.max_map_count 值:

sysctl vm.max_map_count

或者查看 /proc/sys/vm/max_map_count 文件:

cat /proc/sys/vm/max_map_count

Elasticsearch 官方建议将 vm.max_map_count 设置为至少 262144。对于其他应用程序。

Easysearch 具体安装步骤见 INFINI Easysearch 尝鲜 Hands on

Amazon OpenSearch

使用 Amazon Web Services 控制台进行创建。

Elasticsearch

使用如下 docker compose 部署一个三节点的 ES 集群:

version: "2.2"
services:
  es01:
    image: docker.elastic.co/elasticsearch/elasticsearch:7.10.2
    container_name: es01
    environment:
      - node.name=es01
      - cluster.name=es-docker-cluster
      - discovery.seed_hosts=es02,es03
      - cluster.initial_master_nodes=es01,es02,es03
      - bootstrap.memory_lock=true
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
    ulimits:
      memlock:
        soft: -1
        hard: -1
    volumes:
      - data01:/usr/share/elasticsearch/data
    ports:
      - 9200:9200
    networks:
      - elastic
  es02:
    image: docker.elastic.co/elasticsearch/elasticsearch:7.10.2
    container_name: es02
    environment:
      - node.name=es02
      - cluster.name=es-docker-cluster
      - discovery.seed_hosts=es01,es03
      - cluster.initial_master_nodes=es01,es02,es03
      - bootstrap.memory_lock=true
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
    ulimits:
      memlock:
        soft: -1
        hard: -1
    volumes:
      - data02:/usr/share/elasticsearch/data
    networks:
      - elastic
  es03:
    image: docker.elastic.co/elasticsearch/elasticsearch:7.10.2
    container_name: es03
    environment:
      - node.name=es03
      - cluster.name=es-docker-cluster
      - discovery.seed_hosts=es01,es02
      - cluster.initial_master_nodes=es01,es02,es03
      - bootstrap.memory_lock=true
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
    ulimits:
      memlock:
        soft: -1
        hard: -1
    volumes:
      - data03:/usr/share/elasticsearch/data
    networks:
      - elastic

volumes:
  data01:
    driver: local
  data02:
    driver: local
  data03:
    driver: local

networks:
  elastic:
    driver: bridge

由于这个 docker compose 没有关于 kibana 的配置,所以我们还是用 Console 添加原生的 Elasticsearch 集群!

集群信息

快照还原的步骤

快照前的准备

插件安装

本次测试选择把索引快照备份到 Amazon S3,所以需要使用 S3 repository plugin,这个插件添加了对使用 Amazon S3 作为快照/恢复存储库的支持。

Easysearch 和 OpenSearch 集群自带了这个插件,所以无需额外安装。

对于自己部署的三节点 Elasticsearch 则需要进入每一个节点运行安装命令然后再重启集群,建议使用自动化运维工具来做这步,安装命令如下:

sudo bin/elasticsearch-plugin install repository-s3

如果不再需要这个插件,可以这样删除。

sudo bin/elasticsearch-plugin remove repository-s3

由于需要和 Amazon Web Services 打交道,所以我们需要设置 IAM 凭证,这个插件可以从 EC2 IAM instance profile,ECS task role 以及 EKS 的 Service account 读取相应的凭证。

对于托管的 Amazon OpenSearch 来说,我们无法在托管的 EC2 上绑定我们的凭证,所以需要新建一个 OpenSearchSnapshotRole,然后通过当前的用户把这个角色传递给服务,也就是我们说的 IAM:PassRole。

创建 OpenSearchSnapshotRole,策略如下:

{
  "Version": "2012-10-17",
  "Statement": [{
      "Action": [
        "s3:ListBucket"
      ],
      "Effect": "Allow",
      "Resource": [
        "arn:aws:s3:::bucket-name"
      ]
    },
    {
      "Action": [
        "s3:GetObject",
        "s3:PutObject",
        "s3:DeleteObject"
      ],
      "Effect": "Allow",
      "Resource": [
        "arn:aws:s3:::bucket-name/*"
      ]
    }
  ]
}

信任关系如下:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "es.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

然后在我们的 IAM user 上加上 PassRole 的权限,这样我们就可以把 OpenSearchSnapshotRole 传递给 OpenSearch 集群。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "iam:PassRole",
      "Resource": "arn:aws:iam::123456789012:role/OpenSearchSnapshotRole"
    }
  ]
}

注册存储库

在源集群执行注册

PUT /_snapshot/snapshot-repo-name
{
  "type": "s3",
  "settings": {
    "bucket": "<bucket-name>",
    "base_path": "<bucket-prefix>",

在目标集群同样执行这个语句,为了防止覆盖源集群存储库的数据,将 "readonly": true 添加到"settings" PUT 请求中,这样就只有一个集群具有对存储库的写入权限。

PUT /_snapshot/snapshot-repo-name
{
  "type": "s3",
  "settings": {
    "bucket": "<bucket-name>",
    "base_path": "<bucket-prefix>",
    "readonly": true,

对于 OpenSearch 来说,还需要执行 passrole,所以还需要添加role_arn这个字段,由于 IAM:PassRole 需要对 HTTP 请求做 signV4 日签名,所以这部常常使用 Postman 来完成。把角色传递过去之后,接下来的快照还原操作就可以在 OpenSearch Dashboard 中进行操作了。

需要注意的是,需要在 auth 这里输入 AccessKey,SecretKey,AWS Region,Service Name(es)来做 SignV4 的签名。

请求体如下:

{
  "type": "s3",
  "settings": {
    "bucket": "<bucket-name>",
    "base_path": "<bucket-prefix>",
    "readonly": true,
    "role_arn": "arn:aws:iam::123456789012:role/OpenSearchSnapshotRole"
  }
}
  • 查看所有注册的存储库
    • GET _snapshot:这个命令返回所有已注册的快照存储库列表及其基本信息。
GET _snapshot
{
  "es_repository": {
    "type": "s3",
    "settings": {
      "bucket": "your-s3-bucket-name",
      "region": "your-s3-bucket-region"
    }
  }
}
  • 查看特定存储库的详细信息GET _snapshot/es_repository:这个命令返回名为es_repository的存储库的详细配置信息,包括存储桶名称、区域和其他设置。
GET _snapshot/es_repository
{
  "es_repository": {
    "type": "s3",
    "settings": {
      "bucket": "your-s3-bucket-name",
      "region": "your-s3-bucket-region",
      "access_key": "your-access-key",
      "secret_key": "your-secret-key"
    }
  }
}
  • 查看特定存储库中的快照GET _cat/snapshots/es_repository?v:这个命令返回es_repository存储库中的所有快照及其详细信息,包括快照 ID、状态、开始时间、结束时间、持续时间、包含的索引数量、成功和失败的分片数量等。
GET _cat/snapshots/es_repository?v
id                     status start_epoch start_time end_epoch end_time duration indices successful_shards failed_shards total_shards
snapshot_1             SUCCESS 1628884800 08:00:00   1628888400 09:00:00 1h       3       10                0             10
snapshot_2             SUCCESS 1628971200 08:00:00   1628974800 09:00:00 1h       3       10                0             10

创建索引快照

# PUT _snapshot/my_repository/<my_snapshot_{now/d}>
PUT _snapshot/my_repository/my_snapshot
{
  "indices": "my-index,logs-my_app-default",
}

根据快照的大小不同,完成快照可能需要一些时间。默认情况下,create snapshot API 只会异步启动快照过程,该过程在后台运行。要更改为同步调用,可以将 wait_for_completion 查询参数设置为 true

PUT _snapshot/my_repository/my_snapshot?wait_for_completion=true

另外还可以使用 clone snapshot API 克隆现有的快照。要监控当前正在运行的快照,可以使用带有 _current 请求路径参数的 get snapshot API。

GET _snapshot/my_repository/_current

如果要获取参与当前运行快照的每个分片的完整详细信息,可以使用 get snapshot status API。

GET _snapshot/_status

成功创建快照之后,就可以在 S3 上看到备份的数据块文件,这个是正确的快照层级结构:

需要注意的是, "base_path": ""这里最好不要加/,虽然不影响同集群迁移,这个会为我们在不同厂商的搜索引擎中迁移遇到问题,可能是这样的,所以需要注意。

所以在 Open Search 中还原 Elasticsearch 就遇到了这个问题:

{
  "error": {
    "root_cause": [
      {
        "type": "snapshot_missing_exception",
        "reason": "[easy_repository:2/-jOQ0oucQDGF3hJMNz-vKQ] is missing"
      }
    ],
    "type": "snapshot_missing_exception",
    "reason": "[easy_repository:2/-jOQ0oucQDGF3hJMNz-vKQ] is missing",
    "caused_by": {
      "type": "no_such_file_exception",
      "reason": "Blob object [11111/indices/7fv2zAi4Rt203JfsczUrBg/meta-YGnzxZABRBxW-2vqcmci.dat] not found: The specified key does not exist. (Service: S3, Status Code: 404, Request ID: R71DDHX4XXM0434T, Extended Request ID: d9M/HWvPvMFdPhB6KX+wYCW3ZFqeFo9EoscWPkulOXWa+TnovAE5PlemtuVzKXjlC+rrgskXAus=)"
    }
  },
  "status": 404
}

恢复索引快照

POST _snapshot/my_repository/my_snapshot_2099.05.06/_restore
{
  "indices": "my-index,logs-my_app-default",
}

各个集群的还原

  1. Elasticsearch 7.10.2 的快照可以还原到 Easysearch 和 Amazon OpenSearch

  2. 从 Easysearch 1.8.2 还原到 Elasticsearch 7.10.2 报错如下:
{
  "error": {
    "root_cause": [
      {
        "type": "snapshot_restore_exception",
        "reason": "[s3_repository:1/a2qV4NYIReqvgW6BX_nxxw] cannot restore index [my_indexs] because it cannot be upgraded"
      }
    ],
    "type": "snapshot_restore_exception",
    "reason": "[s3_repository:1/a2qV4NYIReqvgW6BX_nxxw] cannot restore index [my_indexs] because it cannot be upgraded",
    "caused_by": {
      "type": "illegal_state_exception",
      "reason": "The index [[my_indexs/ALlTCIr0RJqtP06ouQmf0g]] was created with version [1.8.2] but the minimum compatible version is [6.0.0-beta1]. It should be re-indexed in Elasticsearch 6.x before upgrading to 7.10.2."
    }
  },
  "status": 500
}
  1. 从 Amazon OpenSearch 2.1.3 还原到 Elasticsearch 7.10.2 报错如下(无论是否开启兼容模式):
{
  "error": {
    "root_cause": [
      {
        "type": "snapshot_restore_exception",
        "reason": "[aos:2/D-oyYSscSdCbZFcmPZa_yg] the snapshot was created with Elasticsearch version [36.34.78-beta2] which is higher than the version of this node [7.10.2]"
      }
    ],
    "type": "snapshot_restore_exception",
    "reason": "[aos:2/D-oyYSscSdCbZFcmPZa_yg] the snapshot was created with Elasticsearch version [36.34.78-beta2] which is higher than the version of this node [7.10.2]"
  },
  "status": 500
}
  1. 从 Easysearch 1.8.2 还原到 Amazon OpenSearch2.13 报错如下(无论是否开启兼容模式):
{
  "error": {
    "root_cause": [
      {
        "type": "snapshot_restore_exception",
        "reason": "[easy_repository:2/LE18AWHlRJu9rpz9BJatUQ] cannot restore index [my_indexs] because it cannot be upgraded"
      }
    ],
    "type": "snapshot_restore_exception",
    "reason": "[easy_repository:2/LE18AWHlRJu9rpz9BJatUQ] cannot restore index [my_indexs] because it cannot be upgraded",
    "caused_by": {
      "type": "illegal_state_exception",
      "reason": "The index [[my_indexs/VHOo7yfDTRa48uhQvquFzQ]] was created with version [1.8.2] but the minimum compatible version is OpenSearch 1.0.0 (or Elasticsearch 7.0.0). It should be re-indexed in OpenSearch 1.x (or Elasticsearch 7.x) before upgrading to 2.13.0."
    }
  },
  "status": 500
}
  1. Amazon OpenSearch 还原到 Easysearch 同样失败
{
  "error": {
    "root_cause": [
      {
        "type": "snapshot_restore_exception",
        "reason": "[aoss:2/D-oyYSscSdCbZFcmPZa_yg] cannot restore index [aos] because it cannot be upgraded"
      }
    ],
    "type": "snapshot_restore_exception",
    "reason": "[aoss:2/D-oyYSscSdCbZFcmPZa_yg] cannot restore index [aos] because it cannot be upgraded",
    "caused_by": {
      "type": "illegal_state_exception",
      "reason": "The index [[aos/864WjTAXQCaxJ829V5ktaw]] was created with version [36.34.78-beta2] but the minimum compatible version is [6.0.0]. It should be re-indexed in Easysearch 6.x before upgrading to 1.8.2."
    }
  },
  "status": 500
}
  1. Elasticsearch 8.14.3 迁移到 Amazon OpenSearch 或者 Elasticsearch 都是有这个报错:
{
  "error": {
    "root_cause": [
      {
        "type": "parsing_exception",
        "reason": "Failed to parse object: unknown field [uuid] found",
        "line": 1,
        "col": 25
      }
    ],
    "type": "repository_exception",
    "reason": "[snap] Unexpected exception when loading repository data",
    "caused_by": {
      "type": "parsing_exception",
      "reason": "Failed to parse object: unknown field [uuid] found",
      "line": 1,
      "col": 25
    }
  },
  "status": 500
}

这是由于 Elasticsearch 8 在创建快照的时候会默认加上一个 UUID 的字段,所以我们低版本的 Easysearch、Amazon OpenSearch 中会找不到这个字段,在执行GET _cat/snapshots/snap?v的时候就报错,及时在注册存储库的时候显示加上 UUID 的字段也无事无补。

{
  "snapshot-repo-name": {
    "type": "s3",
    "uuid": "qlJ0uqErRmW6aww2Fyt4Fg",
    "settings": {
    "bucket": "<bucket-name>",
    "base_path": "<bucket-prefix>",
    }
  },

以下是兼容性对比,每行第一列代表源集群,第一行代表目标集群:

快照兼容对比 Easysearch 1.8.2 Elasticsearch 7.10.2 OpenSearch 2.13
Easysearch 1.8.2 兼容 不兼容 不兼容
Elasticsearch 7.10.2 兼容 兼容 兼容
OpenSearch 2.13 不兼容 不兼容 兼容

Elasticsearch 的兼容列表官方的列表如下:

参考文献

  1. 开始使用 Elastic Stack 和 Docker Compose:第 1 部分
    https://www.elastic.co/cn/blog/getting-started-with-the-elastic-stack-and-docker-compose

  2. Docker Compose 部署多节点 Elasticsearch
    https://www.elastic.co/guide/en/elasticsearch/reference/7.10/docker.html#docker-compose-file

  3. repository-s3 教程
    https://www.elastic.co/guide/en/elasticsearch/reference/8.14/repository-s3.html
    https://www.elastic.co/guide/en/elasticsearch/plugins/7.10/repository-s3.html

  4. snapshot-restore
    https://www.elastic.co/guide/en/elasticsearch/reference/7.10/snapshot-restore.html

  5. 在亚马逊 OpenSearch 服务中创建索引快照
    https://docs.amazonaws.cn/zh_cn/opensearch-service/latest/developerguide/managedomains-snapshots.html#managedomains-snapshot-restore

  6. 教程:迁移至 Amazon OpenSearch Service
    https://docs.amazonaws.cn/zh_cn/opensearch-service/latest/developerguide/migration.html

关于 Easysearch 有奖征文活动

黑神话悟空

无论你是 Easysearch 的老用户,还是第一次听说这个名字,只要你对 INFINI Labs 旗下的 Easysearch 产品感兴趣,或者是希望了解 Easysearch,都可以参加这次活动。

详情查看:Easysearch 征文活动

作者:韩旭,亚马逊云技术支持,亚马逊云科技技领云博主,目前专注于云计算开发和大数据领域。

原文:https://infinilabs.cn/blog/2024/comparison-of-snapshot-compatibility-between-easysearch-elasticsearch-and-opensearch/

使用 Easysearch 打造企业内部知识问答系统

EasysearchINFINI Labs 小助手 发表了文章 • 0 个评论 • 2461 次浏览 • 2024-07-29 11:08 • 来自相关话题

大家可能都有这样的经历,刚入职一家企业时,同事往往会给你分享一些文档资料,有可能是产品信息、规章制度等等。这些文档有的过于冗长,很难第一时间找到想要的内容。有的已经有了新版本,但员工使用的还是老版本。

基于这种背景,我们可以利用 Easysearch 加 LLM 实现一个内部知识的 QA 问答系统。这个系统将利用 LangChain 框架调用本地部署的大模型和 Easysearch,实现理解员工的提问,并基于最新的文档,给出精准答案。

开发框架

整个框架分为四个部分:

  • 数据源:数据可以有很多种,可以是非结构化的,比如 PDF、docx、txt 等。也可以是结构化的数据,甚至代码也行。在本次示例中,我们使用 PDF 的非结构化数据。
  • 大模型应用:应用与大模型交互,生成我们需要的答案。
  • 大模型:系统执行相关任务需要用到的大模型,可以有多个。
  • Q&A 场景:基于大模型为引擎的 QA 场景,使用 web 框架,构建一个交互界面。

数据准备

本次我们使用的资料是 "INFINI 产品安装手册.pdf" ,文档部分内容展示如下:

首先我们使用 LangChain 的 document_loaders 来加载文件。document_loaders 集成了数百种数据源格式,可以很方便的加载数据。我们的数据的 pdf 格式的,导入 PyPDFLoader 类来进行处理。代码如下:

import os

# 导入 Document Loaders
from langchain_community.document_loaders import PyPDFLoader

# Load Pdf
base_dir = '.\\easysearch' # 文档的存放目录
docs = []
for file in os.listdir(base_dir):
    file_path = os.path.join(base_dir, file)
    if file.endswith('.pdf'):
        loader = PyPDFLoader(file_path)
        documents.extend(loader.load())

上面的代码将 pdf 文件的内容存储在 docs 这个列表中,以便后续进行处理。

文本分割

一个文件的文本内容可能很大,无法适应许多模型的上下文窗口,也不利于检索和存储。因此,通常我们会将文本内容分割成更小的块,这将帮助我们在运行时只检索文档中最相关的部分。LangChain 提供了工具来进行处理文本分割,非常方便。 我们将把文档分割成 1000 个字符的块,每个块之间有 200 个重叠字符。这种重叠有助于减少将语句与相关的重要上下文分离的可能性。

# 2.将Documents切分成块
from langchain.text_splitter import RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=20)
chunked_documents = text_splitter.split_documents(docs)

上面的代码将 docs 的内容按 1000 字符大小进行切分,存储在 chunked_documents 中,以便后续进行处理。
注意,实际运行中,切分及重叠的大小,都会影响应用效果,需自行调试。

向量库 Easysearch

接下来,我们将这些文本块转换成向量的形式,并存储在一个向量数据库中。在本示例中,我们使用 mxbai-embed-large 模型来生成向量,然后将向量和原始内容存入 easysearch 。

本地部署模型,我使用的是 ollama ,大家可以使用自己喜欢的工具。

# 3. 定义embedding模型
from langchain_community.embeddings import OllamaEmbeddings
ollama_emb = OllamaEmbeddings(
    model="mxbai-embed-large",
)

# 4. 定义 easysearch 集群的信息,以及存放向量的索引名称 infini
from langchain_community.vectorstores import EcloudESVectorStore
ES_URL = "https://192.168.56.3:9200"
USER = "admin"
PASSWORD = "e5ac1b537785ae27c187"
indexname = "infini"

docsearch = EcloudESVectorStore.from_documents(
    chunked_documents,
    ollama_emb,
    es_url=ES_URL,
    user=USER,
    password=PASSWORD,
    index_name=indexname,
    verify_certs=False,
)

通过上面的步骤,我们成功将文本块转换成了向量,并存入到了 easysearch 集群的 infini 索引中。 我们看看 infini 索引内容是怎样的 text 字段存放了文本块的原始内容,vector 字段存放着对应的向量表示。

检索及生成答案

在这一步,我们会定义一个生成式大模型。然后创建一个 RetrievalQA 链,它是一个检索式问答模型,用于生成问题的答案。
在 RetrievalQA 链中有下面两大重要组成部分。

  • LLM 是大模型,负责回答问题。
  • retriever(vectorstore.as_retriever())负责根据用户的问题检索相关的信息。先是找最近似的“向量块”,再把”向量块“对应的“文档块”作为知识信息,和问题一起传递进入大模型。之所以要先检索,是因为从互联网信息训练而来的大模型不可能拥有一个私营企业的内部知识。
# 5. Retrieval 准备模型和Retrieval链
import logging
# MultiQueryRetriever工具
from langchain.retrievers.multi_query import MultiQueryRetriever
# RetrievalQA链
from langchain.chains import RetrievalQA

# # 设置Logging
logging.basicConfig()
logging.getLogger('langchain.retrievers.multi_query').setLevel(logging.INFO)

# # 实例化一个大模型工具
from langchain_community.chat_models import ChatOllama
llm = ChatOllama(model="qwen2:latest")

from langchain.prompts import PromptTemplate
my_template = PromptTemplate(
    input_variables=["question"],
    template="""You are an AI language model assistant. Your task is
    to generate 3 different versions of the given user
    question in Chinese to retrieve relevant documents from a vector  database.
    By generating multiple perspectives on the user question,
    your goal is to help the user overcome some of the limitations
    of distance-based similarity search. Provide these alternative
    questions separated by newlines. Original question: {question}""",
)

# # 实例化一个MultiQueryRetriever
retriever_from_llm = MultiQueryRetriever.from_llm(retriever=docsearch.as_retriever(), llm=llm,prompt=my_template,include_original=True)

# # 实例化一个RetrievalQA链
qa_chain = RetrievalQA.from_chain_type(llm,retriever=retriever_from_llm)

这里我们使用 ollama 在本地部署一个 qwen2 大模型,负责问题改写和生成答案。

启动 qwen2 大模型:ollama run qwen2

我们获取到用户问题后,先通过 MultiQueryRetriever 类调用大模型 qwen2 进行改写,生成 3 个同样语义的问题,然后再调用 easyearch 进行向量检索,搜索相关内容。

最后把所有相关内容,合并、去重后,与原始问题一起提交给大模型 qwen2,进行答案生成。

虽然这里使用的是向量检索,但实际上我们可以同时使用全文检索和向量检索。这也是使用 easysearch 作为检索库的优势之一。

前端展示

这一步我们创建一个 Flask 应用(需要安装 Flask 包)来接收用户的问题,并生成相应的答案,最后通过 index.html 对答案进行渲染和呈现。

在这个步骤中,我们使用了之前创建的 RetrievalQA 链来获取相关的文档和生成答案。然后,将这些信息返回给用户,显示在网页上。

# 6. Q&A系统的UI实现
from flask import Flask, request, render_template
app = Flask(__name__) # Flask APP

@app.route('/', methods=['GET', 'POST'])
def home():
    if request.method == 'POST':

        # 接收用户输入作为问题
        question = request.form.get('question')

        # RetrievalQA链 - 读入问题,生成答案
        result = qa_chain({"query": question})

        # 把大模型的回答结果返回网页进行渲染
        return render_template('index.html', result=result)

    return render_template('index.html')

if __name__ == "__main__":
    app.run(host='0.0.0.0',debug=True,port=5000)

效果演示

我们模仿用户进行提问。 Q&A 系统进行回答,回答速度取决于本地的计算资源。 内容校验,在原始文档内用 ctrl+F 搜索关键字 LOGGING_ES_ENDPOINT 得到如下内容。 嗯,回答的还不错,达到预期目的。如果还有其他要求,可修改 my_template 中的提示词或者替换成别的大模型也是可以的。

小结

通过这次示例,我们演示了如何基于 LangChain 和 easysearch 以及大模型,快速开发出一个内部知识问答系统。怎么样,是不是觉得整个流程特别简单易懂?

如有任何问题,请随时联系我,期待与您交流!

关于 Easysearch 有奖征文活动

黑神话悟空

无论你是 Easysearch 的老用户,还是第一次听说这个名字,只要你对 INFINI Labs 旗下的 Easysearch 产品感兴趣,或者是希望了解 Easysearch,都可以参加这次活动。

详情查看:Easysearch 征文活动

【第1期】2024 搜索客 Meetup | Easysearch 结合大模型实现 RAG

活动searchkit 发表了文章 • 0 个评论 • 2944 次浏览 • 2024-07-25 16:57 • 来自相关话题

2024 搜索客社区 Meetup 首期线上活动正式启动,本次活动由 搜索客社区、极限科技(INFINI Labs)联合举办,诚邀广大搜索技术开发者和爱好者参加交流学习。

活动时间:2024 年 7 月 31 日 19:00-20:00 (周三)
活动形式:微信视频号(极限实验室)直播
报名方式:关注或扫码海报中的二维码进行预约

活动海报

活动简介

在这个人工智能飞速发展的时代,ChatGPT 和 GPT-4 的出现无疑为人类带来了前所未有的震撼。我们不禁思考:通用人工智能的奇点是否真的即将来临?而最前沿的 AI 技术与最实用的落地应用之间的距离,又该如何缩短?

为了深入探讨这些问题,我们特别邀请到了极限科技(INFINI Labs)高级解决方案架构师、《老杨玩搜索》栏目 B 站 UP 主——杨帆先生,为我们带来一场主题为 “Easysearch 结合大模型实现 RAG” 的精彩演讲。

嘉宾介绍

杨帆,拥有十余年金融行业服务工作经验,熟悉 Linux、数据库、网络等领域。目前主要从事 Easysearch、Elasticsearch 等搜索引擎的技术支持工作,服务国内私有化部署的客户。他的丰富经验和深刻见解,将为我们揭开 AI 技术与实际应用之间的神秘面纱。

演讲主题

《Easysearch 结合大模型实现 RAG》

主题摘要

在本次演讲中,杨帆将跟大家分享和探讨以下几个方面:

  1. LangChain 简介:LangChain 的作用是什么?它由哪些组件构成,优势是什么。
  2. RAG 的背景及其局限性:RAG 出现以前的我们是如何获取信息的,RAG 解决了什么问题?它就是最终的答案了吗?
  3. LangChain 下的 RAG 工作流:在 LangChain 的框架下,实现 RAG 的步骤是怎样的。
  4. RAG Demo:使用 ollama 部署本地模型,利用 LangChain 集成 Easysearch 和 LLM , 开发 QA 问答系统

活动亮点

  • 前沿技术分享: 深入了解当前 AI 领域的最新动态和发展趋势。
  • 实战经验交流: 学习如何在实际工作中应用这些先进技术。
  • 互动问答环节: 与演讲嘉宾直接对话,解答你的疑惑。

参与有奖

本次直播活动中设置了随机抽奖环节,奖品为 INFINI Labs 周边纪念品,包括 T 恤、鸭舌帽、咖啡杯、指甲刀套件等等(图片仅供参考,款式、颜色与尺码随机)。

抽奖礼品

活动交流

活动交流群二维码 7 天内(8 月 1 日前)有效,如过期请添加小助手微信拉群。活动最新消息也会在群内及时同步,欢迎大家参与,记得先预约,精彩内容不错过!

活动交流

讲师招募

讲师招募

搜索客社区 Meetup 讲师持续招募中...

这是一个由搜索客社区精心组织策划的线下线上技术交流活动,我们诚挚邀请各位技术大咖、行业精英踊跃提交演讲议题。Meetup 活动将聚焦 AI 与搜索领域的最新动态,以及数据实时搜索分析、向量检索、技术实践与案例分析、日志分析、安全等领域的深度探讨。详情参见:http://cfp.searchkit.cn 。我们热切期待您的精彩分享!

关于 搜索客(SearchKit)社区

搜索客社区由 Elasticsearch 中文社区进行全新的品牌升级,以新的 Slogan:“搜索人自己的社区” 为宣言。汇集搜索领域最新动态、精选干货文章、精华讨论、文档资料、翻译与版本发布等,为广大搜索领域从业者提供更为丰富便捷的学习和交流平台。社区官网:https://searchkit.cn

Easysearch 有奖征文活动推荐

黑神话悟空

无论你是 Easysearch 的老用户,还是第一次听说这个名字,只要你对 INFINI Labs 旗下的 Easysearch 产品感兴趣,或者是希望了解 Easysearch,都可以参加这次活动。

详情查看:Easysearch 征文活动

Easysearch 新特性:写入限流功能介绍

EasysearchINFINI Labs 小助手 发表了文章 • 0 个评论 • 2726 次浏览 • 2024-07-17 14:52 • 来自相关话题

背景

在 Easysearch 的各种使用场景中,高写入吞吐量的场景占了很大一部分,由此也带来了一些使用上的问题,很多用户由于使用经验不足,对集群的写入压测进行的不够充分,不能很好的规划集群的写入量。

导致经常发生以下问题:

  • 写入吞吐量过大对内存影响巨大,引发节点 OOM,节点掉线问题。
  • 对 CPU 和内存的占用严重影响了其他的查询业务的响应。
  • 以及磁盘 IO 负载增加,挤占集群的网络带宽等问题。

之前就有某金融保险类客户遇到了因业务端写入量突然猛增导致数据节点不停的 Full GC,进而掉入了不停的掉线,上线,又掉线的恶性循环中。当时只能建议用户增加一个类似“挡板”的服务,在数据进入到集群之前进行拦截,对客户端写入进行干预限流:

这样做虽然有效,但是也增加了整个系统的部署复杂性,提高了运维成本。

根据客户的实际场景,Easysearch 从 1.8.0 版本开始引入了节点和 Shard 级别的限流功能,不用依赖第三方就可以限制写入压力,并在 1.8.2 版本增加了索引级别的写入限流。 注意:所有写入限流都是针对各数据节点的 Primary Shard 写入进行限流的,算上副本的话吞吐量要乘以 2。

限流示意图:

下面是限流前后相同数据节点的吞吐量和 CPU 对比:

测试环境:

ip       name   http          port version role master
10.0.0.3 node-3 10.0.0.3:9209 9303 1.8.0   dimr -
10.0.0.3 node-4 10.0.0.3:9210 9304 1.8.0   im   -
10.0.0.3 node-2 10.0.0.3:9208 9302 1.8.0   dimr -
10.0.0.3 node-1 10.0.0.3:9207 9301 1.8.0   dimr *

测试索引配置:

PUT test_0
{
  "settings": {
    "number_of_replicas": 1,
    "number_of_shards": 3
  }
}

压测工具:采用极限科技的 INFINI Loadgen 压测,这款压测工具使用简单,可以方便对任何支持 Rest 接口的库进行压测。

压测命令:

 ./loadgen-linux-amd64 -d 180 -c 10 -config loadgen-easy-1.8.yml

压测 180 秒,10 个并发,每个 bulk 请求 5000 条。

节点级别限流

通过 INFINI Console 监控指标可以看到,限流之前的某个数据节点,CPU 占用 10%,每秒写入 40000 条左右:

在 Cluster Settings 里配置,启用节点级别限流,限制每个节点的每秒最大写入 10000 条,并在默认的 1 秒间隔内进行重试,超过默认间隔后直接拒绝。

PUT _cluster/settings
{
  "transient": {
    "cluster.throttle.node.write": true,
    "cluster.throttle.node.write.max_requests": 10000,
    "cluster.throttle.node.write.action": "retry"
  }
}

限流后,CPU 占用降低了约 50%,算上副本一共 20000 条每秒:

Shard 级别限流

设置每个分片最大写入条数为 2000 条每秒

PUT _cluster/settings
{
  "transient": {
    "cluster.throttle.shard.write": true,
    "cluster.throttle.shard.write.max_requests": 2000,
    "cluster.throttle.shard.write.action": "retry"
  }
}

集群级别的监控,同样是只针对主 Shard。

从 Console 的监控指标可以看出,索引 test_0 的 Primary indexing 维持在 6000 左右,正好是 3 个主分片限制的 2000 的写入之和。

再看下数据节点监控,Total Shards 表示主分片和副本分片的写入总和即 4000,单看主分片的话,正好是 2000.

索引级别限流

有时,集群中可能某个索引的写入吞吐过大而影响了其他业务,也可以针对特定的索引配置写入限制。 可以在索引的 Settings 里设置当前索引每秒写入最大条数为 6000:

PUT test_0
{
  "settings": {
    "number_of_replicas": 1,
    "number_of_shards": 3,
    "index.throttle.write.max_requests": 6000,
    "index.throttle.write.action": "retry",
    "index.throttle.write.enable": true
  }
}

下图索引的 Primary indexing 在 6000 左右,表示索引的所有主分片的写入速度限制在了 6000。

总结

通过本次测试对比,可以看出限流的好处:

  1. 有效控制写入压力: 写入限流功能能够有效限制每个节点和每个 Shard 的写入吞吐量,防止因写入量过大而导致系统资源被过度消耗的问题。

  2. 降低系统资源占用: 在限流前,某数据节点的 CPU 占用率约为 10%。限流后,CPU 占用率显著降低至约 5%,减少了约 50%。这表明在高并发写入场景下,写入限流功能显著降低了系统的 CPU 负载。

  3. 提高系统稳定性: 通过控制写入吞吐量,避免了频繁的 Full GC 和节点掉线问题,从而提升了系统的整体稳定性和可靠性。

  4. 保障查询业务性能: 写入限流功能减少了写入操作对 CPU 和内存的占用,确保其他查询业务的响应性能不受影响。

综上所述,写入限流功能在高并发写入场景下表现出色,不仅有效控制了写入压力,还显著降低了系统资源占用,从而提高了系统的稳定性和查询业务的性能。

关于 Easysearch 有奖征文活动

黑神话悟空

无论你是 Easysearch 的老用户,还是第一次听说这个名字,只要你对 INFINI Labs 旗下的 Easysearch 产品感兴趣,或者是希望了解 Easysearch,都可以参加这次活动。

详情查看:Easysearch 征文活动

作者:张磊

原文:https://infinilabs.cn/blog/2024/easysearch-new-feature-write-throttling-introduction/

【搜索客社区日报】第1859期 (2024-07-15)

社区日报searchkit 发表了文章 • 0 个评论 • 2463 次浏览 • 2024-07-17 14:50 • 来自相关话题

1. Easysearch 新特性:写入限流功能介绍 https://infinilabs.cn/blog/202 ... tion/ 2. 中文大模型基准测评2024年上半年报告 https://report.oschina.net/api ... o.pdf 3. ClickHouse 24.6 版本发布说明 https://mp.weixin.qq.com/s/JrAikqoUMjHHuaLEHZptew 4. 斯坦福年度《人工智能指数报告》的十条重要结论 https://cn.weforum.org/agenda/ ... t-cn/ 5. 面壁智能首席科学家刘知远:大模型的“摩尔定律”是模型知识密度持续增强  https://www.tsinghua.edu.cn/info/1182/112713.htm 编辑:Muse 更多资讯:http://news.searchkit.cn

【搜索客社区日报】第1858期 (2024-07-12)

社区日报Fred2000 发表了文章 • 0 个评论 • 3051 次浏览 • 2024-07-12 14:05 • 来自相关话题

1、中文大模型基准测评上半年报告:GPT-4o 排名第一、通义千问 “国服最强” https://www.oschina.net/news/301339 2、高级 RAG 检索策略之流程与模块化 https://mp.weixin.qq.com/s/WeAcAevUPemPKhQLhId3Vg 3、下一代 RAG 技术来了!微软正式开源 GraphRAG:大模型行业将迎来新的升级? https://www.infoq.cn/article/sqaUMyNg6B8OrCcwg4vo 4、电商场景下 ES 搜索引擎的稳定性治理实践 https://mp.weixin.qq.com/s/fAgAgWWYJbbfcGGx1BpLsw 5、玩转 Easysearch 语法 https://infinilabs.cn/blog/202 ... ntax/ 编辑:Fred  更多资讯:http://news.searchkit.cn
1、中文大模型基准测评上半年报告:GPT-4o 排名第一、通义千问 “国服最强” https://www.oschina.net/news/301339 2、高级 RAG 检索策略之流程与模块化 https://mp.weixin.qq.com/s/WeAcAevUPemPKhQLhId3Vg 3、下一代 RAG 技术来了!微软正式开源 GraphRAG:大模型行业将迎来新的升级? https://www.infoq.cn/article/sqaUMyNg6B8OrCcwg4vo 4、电商场景下 ES 搜索引擎的稳定性治理实践 https://mp.weixin.qq.com/s/fAgAgWWYJbbfcGGx1BpLsw 5、玩转 Easysearch 语法 https://infinilabs.cn/blog/202 ... ntax/ 编辑:Fred  更多资讯:http://news.searchkit.cn

玩转 Easysearch 语法

EasysearchINFINI Labs 小助手 发表了文章 • 0 个评论 • 2926 次浏览 • 2024-07-11 12:11 • 来自相关话题

什么是 Easysearch

Elasticsearch 是一个基于 Apache Lucene 的开源分布式搜索和分析引擎,它被广泛应用于全文搜索、结构化搜索和分析等多种场景中。作为 Elasticsearch 的国产化替代方案,Easysearch 不仅保持了与原生 Elasticsearch 的高度兼容性,还在功能、性能、稳定性和扩展性方面进行了全面提升。对于开发团队来说,从 Elasticsearch 切换到 Easysearch 不需要做任何业务代码的调整,确保了无缝衔接和平滑迁移。

Easysearch 是基于 Elasticsearch 7.10.2 开源版本二次开发,所以支持 Elasticsearch 原始的 Query DSL 语法,基本的 SQL 语法,并且兼容现有 Elasticsearch 的 SDK,使得应用无需修改代码即可进行迁移。其平滑的迁移特性,如基于网关的无缝跨版本迁移与升级,提供了随时安全回退的能力。

在之前的文章中,我们已经介绍了 Easysearch 的搭建可视化工具的使用,今天我们将探讨 Easysearch 集群的基本概念和常用的 API。

Easysearch 集群的核心概念

Easysearch 集群由以下几个核心概念构成:

  1. 节点(Node):集群中的单个服务器,负责存储数据并参与集群的索引和搜索功能。
  2. 集群(Cluster):由一个或多个节点组成,拥有唯一的集群名,协同完成数据索引和查询任务。
  3. 索引(Index):存储相关数据的容器,类似于关系数据库中的数据库,一个索引包含多个文档。
  4. 文档(Document):索引中的基本数据单位,相当于关系数据库中的行。
  5. 字段(Field):文档中的一个属性,相当于数据库中的列。
  6. 分片(Shard):为了提高性能和扩展性,索引可以被分割成多个分片,每个分片是索引的一个部分。
  7. 副本(Replica):分片的副本,用于提高数据的可靠性和在节点出现故障时的可用性。

通过多个 API,例如 _cluster/health_cluster/stats,用户可以轻松查看集群的健康状态和详细信息,这些信息对于维护和优化 Easysearch 集群至关重要。

无论是在性能的提升,还是在功能的兼容性方面,Easysearch 都为用户提供了一个强大的搜索引擎平台,让从 Elasticsearch 到 Easysearch 的迁移变得无缝且高效。掌握其核心概念和 API 的使用,将帮助开发者更好地利用这些工具来构建和优化他们的搜索解决方案。

查看集群信息

在 Easysearch 中,可以通过多个 API 来查看集群的各种信息,包括集群的健康状况、节点信息和索引状态。以下是一些常用的查看集群信息的 API 和示例:

查看集群健康状况

_cluster/health API 可以查看集群的健康状态,包括集群是否处于正常状态、节点数量、分片状态等。

GET /_cluster/health

示例响应:

{
  "cluster_name": "my_cluster",
  "status": "green",
  "timed_out": false,
  "number_of_nodes": 3,
  "number_of_data_nodes": 3,
  "active_primary_shards": 5,
  "active_shards": 10,
  "relocating_shards": 0,
  "initializing_shards": 0,
  "unassigned_shards": 0,
  "delayed_unassigned_shards": 0,
  "number_of_pending_tasks": 0,
  "number_of_in_flight_fetch": 0,
  "task_max_waiting_in_queue_millis": 0,
  "active_shards_percent_as_number": 100.0
}

查看集群状态

_cluster/stats API 可以查看集群的详细状态,包括索引、节点、分片等信息。

GET /_cluster/stats

示例响应:

{
  "cluster_name": "my_cluster",
  "status": "green",
  "indices": {
    "count": 10,
    "shards": {
      "total": 20,
      "primaries": 10,
      "replication": 1.0,
      "index": {
        "shards": {
          "min": 1,
          "max": 5,
          "avg": 2.0
        }
      }
    }
  },
  "nodes": {
    "count": {
      "total": 3,
      "data": 3,
      "coordinating_only": 0,
      "master": 1,
      "ingest": 2
    },
    "os": {
      "available_processors": 12,
      "allocated_processors": 12
    },
    "process": {
      "cpu": {
        "percent": 10
      },
      "open_file_descriptors": {
        "min": 100,
        "max": 300,
        "avg": 200
      }
    }
  }
}

查看节点信息

_nodes API 可以查看集群中节点的详细信息,包括节点角色、IP 地址、内存使用情况等。

GET /_nodes

示例响应:

{
  "cluster_name": "my_cluster",
  "nodes": {
    "node_id_1": {
      "name": "node_1",
      "transport_address": "192.168.1.1:9300",
      "host": "192.168.1.1",
      "ip": "192.168.1.1",
      "roles": ["master", "data", "ingest"],
      "os": {
        "available_processors": 4,
        "allocated_processors": 4
      },
      "process": {
        "cpu": {
          "percent": 10
        },
        "open_file_descriptors": 200
      }
    },
    "node_id_2": {
      "name": "node_2",
      "transport_address": "192.168.1.2:9300",
      "host": "192.168.1.2",
      "ip": "192.168.1.2",
      "roles": ["data"],
      "os": {
        "available_processors": 4,
        "allocated_processors": 4
      },
      "process": {
        "cpu": {
          "percent": 15
        },
        "open_file_descriptors": 150
      }
    }
  }
}

查看索引状态

_cat/indices API 可以查看集群中所有索引的状态,包括文档数、存储大小、分片数等信息。

GET /_cat/indices?v

示例响应:

health status index   uuid                   pri rep docs.count docs.deleted store.size pri.store.size
green  open   index_1 SxNUd84vRl6QH5P7g0T4Vg   1   1          0            0       230b           230b
green  open   index_2 NxEYib4yToCnA1PpQ8P4Xw   5   1        100            1      10mb           5mb

这些 API 可以帮助你全面了解 Easysearch 集群的状态和健康状况,从而更好地管理和维护集群。

增删改查操作

在 Easysearch 中,增删改查操作是管理数据和索引的基本功能。以下是如何使用这些操作的详细示例。

创建索引

创建一个新的索引,并指定分片和副本的数量:

PUT /my_index
{
  "settings": {
    "number_of_shards": 3,
    "number_of_replicas": 2
  }
}

删除索引

删除一个不再需要的索引:

DELETE /my_index

添加文档

通过 POST 或 PUT 请求向索引中添加文档:

POST /my_index/_doc/1
{
  "name": "John Doe",
  "age": 30,
  "occupation": "Engineer"
}
PUT /my_index/_doc/1
{
  "name": "John Doe",
  "age": 30,
  "occupation": "Engineer"
}

POSTPUT 方法用于不同的操作,尽管它们都可以用于添加或更新文档,但它们的行为有所不同。

POST /my_index/_doc/1 方法用于创建或替换一个文档。如果指定的文档 ID 已经存在,POST 请求将更新整个文档(不会合并字段)。如果文档 ID 不存在,它将创建一个新的文档。


POST /my_index/_doc/1
{
  "name": "John Doe",
  "age": 30,
  "occupation": "Engineer"
}

PUT /my_index/_doc/1 方法通常用于创建一个新的文档,或者完全替换一个已存在的文档。与 POST 类似,如果指定的文档 ID 已经存在,PUT 请求将替换整个文档。

PUT /my_index/_doc/1
{
  "name": "John Doe",
  "age": 30,
  "occupation": "Engineer"
}

1.使用场景:

  • POST:更适合用于添加或部分更新文档,即使文档 ID 已经存在。
  • PUT:更适合用于创建或完全替换文档。

2.ID 自动生成:

  • POST 请求可以不提供文档 ID,此时 Easysearch 会自动生成一个文档 ID。
  • PUT 请求必须提供文档 ID,如果未提供,则会返回错误。

3.部分更新:

  • POST 请求可以用于部分更新(通过 _update API)。
  • PUT 请求用于完全替换文档,不支持部分更新。

如果文档 ID 已经存在,POSTPUT 都会覆盖整个文档,并且效果是一样的。但是,通常 POST 用于提交数据,而 PUT 用于上传和替换资源。

1.使用 POST 方法添加或更新文档:

POST /my_index/_doc/1
{
  "name": "John Doe",
  "age": 30,
  "occupation": "Engineer"
}

2.使用 PUT 方法添加或更新文档:

PUT /my_index/_doc/1
{
  "name": "John Doe",
  "age": 30,
  "occupation": "Engineer"
}

在这两个示例中,结果都是在索引 my_index 中创建或更新文档 ID 为 1 的文档。无论使用 POST 还是 PUT,如果文档 ID 已存在,都会覆盖原有的文档内容。

新建文档

使用 _create 方法新建文档,如果文档已经存在则返回错误:

PUT /my_index/_create/1
{
  "a": 1
}

如果尝试新建已存在的文档,将会出现如下错误:

{
  "error": {
    "root_cause": [
      {
        "type": "version_conflict_engine_exception",
        "reason": "[1]: version conflict, document already exists (current version [1])",
        "index_uuid": "1xWdHLTaTm6l6HbqACaIEA",
        "shard": "0",
        "index": "my_index"
      }
    ],
    "type": "version_conflict_engine_exception",
    "reason": "[1]: version conflict, document already exists (current version [1])",
    "index_uuid": "1xWdHLTaTm6l6HbqACaIEA",
    "shard": "0",
    "index": "my_index"
  },
  "status": 409
}

获取文档

通过 ID 获取文档的详细信息:

GET /my_index/_doc/1

更新文档

更新文档的特定字段,保留原有字段:

POST /my_index/_update/1
{
  "doc": {
    "age": 31
  }
}

删除文档

通过 ID 删除指定的文档:

DELETE /my_index/_doc/1

查询所有文档

查询索引中的所有文档:

GET /my_index/_search
{
  "query": {
    "match_all": {}
  }
}

这个是 《老杨玩搜索》中总结的图,可以作为“小抄”来记忆:

批量操作 (_bulk API)

_bulk API 用于在一次请求中执行多个索引、删除和更新操作,这对于批量处理大规模数据非常有用,可以显著提高性能和效率。以下是 _bulk API 的基本使用示例:

POST /my_index/_bulk
{ "index": { "_id": "1" } }
{ "name": "John Doe", "age": 30, "occupation": "Engineer" }
{ "index": { "_id": "2" } }
{ "name": "Jane Doe", "age": 25, "occupation": "Designer" }
{ "update": { "_id": "1" } }
{ "doc": { "age": 31 } }

_bulk API 的请求体由多个操作和文档组成。每个操作行包含一个动作描述行和一个可选的源文档行。动作描述行指明了操作的类型(例如,index、create、delete、update)以及操作的元数据。源文档行则包含了实际的数据。

每个操作之间需要用换行符分隔,并且请求体最后必须以换行符结尾。

POST /_bulk
{ "index": { "_index": "a", "_id": "1" } }
{ "name": "John Doe", "age": 30, "occupation": "Engineer" }
{ "index": { "_index": "b", "_id": "2" } }
{ "name": "Jane Doe", "age": 25, "occupation": "Designer" }
{ "update": { "_index": "a", "_id": "1" } }
{ "doc": { "age": 31 } }

分词器

在 Easysearch 中,分词器(Analyzer)用于将文本分解为词项(terms),是全文搜索和文本分析的基础。分词器通常由字符过滤器(Character Filters)、分词器(Tokenizer)和词项过滤器(Token Filters)组成。以下是关于分词器的详细介绍:

1.字符过滤器(Character Filters):在分词之前对文本进行预处理。例如,去除 HTML 标签,替换字符等。

2.分词器(Tokenizer):将文本分解为词项(tokens)。这是分词过程的核心。

3.词项过滤器(Token Filters):对词项进行处理,如小写化、去除停用词、词干提取等。

只有 text 字段支持全文检索,返回的结果根据相似度打分,我们一起看下

POST /index/_mapping
{
  "properties": {
    "content": {
      "type": "text",
      "analyzer": "ik_max_word",
      "search_analyzer": "ik_smart"
    }
  }
}

.POST /index/_mapping

  • 这个部分表示要向名为 index 的索引添加或更新映射设置。

2.“properties”

  • properties 定义了索引中文档的字段结构。在这个例子中,定义了一个名为 content 的字段。

3.“content”

  • 定义了名为 content 的字段。

4.“type”: “text”

type 字段指定 content 字段的数据类型为 texttext 类型适用于需要分词和全文搜索的字段。

5.“analyzer”: “ik_max_word”

analyzer 字段指定索引时使用的分词器为ik_max_wordik_max_word 是 IK 分词器中的一种,它会尽可能多地将文本分解为更多的词项。

6.“search_analyzer”: “ik_smart”

search_analyzer 字段指定搜索时使用的分词器为ik_smartik_smart 是 IK 分词器中的另一种,它会更智能地进行分词,以提高搜索的准确性。

当然,在设置这个 mapping 的时候可以使用同样的分词器,也可以使用不同的分词器。这里介绍下 IK 分词器:

  • IK 分词器是一种中文分词器,适用于中文文本的分词。IK 分词器有两种分词模式:ik_max_wordik_smart
    • ik_max_word:将文本尽可能多地切分成词项,适用于需要更高召回率的场景。
    • ik_smart:进行最智能的分词,适用于需要更高精度的搜索场景。

这个 DSL 的设置意味着,在向这个索引添加或更新文档时,content 字段的文本会使用ik_max_word 分词器进行分词处理,以确保文本被尽可能多地切分成词项。而在搜索时,content 字段的文本会使用ik_smart 分词器进行分词处理,以提高搜索的准确性和相关性。

以下是关于 standard,ik_smart,ik_max_word 这几个分词器的对比:

GET /_analyze
{
  "tokenizer": "standard",
  "text": "我,机器人"
}

GET /_analyze
{
  "tokenizer": "ik_smart",
  "text": "我,机器人"
}

GET /_analyze
{
  "tokenizer": "ik_max_word",
  "text": "我,机器人"
}

结果如下:

# GET /_analyze (standard)
{
  "tokens": [
    {
      "token": "我",
      "start_offset": 0,
      "end_offset": 1,
      "type": "<IDEOGRAPHIC>",
      "position": 0
    },
    {
      "token": "机",
      "start_offset": 2,
      "end_offset": 3,
      "type": "<IDEOGRAPHIC>",
      "position": 1
    },
    {
      "token": "器",
      "start_offset": 3,
      "end_offset": 4,
      "type": "<IDEOGRAPHIC>",
      "position": 2
    },
    {
      "token": "人",
      "start_offset": 4,
      "end_offset": 5,
      "type": "<IDEOGRAPHIC>",
      "position": 3
    }
  ]
}
# GET /_analyze(ik_smart)
{
  "tokens": [
    {
      "token": "我",
      "start_offset": 0,
      "end_offset": 1,
      "type": "CN_CHAR",
      "position": 0
    },
    {
      "token": "机器人",
      "start_offset": 2,
      "end_offset": 5,
      "type": "CN_WORD",
      "position": 1
    }
  ]
}
# GET /_analyze (ik_max_word)
{
  "tokens": [
    {
      "token": "我",
      "start_offset": 0,
      "end_offset": 1,
      "type": "CN_CHAR",
      "position": 0
    },
    {
      "token": "机器人",
      "start_offset": 2,
      "end_offset": 5,
      "type": "CN_WORD",
      "position": 1
    },
    {
      "token": "机器",
      "start_offset": 2,
      "end_offset": 4,
      "type": "CN_WORD",
      "position": 2
    },
    {
      "token": "人",
      "start_offset": 4,
      "end_offset": 5,
      "type": "CN_CHAR",
      "position": 3
    }
  ]
}

如果使用了不存在的分词器会出现这个错误。

{
  "error": {
    "root_cause": [
      {
        "type": "illegal_argument_exception",
        "reason": "failed to find global tokenizer under [simple]"
      }
    ],
    "type": "illegal_argument_exception",
    "reason": "failed to find global tokenizer under [simple]"
  },
  "status": 400
}

精确搜索/正则表达式搜索/通配符

在 Easysearch 中,精确搜索、正则表达式搜索和通配符搜索是三种不同的搜索方式,各有其应用场景和特点:

1.精确搜索 (Term Query)

  • 精确搜索用于查找与搜索词完全匹配的文档。
  • 不进行分词处理,通常用于关键字、ID、标签等字段的精确匹配。
  • 适用于结构化数据或不需要分词的字段(如数字、日期、布尔值等)。
{
  "query": {
    "term": {
      "status": "active"
    }
  }
}

2.正则表达式搜索 (Regexp Query)

  • 正则表达式搜索用于基于正则表达式模式匹配的文档搜索。
  • 支持复杂的字符串匹配模式,但性能可能较低,特别是当数据量较大时。
  • 适用于需要灵活且复杂匹配条件的搜索。
{
  "query": {
    "regexp": {
      "content": "Easysearch .*powerful"
    }
  }
}

3.通配符搜索 (Wildcard Query)

  • 通配符搜索用于通过通配符模式匹配文档。
  • 支持 ?(匹配单个字符)和 *(匹配零个或多个字符)。
  • 性能相对较差,因为通配符搜索可能需要扫描大量数据。
{
  "query": {
    "wildcard": {
      "username": "john*"
    }
  }
}
  • 精确搜索:用于需要绝对匹配特定词语或不需要分词的字段。例如,查找特定用户 ID 或状态。
  • 正则表达式搜索:用于需要复杂字符串模式匹配的场景,但要谨慎使用,避免性能问题。
  • 通配符搜索:用于简单模式匹配,但同样需要注意性能影响,尽量避免在大数据集上频繁使用。

接下来看这个例子,我们将使用批量导入数据,然后进行几种不同类型的查询,包括精确查询、通配符查询和正则表达式查询。

POST /users/_bulk
{ "index": { "_index": "users", "_id": 1 }}
{ "username": "john_doe", "status": "active", "email": "john.doe@example.com", "bio": "John loves Easysearch  and open-source technologies." }
{ "index": { "_index": "users", "_id": 2 }}
{ "username": "jane_doe", "status": "inactive", "email": "jane.doe@example.com", "bio": "Jane is a data scientist working with big data." }
{ "index": { "_index": "users", "_id": 3 }}
{ "username": "john_smith", "status": "active", "email": "john.smith@example.com", "bio": "John enjoys hiking and nature." }
{ "index": { "_index": "users", "_id": 4 }}
{ "username": "alice_jones", "status": "active", "email": "alice.jones@example.com", "bio": "Alice is a software engineer specialized in JavaScript." }
{ "index": { "_index": "users", "_id": 5 }}
{ "username": "bob_jones", "status": "inactive", "email": "bob.jones@example.com", "bio": "Bob is an AI enthusiast and machine learning expert." }

1.精确查询:查询状态为 “active” 的用户。

GET /users/_search
{
  "query": {
    "term": {
      "status": "active"
    }
  }
}

2.通配符查询:查询 bio 字段中包含 “John” 开头的词。

GET /users/_search
{
  "query": {
    "wildcard": {
      "bio": "John*"
    }
  }
}

3.正则表达式查询:查询用户名以 “john” 开头的用户

GET /users/_search
{
  "query": {
    "regexp": {
      "username": "john.*"
    }
  }
}

通过这些例子,你可以看到如何在 Easysearch 中使用批量导入数据,然后使用各种查询方法来检索特定条件的数据。这些查询方法可以帮助你高效地搜索和分析数据,以满足不同的业务需求。

这里同样是《老杨玩搜索》中总结的“小抄”来方便记忆:

多字段查询

在 Easysearch 中,多字段查询允许您在多个字段上同时执行搜索,以获取更精确的结果。最常用的多字段查询类型是 multi_match 查询。multi_match 查询是 match 查询的扩展,能够在多个字段中搜索指定的关键词。

multi_match 查询支持多种匹配模式,如 best_fieldsmost_fieldscross_fieldsphrasephrase_prefix。以下是各模式的简要介绍:

  • best_fields:默认模式,选择匹配度最高的字段。
  • most_fields:计算每个字段的匹配度,然后将匹配度相加。
  • cross_fields:将多个字段视为一个字段进行匹配,适用于分析文本被分散到多个字段的情况。
  • phrase:短语匹配,确保词项顺序与查询相同。
  • phrase_prefix:短语前缀匹配,允许词项的部分匹配。

我们先导入一些示例数据到一个索引 documents 中:

POST /documents/_bulk
{ "index": { "_id": 1 } }
{ "title": "Easysearch  Guide", "content": "This is an introductory guide to Easysearch ." }
{ "index": { "_id": 2 } }
{ "title": "Advanced Easysearch ", "content": "This guide covers advanced topics in Easysearch ." }
{ "index": { "_id": 3 } }
{ "title": "Easysearch  in Action", "content": "Practical guide to Easysearch  usage." }
{ "index": { "_id": 4 } }
{ "title": "Learning Easysearch ", "content": "Beginner's guide to learning Easysearch ." }

我们将使用 multi_match 查询在 titlecontent 字段中同时搜索关键词。

1.基本 multi_match 查询

POST /documents/_search
{
  "query": {
    "multi_match": {
      "query": "guide",
      "fields": ["title", "content"]
    }
  }
}

2.指定匹配模式为 best_fields

POST /documents/_search
{
  "query": {
    "multi_match": {
      "query": "guide",
      "fields": ["title", "content"],
      "type": "best_fields"
    }
  }
}

3.指定匹配模式为 most_fields

POST /documents/_search
{
  "query": {
    "multi_match": {
      "query": "guide",
      "fields": ["title", "content"],
      "type": "most_fields"
    }
  }
}

4.使用 cross_fields 模式

POST /documents/_search
{
  "query": {
    "multi_match": {
      "query": "Easysearch  guide",
      "fields": ["title", "content"],
      "type": "cross_fields"
    }
  }
}

5.短语匹配 (phrase)

POST /documents/_search
{
  "query": {
    "multi_match": {
      "query": "introductory guide",
      "fields": ["title", "content"],
      "type": "phrase"
    }
  }
}

6.短语前缀匹配 (phrase_prefix)

POST /documents/_search
{
  "query": {
    "multi_match": {
      "query": "introductory gui",
      "fields": ["title", "content"],
      "type": "phrase_prefix"
    }
  }
}
  • query:要搜索的关键词或短语。
  • fields:要搜索的字段列表,可以包含一个或多个字段。
  • type:指定匹配模式,默认为 best_fields。

使用 multi_match 查询,您可以在多个字段上同时执行搜索,获得更精确和全面的结果。通过指定不同的匹配模式,您可以调整查询行为以满足特定的搜索需求。无论是基本关键词匹配、短语匹配还是跨字段匹配,multi_match 查询都提供了强大的功能来处理复杂的搜索场景。

除此之外,还可以使用 boost 参数用于调整特定字段的权重,从而影响搜索结果的相关性评分。multi_match 查询支持为不同字段设置不同的 boost 值,以便在搜索结果中优先显示某些字段的匹配项。

布尔查询

布尔查询是 Easysearch 中非常强大且灵活的一种查询方式,它允许用户通过组合多个查询条件来实现复杂的搜索需求。布尔查询使用 bool 查询类型,可以包含以下几种子句:mustfiltermust_notshould。每种子句都有其特定的用途和语义。

1.must

  • 包含在 must 数组中的查询条件必须匹配,类似于逻辑上的 AND 操作。
  • 如果有多个条件,所有条件都必须满足,文档才会被包含在结果集中。

2.filter

  • 包含在 filter 数组中的查询条件必须匹配,但它不会影响评分。
  • filter 子句通常用于对性能要求较高的过滤操作,因为它不计算相关性评分。

3.must_not

  • 包含在 must_not 数组中的查询条件必须不匹配,类似于逻辑上的 NOT 操作。
  • 如果有任何一个条件匹配,文档就会被排除在结果集之外。

4.should

  • 包含在 should 数组中的查询条件至少匹配一个。
  • 如果布尔查询中没有 must 子句,则至少要匹配一个 should 子句。
  • should 子句在计算相关性评分时也有影响。

5.minimum_should_match

  • 指定 should 子句中至少需要满足的条件数量。

首先,我们需要创建一个名为 books 的索引,并定义它的映射(mappings)。映射用于指定每个字段的数据类型。在这个例子中,类别书名字段都被定义为 keyword 类型,这是因为我们需要进行精确匹配查询。

PUT /books
{
  "mappings": {
    "properties": {
      "类别": { "type": "keyword" },
      "书名": { "type": "keyword" }
    }
  }
}

接下来,我们使用批量操作(bulk API)将一些示例数据导入到 books 索引中。这些数据包括不同类别的书籍。

POST /books/_bulk
{ "index": { "_id": 1 } }
{ "类别": "文学", "书名": "我的阿勒泰" }
{ "index": { "_id": 2 } }
{ "类别": "文学", "书名": "平凡的世界" }
{ "index": { "_id": 3 } }
{ "类别": "科学", "书名": "时间简史" }
{ "index": { "_id": 4 } }
{ "类别": "文学", "书名": "百年孤独" }
{ "index": { "_id": 5 } }
{ "类别": "文学", "书名": "红楼梦" }

现在,我们使用布尔查询来搜索类别为“文学”并且书名为“我的阿勒泰”的文档。这里使用的是 must子句,表示查询结果必须满足所有条件。

POST /books/_search
{
  "query": {
    "bool": {
      "must": [
        { "term": { "类别": "文学" } },
        { "term": { "书名": "我的阿勒泰" } }
      ]
    }
  }
}

我们还可以使用 filter 子句来执行相同的查询。filter 子句用于过滤文档,且不会影响文档的相关性评分。这在不需要计算相关性评分时可以提高查询性能。

POST /books/_search
{
  "query": {
    "bool": {
      "filter": [
        { "term": { "类别": "文学" } },
        { "term": { "书名": "我的阿勒泰" } }
      ]
    }
  }
}

当我们执行上述查询时,期望返回的结果是 books 索引中类别为“文学”且书名为“我的阿勒泰”的文档。无论是使用 must 还是 filter 子句,结果应该都是:

{
  "hits": {
    "total": {
      "value": 1,
      "relation": "eq"
    },
    "hits": [
      {
        "_index": "books",
        "_id": "1",
        "_source": {
          "类别": "文学",
          "书名": "我的阿勒泰"
        }
      }
    ]
  }
}

POST /_search
{
  "query": {
    "bool": {
      "must": [
        { "term": { "user.id": "kimchy" } }
      ],
      "filter": [
        { "term": { "tags": "production" } }
      ],
      "must_not": [
        {
          "range": {
            "age": { "gte": 10, "lte": 20 }
          }
        }
      ],
      "should": [
        { "term": { "tags": "env1" } },
        { "term": { "tags": "deployed" } }
      ],
      "minimum_should_match": 1,
      "boost": 1.0
    }
  }
}
  • must 子句:必须匹配的条件,文档必须包含 user.idkimchy
  • filter 子句:过滤条件,文档必须包含 tagsproduction ,但不会影响评分。
  • must_not子句:不匹配的条件,文档的 age 字段不能在 10 到 20 之间。
  • should 子句:可选匹配条件,至少需要匹配一个 should 子句中的条件。这里要求 tags 字段匹配 env1deployed
  • minimum_should_match:至少需要匹配一个 should 子句中的条件。
  • boost:提升查询的整体评分。

为了展示这个 DSL ,我们需要创建一个索引并导入一些数据。假设我们要在 Easysearch 中创建一个索引 users ,并插入一些测试数据。

创建索引

PUT /users
{
  "mappings": {
    "properties": {
      "user.id": { "type": "keyword" },
      "tags": { "type": "keyword" },
      "age": { "type": "integer" }
    }
  }
}

批量导入数据

POST /users/_bulk
{ "index": { "_id": 1 } }
{ "user.id": "kimchy", "tags": ["production", "env1"], "age": 25 }
{ "index": { "_id": 2 } }
{ "user.id": "kimchy", "tags": ["production"], "age": 15 }
{ "index": { "_id": 3 } }
{ "user.id": "kimchy", "tags": ["deployed"], "age": 30 }
{ "index": { "_id": 4 } }
{ "user.id": "kimchy", "tags": ["test"], "age": 35 }
{ "index": { "_id": 5 } }
{ "user.id": "other", "tags": ["production"], "age": 25 }

接下来执行布尔查询:

POST /users/_search
{
  "query": {
    "bool": {
      "must": [
        { "term": { "user.id": "kimchy" } }
      ],
      "filter": [
        { "term": { "tags": "production" } }
      ],
      "must_not": [
        {
          "range": {
            "age": { "gte": 10, "lte": 20 }
          }
        }
      ],
      "should": [
        { "term": { "tags": "env1" } },
        { "term": { "tags": "deployed" } }
      ],
      "minimum_should_match": 1,
      "boost": 1.0
    }
  }
}

根据以上查询,预期返回的结果应该符合以下条件:

  1. user.id必须是 kimchy(由 must 子句决定)。
  2. tags 必须包含 production (由 filter 子句决定)。
  3. age 字段不在 10 到 20 之间(由 must_not 子句决定)。
  4. tags字段中至少包含 env1deployed 中的一个(由 should 子句和 minimum_should_match 参数决定)。
{
  "took": 1,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 1,
      "relation": "eq"
    },
    "max_score": 1.3769134,
    "hits": [
      {
        "_index": "users",
        "_type": "_doc",
        "_id": "1",
        "_score": 1.3769134,
        "_source": {
          "user.id": "kimchy",
          "tags": ["production", "env1"],
          "age": 25
        }
      }
    ]
  }
}

SQL 搜索

Easysearch 直接支持 SQL 查询,无需额外安装插件,同时兼容 Elasticsearch 的 SQL 调用方式,还可以直接编写原生 SQL 查询。

以下是一些测试 SQL 语句的示例:

SELECT * FROM my_index;

SELECT * FROM my_index LIMIT 2;

SELECT * FROM my_index ORDER BY name;

SELECT name AS full_name, age FROM my_index WHERE age > 25;

SELECT name AS full_name, age FROM my_index WHERE age = 25;

SELECT * FROM my_index WHERE age IS NULL;

SELECT DISTINCT age FROM my_index;

SELECT MIN(age), MAX(age), AVG(age) FROM my_index;

SELECT age, COUNT(*) AS CNT FROM my_index GROUP BY age;

使用 Easysearch 执行 SQL 查询

Easysearch 提供了对直接使用 SQL 查询的支持。以下是如何在 Easysearch 中通过 POST 请求使用 _sql 端点进行查询的示例:

执行 SQL 查询非常简单,只需通过 POST 请求发送 SQL 查询即可。以下是一个示例:

POST /_sql
{
  "query": "SELECT name AS full_name, age FROM my_index WHERE age > 25"
}

你也可以规定返回 JSON 格式:

POST /_sql?format=json
{
  "query": "SELECT name AS full_name, age FROM my_index WHERE age > 25"
}

和 Elasticsearch 一样,Easysearch 允许你通过 POST 请求直接在集群上运行 SQL 查询,并返回查询结果。以下是一些常见的 SQL 查询示例及其对应的 POST 请求:

1.查询所有文档

POST /_sql
{
  "query": "SELECT * FROM my_index"
}

2.限制返回文档数

POST /_sql
{
  "query": "SELECT * FROM my_index LIMIT 2"
}

3.按字段排序

POST /_sql
{
  "query": "SELECT * FROM my_index ORDER BY name"
}

4.筛选条件查询

POST /_sql
{
  "query": "SELECT name AS full_name, age FROM my_index WHERE age > 25"
}

5.精确值查询

POST /_sql
{
  "query": "SELECT name AS full_name, age FROM my_index WHERE age = 25"
}

6.查询空值

POST /_sql
{
  "query": "SELECT * FROM my_index WHERE age IS NULL"
}

7.查询唯一值

POST /_sql
{
  "query": "SELECT DISTINCT age FROM my_index"
}

8.聚合函数查询

POST /_sql
{
  "query": "SELECT MIN(age), MAX(age), AVG(age) FROM my_index"
}

9.分组统计

POST /_sql
{
  "query": "SELECT age, COUNT(*) AS CNT FROM my_index GROUP BY age"
}

多表操作的 SQL 语句

以下是多表操作的 SQL 语句及其解释:

1.子查询

SELECT * FROM `table1` t1 WHERE t1.id IN (SELECT id FROM `table2`)

这个查询从 table1 中选择所有字段的记录,其中这些记录的 idtable2 表中也存在。

2.内连接

SELECT * FROM `table1` t1 JOIN `table2` t2 ON t1.id = t2.id

这个查询进行内连接,从 table1table2 中选择所有字段的记录,前提是 table1table2id 相等。

3.左连接

SELECT * FROM `table1` t1 LEFT JOIN `table2` t2 ON t1.id = t2.id

这个查询进行左连接,从 table1table2 中选择所有字段的记录,即使 table2 中没有匹配的记录,也会返回 table1 中的所有记录,未匹配到的部分会用 NULL 填充。

4.右连接

SELECT * FROM `table1` t1 RIGHT JOIN `table2` t2 ON t1.id = t2.id

这个查询进行右连接,从 table1table2 中选择所有字段的记录,即使 table1 中没有匹配的记录,也会返回 table2 中的所有记录,未匹配到的部分会用 NULL 填充。

假设我们有两个索引 table1table2,对应于 SQL 中的两个表。

创建索引 table1

PUT /`table1`
{
  "mappings": {
    "properties": {
      "id": { "type": "integer" },
      "name": { "type": "text" }
    }
  }
}

创建索引 table2

PUT /`table2`
{
  "mappings": {
    "properties": {
      "id": { "type": "integer" },
      "value": { "type": "text" }
    }
  }
}

导入数据到 table1

POST /`table1`/_bulk
{ "index": { "_id": 1 } }
{ "id": 1, "name": "Alice" }
{ "index": { "_id": 2 } }
{ "id": 2, "name": "Bob" }
{ "index": { "_id": 3 } }
{ "id": 3, "name": "Charlie" }
{ "index": { "_id": 4 } }
{ "id": 4, "name": "David" }

导入数据到 table2

POST /`table2`/_bulk
{ "index": { "_id": 1 } }
{ "id": 1, "value": "Value1" }
{ "index": { "_id": 2 } }
{ "id": 2, "value": "Value2" }
{ "index": { "_id": 5 } }
{ "id": 5, "value": "Value5" }
{ "index": { "_id": 6 } }
{ "id": 6, "value": "Value6" }

导入数据后,可以使用 SQL 来执行这些查询:

1.子查询:

POST /_sql
{
  "query": "SELECT * FROM `table1` WHERE id IN (SELECT id FROM `table2`)"
}

2.内连接:

POST /_sql
{
  "query": "SELECT * FROM `table1` t1 JOIN `table2` t2 ON t1.id = t2.id"
}

3.左连接:

POST /_sql
{
  "query": "SELECT * FROM `table1` t1 LEFT JOIN `table2` t2 ON t1.id = t2.id"
}

4.右连接:

POST /_sql
{
  "query": "SELECT * FROM `table1` t1 RIGHT JOIN `table2` t2 ON t1.id = t2.id"
}

效果如下:

SQL 全文检索

matchmatch_phrase 是 Easysearch 中用于全文搜索的查询类型,它们在处理文本匹配方面有不同的用途:

1.match 查询:

  • match 查询用于对文档进行全文搜索。
  • 它将搜索关键词进行分词,并对这些分词后的词项进行搜索。
  • 适用于查询单个或多个字段,可以进行布尔操作(如 “AND”, “OR”)。
  • 例如,搜索 “Easysearch is powerful” 会被分词为 "Easysearch ", “is”, “powerful” 三个词,然后对这三个词进行搜索,文档中包含这些词的都会被认为是匹配的。
{
  "query": {
    "match": {
      "content": "Easysearch  is powerful"
    }
  }
}

2.match_phrase 查询:

  • match_phrase 查询用于短语搜索。
  • 它要求搜索的短语必须在文档中出现且词的顺序相同,词之间的间隔也必须与查询中的短语相同。
  • 适用于需要精确匹配短语的场景。
  • 例如,搜索 “Easysearch is powerful” 时,只有包含这个确切短语的文档才会被认为是匹配的。
{
  "query": {
    "match_phrase": {
      "content": "Easysearch  is powerful"
    }
  }
}

总结来说,match 更灵活,用于一般的关键词搜索,而 match_phrase 则用于需要精确匹配短语的搜索。

SQL 全文检索示例

我们先造一些数据,然后使用 SQL 来进行全文检索。

批量导入数据:

POST /table3/_bulk
{ "index": { "_id": 1 } }
{ "id": 1, "test": "The quick brown fox jumps over the lazy dog" }
{ "index": { "_id": 2 } }
{ "id": 2, "test": "Foxes are wild animals" }
{ "index": { "_id": 3 } }
{ "id": 3, "test": "Jump high to catch the ball" }
{ "index": { "_id": 4 } }
{ "id": 4, "test": "Some animals can jump very high" }
{ "index": { "_id": 5 } }
{ "id": 5, "test": "The lazy dog sleeps all day" }
{ "index": { "_id": 6 } }
{ "id": 6, "test": "The foxes jump all day" }

执行全文检索的 SQL 查询:

SELECT * FROM table3;

SELECT * FROM table3 WHERE match(test, 'jump');

SELECT * FROM table3 WHERE match_phrase(test, 'foxes jump');

总结

随着数据量的不断增加,高效的数据搜索和分析变得尤为重要。Elasticsearch 以其强大的全文搜索能力和灵活的数据处理能力成为行业标准。Easysearch 作为 Elasticsearch 的优化版本,不仅继承了其强大的功能,还在性能和安全性上做了进一步的提升,为企业提供了一个高效、稳定且易于迁移的搜索引擎解决方案。通过深入了解这些技术和实践其应用,开发者和企业能够更好地利用这些工具来应对现代数据挑战,推动业务的持续发展和创新。

关于 Easysearch 有奖征文活动

黑神话悟空

无论你是 Easysearch 的老用户,还是第一次听说这个名字,只要你对 INFINI Labs 旗下的 Easysearch 产品感兴趣,或者是希望了解 Easysearch,都可以参加这次活动。

详情查看:Easysearch 征文活动

作者:韩旭,亚马逊云技术支持,亚马逊云科技技领云博主,目前专注于云计算开发和大数据领域。

原文:https://infinilabs.cn/blog/2024/mastering-easysearch-syntax/

Easysearch 数据可视化和管理平台:INFINI Console 使用介绍

EasysearchINFINI Labs 小助手 发表了文章 • 0 个评论 • 2837 次浏览 • 2024-07-10 16:26 • 来自相关话题

上次在《INFINI Easysearch 尝鲜 Hands on》中,我们部署了两个节点的 Easysearch,并设置了 Console 进行集群监控。今天,我们将介绍 INFINI Console 的使用。

Dashboard

INFINI Console 是一个功能强大的数据管理和分析平台,其仪表盘页面提供了直观简洁的界面,使用户能够快速了解系统状态并进行管理操作。本文将详细介绍仪表盘页面的各项功能。

仪表盘顶部显示系统的实时告警、通知和待办事项的数量,当前数据显示:

  • 告警:0 条
  • 通知:0 条
  • 待办:0 条

在仪表盘的中心区域,用户可以看到几项关键的系统概览信息:

  • 集群数量:当前有 3 个集群正在运行。
  • 节点数量:系统中有 16 个节点。
  • 主机数量:共有 3 台主机。
  • 已用存储:系统已使用存储空间为 2.0GB。

仪表盘页面还提供了几个常用操作的快速入口,方便用户迅速访问常用功能:

  • 集群注册:用户可以通过此入口快速注册新的集群。
  • 数据探索:用户可以访问数据探索工具,对系统中的数据进行分析和查询。
  • 告警管理:提供对告警信息的管理功能,用户可以查看和处理告警。
  • 安全管理:安全管理入口帮助用户维护系统的安全设置和策略。

仪表盘右侧显示了集群的动态信息,包括最近的操作日志。例如:

  • 2024-07-03 22:43:43,index medcl 在 cluster infiniLabs 中的状态更新。
  • 2024-07-03 22:06:43,index medcl 在 cluster infiniLabs 中被创建。

集群管理页面

集群管理页面主要分为几个部分:顶部的功能选项卡、中部的集群列表、以及右侧的筛选和排序选项。

页面顶部的功能选项卡包括以下几项:

  • Clusters (集群):显示当前系统中的所有集群。
  • Nodes (节点):显示集群中的节点详细信息。
  • Indices (索引):显示集群中的索引信息。
  • Hosts (主机):显示系统中的主机信息。

集群列表展示了每个集群的详细信息,包括:

  • 集群名称:每个集群的名称,如 “infinilabs”、“mycluster”、“INFINI_SYSTEM (JeanGrey)”。
  • 集群健康状态:以颜色条的形式显示最近 14 天的集群健康状态(绿色表示健康,黄色表示有警告)。
  • 节点数量:集群中包含的节点数量。
  • 索引数量:集群中的索引数量。
  • 分片数量:集群中的分片数量。
  • 文档数量:集群中存储的文档数量。
  • 磁盘使用率:集群的磁盘使用情况。
  • JVM 堆内存使用率:集群的 JVM 堆内存使用情况。
  • 索引速率:当前集群的索引速率(每秒索引数)。
  • 搜索速率:当前集群的搜索速率(每秒搜索数)。

页面右侧提供了丰富的筛选和排序选项,可以根据以下条件筛选和排序集群:

  • 健康状态 (Health Status):根据集群的健康状态筛选,如绿色(健康)和黄色(警告)。
  • 分布 (Distribution):根据集群的分布类型筛选,如 “easysearch” 和 “elasticsearch”。
  • 版本 (Version):根据集群使用的软件版本筛选,如 Easysearch 1.8.2 和 Elasticsearch 7.10.2。
  • 区域 (Region):根据集群所在的区域筛选,如 “china” 和 “default”。
  • 标签 (Tags):根据自定义标签进行筛选。

接下来分别介绍节点、索引和主机层面的信息,这些监控指标与集群层面大同小异。

节点监控

索引监控

主机监控

包括了常规的 CPU、内存、磁盘、网络的监控。

监控指标页面

监控报表页面提供了对集群运行状况的详细监控和分析功能。用户可以选择最近 15 分钟、1 小时、24 小时等不同时间范围查看数据,并手动点击刷新按钮更新数据,以获取最新的监控信息。

概览信息

显示当前集群的基本状态,包括:

  • 集群名称:如 “infinilabs”。
  • 在线时长:如 “3 天”。
  • 集群版本:如 “1.8.2”。
  • 健康状态:如 “green”。
  • 节点数:如 “2”。
  • 索引数:如 “38”。
  • 主/总分片:如 “38/76”。
  • 未分配分片:如 “0”。
  • 文档数:如 “656,803”。
  • 存储空间:如 “1007.2MB/385.4GB”。
  • JVM 内存:如 “1023.0MB/2.0GB”。

监控报表页面还提供了多个性能指标的图表,包括:

索引吞吐 (doc/s)

  • Total Indexing:总索引吞吐量。
  • Primary Indexing:主分片的索引吞吐量。

查询吞吐 (query/s)

  • Total Query:总查询吞吐量。

索引延迟 (ms)

  • Indexing Latency:索引延迟时间。
  • Delete Latency:删除操作的延迟时间。

查询延迟 (ms)

  • Query Latency:查询延迟时间。
  • Fetch Latency:获取操作的延迟时间。
  • Scroll Latency:滚动操作的延迟时间。

点击“Advance”可以查看更多监控指标:

节点级别性能监控

包括 CPU、负载、JVM 内存、剩余使用空间及磁盘空间、集群启动时间和索引读写情况。

索引级别监控

包括集群内索引的数量、状态、主分片和副本分片数量、文档条数和占用空间。

集群动态页面

提供集群中各类事件和活动的详细记录和监控功能。

别名管理

别名管理页面提供了对索引别名的管理功能,使用户可以方便地管理和配置 Elasticsearch/EasySearch 的索引别名。

创建别名

可以通过 DSL 创建别名。例如,创建一个名为 my_index_alias 的别名指向 my_index

POST /_aliases
{
  "actions": [
    {
      "add": {
        "index": "my_index",
        "alias": "my_index_alias"
      }
    }
  ]
}

删除别名

删除一个别名同样可以通过 REST API 实现:

POST /_aliases
{
  "actions": [
    {
      "remove": {
        "index": "my_index",
        "alias": "my_index_alias"
      }
    }
  ]
}

索引轮换

索引轮换是一种常用的索引管理策略,特别适用于日志和时间序列数据的场景。通过索引轮换,用户可以在索引达到一定条件(如大小或文档数量)时,创建一个新的索引来继续存储数据,而旧的索引可以继续用于查询。

  1. 设置写别名:创建一个指向当前写入索引的别名,例如 current_write_index。
  2. 定义索引轮换条件:可以基于索引的大小、文档数量或时间来定义轮换条件。
  3. 索引并更新写别名指向这个新索引。

创建初始索引并设置写别名:

PUT /my_index-000001
{
  "aliases": {
    "current_write_index": {}
  }
}

使用 /_rollover API 定义轮换条件并执行轮换:

POST /current_write_index/_rollover
{
  "conditions": {
    "max_age": "7d",
    "max_docs": 1000000
  },
  "settings": {
    "number_of_shards": 1
  },
  "aliases": {
    "current_write_index": {}
  }
}

通过这种方式,查询操作可以透明地访问所有历史数据,而写操作总是指向最新的索引。

在 INFINI Console 中提供了可视化创建索引及别名的方式。页面右上角提供了新建按钮,用户可以通过点击该按钮创建新的索引别名,填写别名名称、关联索引、索引路由、搜索路由和过滤查询等配置。

平台监控

展示了多个关键指标的监控图表,包括:

  • 健康状态 (Health):显示系统当前的健康状态。如果没有数据,则显示“暂无数据”。
  • 引擎分布 (Engines):展示系统中不同搜索引擎的分布情况,例如 EasySearch 和 Elasticsearch 的比例。图表显示当前 EasySearch 占 67%,Elasticsearch 占 33%。
  • 提供商 (Providers):显示系统中使用的云服务提供商信息。在示例中,所有资源都托管在 AWS 上。
  • JDK 版本 (JDK):显示系统中使用的 JDK 版本信息。在示例中,所有节点都使用 JDK 版本 11.0.20。
  • 磁盘使用情况 (Disk Utilization) - Top 10:显示磁盘使用率最高的前 10 个节点。在示例中,easysearch-node1 和 easysearch-node2 的磁盘使用率均为 4%。
  • JVM 使用情况 (JVM Utilization) - Top 10:展示 JVM 使用率最高的前 10 个节点。在示例中,infinilabs 集群的 easysearch-node1 和 easysearch-node2 节点的 JVM 使用情况有详细的时间序列数据,显示了不同时间点的使用率变化。

我们还能够看到更多指标:

数据探索

在数据探索里,可以根据时间、字段等条件对索引或者视图下的数据进行搜索查询和分析,类似 Kibana 的 Discover。

这里可以看到集群的警报,目前集群运行良好,没有任何警报。

内部会预设一些警报规则,如下:

点进去一个请求,比如磁盘的警告,可以针对不同的使用量设置不同的警告级别和通知。

这里针对警报设置警报,可以看到现在支持很多平台,Discord、飞书、邮件、微信、Slack 以及钉钉。

点击进去可以查看,对于社交软件而言,其实是使用 Webhook 进行通知,除此之外也支持配置邮件服务器和自定义的 Webhook 进行通知。

开发工具

Console 的开发工具相当于 Kibana DevTool 的升级版,使用上基本没有大的区别,除了支持 DSL 之外,还支持多集群 Tab 切换、常用命令快速 Load、SQL 查询等。

集群连接凭证管理

可以看到连接这三个集群的凭证管理,目前都是有效的。

后台用户授权

可以添加用户以及修改 Console 管理界面的密码。目前设置了 admin 账号。

审计日志

追踪对集群的操作,捕获查看集群监控信息以及集群索引的操作。

结论

INFINI Console 的仪表盘页面集成了系统的关键信息和快捷操作入口,使用户可以高效地管理和监控系统。通过详细的概览信息、实时的告警通知、快速的功能入口和动态日志,用户能够对系统的运行状态一目了然,并快速响应各种管理需求。这个设计不仅提升了用户的工作效率,还确保了系统的安全和稳定运行。

INFINI Console 的集群管理页面提供了对系统集群的全面监控和管理功能。通过详细的集群信息展示、便捷的功能选项卡切换以及丰富的筛选和排序功能,用户可以高效地管理和监控系统中的集群状态。这不仅提升了运维效率,还确保了系统的稳定运行和高效管理。

INFINI Console 的节点管理页面提供了对集群节点的全面监控和管理功能。通过详细的节点信息展示、便捷的功能选项卡切换以及丰富的筛选和搜索功能,用户可以高效地管理和监控系统中的节点状态,从而提升运维效率,确保系统的稳定运行和高效管理。

INFINI Console 的监控报表页面提供了对集群运行状况的全面监控和分析功能。通过详细的概览信息和多个性能指标图表,用户可以高效地监控和管理集群的运行状态。这不仅提升了系统运维效率,还确保了集群的稳定运行和高效管理。

通过这些功能,INFINI Console 为用户提供了全面的系统管理工具,帮助他们高效地应对各种运维挑战,确保系统的高效、安全、稳定运行。

关于 Easysearch 有奖征文活动

黑神话悟空

无论你是 Easysearch 的老用户,还是第一次听说这个名字,只要你对 INFINI Labs 旗下的 Easysearch 产品感兴趣,或者是希望了解 Easysearch,都可以参加这次活动。

详情查看:Easysearch 征文活动

作者:韩旭,亚马逊云技术支持,亚马逊云科技技领云博主,目前专注于云计算开发和大数据领域。

原文:https://blog.csdn.net/weixin_38781498/article/details/140077785