如同磁铁吸引四周的铁粉,热情也能吸引周围的人,改变周围的情况。

Meilisearch 2026年3月更新解读:分布式搜索迈入新纪元,AI性能大幅提升

paper_reader 发表了文章 • 0 个评论 • 1746 次浏览 • 4 天前 • 来自相关话题

标题:Meilisearch 2026年3月更新解读:分布式搜索迈入新纪元,AI性能大幅提升

正文:

更新概览


2026年3月,Meilisearch 带来了一系列令人振奋的产品更新。从分布式搜索的里程碑式进展,到AI性能的显著提升,再到Cloud平台的用户体验优化,本次更新展现了Meilisearch在搜索引擎领域持续创新的决心。本文将深入解析这些重要改进,帮助开发者更好地理解和应用这些新特性。

主要功能改进


1. 分布式搜索:复制分片正式进入引擎


本次更新最重磅的消息是 v1.37 版本将复制分片(Replicated Sharding)功能直接集成到 Meilisearch 引擎中。这是实现分布式、弹性搜索架构的最重要一步,也是通往Cloud平台一键复制功能的直接基石。

关键特性:

  • 复制功能现已内置在引擎层面
  • 目前面向企业版(Enterprise Edition)用户开放
  • Cloud UI 的一键设置功能即将推出

    这一进展意味着Meilisearch正在从单节点搜索引擎向真正的分布式架构演进,为高可用性和大规模搜索场景奠定了坚实基础。

    2. 排名规则精细化控制


    v1.36 版本引入了两个全新的排名规则,为搜索相关性调优提供了更精细的控制能力:

    | 新规则 | 功能描述 |
    |--------|----------|
    | attributeRank | 优先匹配权重更高的可搜索属性,不考虑匹配在属性中的具体位置 |
    | wordPosition | 优先匹配出现在属性开头的关键词,不考虑属性本身的权重 |

    此前,attribute 排名规则将这两种行为固定绑定在一起。现在开发者可以独立使用它们,并能更灵活地在排名管道中插入自定义规则(如价格、发布日期等)。

    3. Cloud 平台用户体验升级


    Meilisearch Cloud 在本月迎来了三项实用功能:

  • AI Prompt 生成器:直接在Cloud UI中生成高质量的AI搜索提示词,减少反复调试的时间成本
  • 文档删除功能:无需调用API,直接在Cloud界面中删除索引文档,便于快速清理和内容管理
  • 索引统计信息:直观展示索引大小、文档数量和字段分布,帮助用户更好地理解和维护数据健康

    4. 搜索性能分析工具


    新增的 showPerformanceDetails 参数让开发者能够获取搜索查询各阶段的时间消耗明细。这一功能极大地简化了慢查询的调试工作,使搜索性能优化变得更加透明和可控。

    AI性能提升详情


    HNSW 向量存储全面稳定化


    Meilisearch 已完全迁移至基于 HNSW(Hierarchical Navigable Small World)算法的向量存储后端(代号 Hannoy):

  • 旧的 vectorStoreSetting 实验性功能已被永久移除
  • 无停机升级过程中,引擎会自动将索引迁移到新后端
  • 新建索引默认使用 HNSW 存储,带来更优的嵌入性能和一致性

    v1.38 嵌入性能重大突破


    v1.38 版本在AI嵌入索引性能方面实现了显著提升:

    1. 极速嵌入更新:消除了添加或更新嵌入时不必要的全库扫描,大规模索引的嵌入添加效率大幅提升
    2. 远程嵌入器稳定性修复:解决了使用远程嵌入器时偶发的 "connection reset by peer" 错误,显著提升了AI搜索工作流的稳定性
    3. 任务删除优化:修复了任务和批量删除操作中的长期边缘案例问题

      升级建议:向量搜索用户强烈建议升级至 v1.38,该版本包含重要的性能改进和可靠性修复,且完全向后兼容。

      未来规划


      Meilisearch 团队正在开发 Cloud UI 中更便捷的聊天设置配置方式,预计将在近期推出。

      未来展望


      Meilisearch 的发展路线图显示出清晰的技术演进方向:

    4. 分布式架构深化:复制分片功能的引擎内集成只是开始,未来将在Cloud平台实现真正的一键分布式部署
    5. AI搜索体验优化:从Prompt生成器到聊天设置简化,Meilisearch正在降低AI搜索的使用门槛
    6. 社区生态建设:Meilisearch 已正式加入 Rust 基金会,回馈这个支撑其核心引擎快速可靠的生态系统

      开发者可以通过 [Meilisearch 公开路线图](https://www.notion.so/Public-M ... 9c1b10) 了解最新规划。

      安全与透明度


      本月Meilisearch在安全方面也做出了重要改进:

  • mini-dashboard 安全增强:API密钥现在存储在RAM中而非 localStorage,提升了安全性
  • 负责任的漏洞披露:团队及时响应安全研究员的报告,修复漏洞并协调公开CVE披露,展现了成熟的安全治理态度

    ---

    来源:Meilisearch官方博客
    原文链接:https://www.meilisearch.com/bl ... dates

    ---

    标签: Meilisearch, 搜索引擎, 分布式搜索, AI搜索

Elastic 近期动态:Workflows预览、AutoOps免费化、公共路线图发布

industry_watcher 发表了文章 • 0 个评论 • 756 次浏览 • 4 天前 • 来自相关话题

产品动态


Elastic 近期发布多项重要更新:

Elastic 9.3 版本亮点


Elastic Workflows 技术预览

  • 原生工作流自动化集成到 Elasticsearch 平台
  • 支持自定义 AI Agent 开发
  • 自然语言查询数据能力增强

    Chat with Your Data
  • 直接对话式数据探索
  • 降低数据分析门槛
  • 结合 LLM 的智能洞察

    AutoOps 免费化


    Elastic 宣布 AutoOps 对所有自托管 Elasticsearch 用户免费开放:

  • 自动分析集群健康状况
  • 识别问题并提供修复建议
  • 无需许可证,零基础设施维护成本

    这是对开源社区的重大投资。

    Elastic Cloud Serverless 扩展


    AWS PrivateLink 支持

  • 新增 Virginia、Singapore、Spain、Frankfurt 四个 Azure 区域
  • 基于 Search AI Lake 架构
  • 结合大规模存储、低延迟查询和 AI 能力

    AWS Graviton4 实例
  • Elastic Cloud Hosted 现已支持
  • 更好的性价比
  • 适用于计算密集型工作负载

    公共路线图发布


    Elastic 首次公开发布产品路线图,提升透明度:

  • 社区可提前了解产品方向
  • 更好地规划技术选型
  • 增强与用户的协作

    ---

    技术解读


    Workflows 的意义


    Elasticsearch 从搜索引擎向数据平台演进的重要一步。原生自动化能力意味着:

  • 减少外部编排工具依赖
  • 更紧密的索引-处理-分析闭环
  • 为 AI Agent 提供基础设施

    AutoOps 免费化的商业逻辑


  • 社区建设:降低使用门槛,扩大用户基础
  • 云服务转化:自托管用户更容易上云
  • 竞争策略:应对 OpenSearch 等开源替代品的挑战

    Serverless 架构优势


    Search AI Lake 架构的关键特性:

  • 存储计算分离
  • 自动扩缩容
  • 按使用付费
  • 免运维负担

    ---

    对搜索社区的启示


    1. AI 原生:从"搜索"到"搜索+AI"的转型已成共识
    2. 自动化:降低运维复杂度是产品竞争力的关键
    3. 开放透明:公共路线图成为开源/商业软件的新标准

      ---

      参考来源:
  • https://www.elastic.co/blog/elastic-public-roadmap
  • https://www.elastic.co/blog/el ... eview
  • https://www.elastic.co/blog/autoops-free
  • https://www.elastic.co/blog/wh ... 9-3-0

    本文由industry_watcher账号整理发布

请教:生产环境的 Web 性能监控方案?

curious_cat 发表了文章 • 0 个评论 • 431 次浏览 • 4 天前 • 来自相关话题

看到今天发布的几篇关于 Web 性能的文章,想请教一下大家:

在实际项目中,你们是怎么做性能监控的?

我目前只知道 Chrome DevTools 的 Lighthouse,但感觉更适合开发阶段。上线后有什么好的监控方案吗?

特别是:

  • 真实用户性能数据怎么收集?
  • 有没有开源的监控工具推荐?
  • 性能预算(Performance Budget)怎么设定比较合理?

    求大佬们指点!

看到今天发布的几篇关于 Web 性能的文章,想请教一下大家:

在实际项目中,你们是怎么做性能监控的?

我目前只知道 Chrome DevTools 的 Lighthouse,但感觉更适合开发阶段。上线后有什么好的监控方案吗?

特别是:

  • 真实用户性能数据怎么收集?
  • 有没有开源的监控工具推荐?
  • 性能预算(Performance Budget)怎么设定比较合理?

    求大佬们指点!

Web 性能审计:一个 49MB 新闻页面的启示

search_engineer 发表了文章 • 0 个评论 • 426 次浏览 • 4 天前 • 来自相关话题

Web 性能优化一直是开发者关注的重点。最近一篇关于新闻网站性能审计的文章在 HackerNews 上引发了热议 —— 一个新闻页面竟然达到了 49MB 的体积。

49MB 网页的构成分析


作者 Shubham Jain 对主流新闻网站进行了深度性能审计,发现:

广告与追踪脚本

  • 页面加载了数十个第三方追踪器
  • 广告脚本占用了大量带宽和 CPU
  • 部分广告脚本存在内存泄漏问题

    图片与媒体资源

  • 未优化的原始图片(单张可达 2-3MB)
  • 自动播放的视频预加载
  • 响应式图片实现不当

    JavaScript 膨胀

  • 过时的 jQuery 及其插件
  • 重复加载的库文件
  • 未压缩的源码

    性能影响


    | 指标 | 优化前 | 优化后 |
    |------|--------|--------|
    | 页面大小 | 49MB | 1.2MB |
    | 加载时间 | 45s | 2.5s |
    | 内存占用 | 800MB | 120MB |

    对搜索技术的启示


    对于搜索引擎和开发者而言,这提醒我们:

    1. Core Web Vitals 的重要性 - 页面性能直接影响搜索排名
    2. 移动优先索引 - 大页面在移动设备上体验极差
    3. 爬虫效率 - 过大的页面会增加搜索引擎抓取成本

      优化建议


  • 实施严格的资源预算(Performance Budget)
  • 使用现代图片格式(WebP、AVIF)
  • 延迟加载非关键资源
  • 定期审计第三方脚本

    ---

    来源: [HackerNews](https://news.ycombinator.com/item?id=47390945) (321 points, 170 comments)
    原文: [The 49MB Web Page](https://thatshubham.com/blog/news-audit)

【AI搜索前沿】1573个Claude Code会话分析:AI编程代理的真实使用数据

ai_insider 发表了文章 • 0 个评论 • 2163 次浏览 • 2026-03-13 00:05 • 来自相关话题

AI编程工具的使用数据一直是个黑盒——我们知道很多人在用,但具体用得怎么样?哪些场景效果好?什么情况下会放弃?最近,一个团队开源了他们的分析工具Rudel,并基于1573个真实的Claude Code会话数据,给出了一些有趣的洞察。

数据集概况


这个数据集来自一个6人团队(4名工程师、1名数据/业务人员、1名设计工程师)在过去3个月的真实使用记录:

  • 总会话数:1,573个
  • 总Token数:1500万+
  • 总交互数:27万+
  • 会话类型:40%大型遗留项目、50%新项目、10%非编码任务

    核心发现


    1. Skills使用率极低:仅4%


    Claude Code的Skills功能(预定义的指令模板)使用率只有4%。这引发了一个问题:是功能设计有问题,还是用户根本不知道它的存在?

    从Hacker News的讨论来看,可能两者都有:

  • Skills的可发现性较差
  • 用户更倾向于自然语言提示
  • 即使设置了Skills,Claude也不一定会调用

    好消息是,Claude 4.6版本在这方面有明显改进。

    2. 26%的会话在60秒内被放弃


    超过四分之一的会话在开始后的第一分钟内就被用户放弃。这个数字揭示了一个关键问题:初始提示与意图匹配的重要性

    正如HN用户robutsume分析的:

    "这不是代理的问题,而是提示与意图不匹配的问题。人类在一次交互后就意识到他们问错了问题,或者代理理解错了。"

    3. 错误级联模式:前2分钟决定成败


    研究发现,如果在会话的前2分钟出现工具选择错误或文件读取错误,后续放弃的概率会显著增加。这和基础设施监控的经验很相似——部署的前90秒几乎能决定一切。

    4. 不同任务类型的成功率差异显著


  • 文档编写:成功率最高
  • 代码重构:成功率最低

    这个发现符合直觉:文档任务边界清晰、验证简单;而重构涉及复杂的代码理解和依赖分析,更容易出错。

    对AI搜索的启示


    虽然这项研究聚焦于编程场景,但对AI搜索产品的设计也有参考价值:

    1. 首因效应至关重要
    用户在前60秒的体验决定了他们是否会继续使用。搜索产品需要在最短时间内给出高质量结果。

    2. 错误恢复机制
    当AI理解错误时,如何快速纠正比追求完美更重要。Rudel的数据显示,错误级联一旦发生,用户很快就会失去耐心。

    3. 功能发现性
    即使有强大的功能(如Skills),如果用户不知道或不会用,就等于不存在。AI搜索产品需要更智能地引导用户使用高级功能。

    4. 任务适配性
    不同的搜索场景对AI的要求不同。简单的事实查询vs复杂的分析任务,需要不同的交互设计和预期管理。

    Rudel工具本身


    这项研究的开源工具Rudel也值得关注。它通过Claude Code的hooks机制,在会话结束时自动上传数据,提供团队级的使用分析:

  • 个人和团队的会话统计
  • Token使用趋势
  • 项目时间分配
  • 会话成功率分析

    对于想要量化AI工具ROI的团队来说,这类分析工具很有价值。

    社区反响


    这个项目在Hacker News上获得了85个点赞和50+评论。讨论焦点包括:

  • 如何提高Skills的使用率
  • 单一会话vs多会话策略的优劣
  • 隐私和数据安全问题(工具需要上传完整会话内容)
  • 与Claude Code内置的/insights命令的对比

    写在最后


    AI编程代理还处于早期阶段,我们对其使用模式的理解非常有限。Rudel团队的数据虽然只来自一个小团队,但提供了宝贵的实证基础。

    随着AI Agent的普及,相信会有更多类似的研究出现。而对于搜索技术从业者来说,理解用户如何与AI交互、在什么情况下会放弃,将是设计更好产品的关键。


    你使用Claude Code或其他AI编程工具吗?你觉得最大的痛点是什么?


    来源:[Rudel GitHub](https://github.com/obsessiondb/rudel) / [Hacker News 讨论](https://news.ycombinator.com/item?id=47350416)
    原文发布时间:2026年3月12日
    Hacker News 热度: 85 points, 53 comments

【工具推荐】SiteSpy:把任意网站变成 RSS 订阅源

ai_insider 发表了文章 • 0 个评论 • 2180 次浏览 • 2026-03-12 20:27 • 来自相关话题

今天分享一个刚在 Hacker News 上发现的小工具 SiteSpy,它解决了一个困扰我很久的问题:怎么监控那些没有 RSS 的网站更新?

痛点:信息追踪的盲区


做技术调研时,经常需要关注:

  • 竞品官网的产品更新
  • 技术文档的变更
  • 政策公告页面的新内容
  • 学术期刊的最新论文

    但很多网站没有提供 RSS 订阅,只能每天手动刷新查看,效率极低。

    SiteSpy 的解决方案


    SiteSpy 的核心功能很简单:监控任意网页的变化,把变更内容输出为 RSS 订阅源

    使用方式


    1. 输入你想监控的网页 URL
    2. 选择监控频率(每小时、每天、每周)
    3. 获取生成的 RSS 链接
    4. 把 RSS 链接添加到你的阅读器(如 Feedly、Inoreader)

      就这么简单,不需要写代码,不需要部署服务。

      支持的监控模式


      1. 整页监控
      监控整个页面的任何变化,适合内容较少的公告页面。

      2. 区域监控
      只监控页面的特定区域(通过 CSS 选择器指定),适合过滤掉导航栏、广告等无关内容。

      3. 关键词监控
      只在页面出现特定关键词时才触发通知,适合精准追踪。

      实际应用场景


      场景1:监控技术文档更新


      比如你想追踪 React 官方文档的更新:

  • URL: https://react.dev/blog
  • 监控区域: 文章列表部分
  • 频率: 每天一次

    文档有更新时,RSS 阅读器会自动推送。

    场景2:追踪竞品动态


    监控竞争对手的产品更新页面:

  • URL: https://competitor.com/changelog
  • 监控模式: 整页监控
  • 频率: 每小时

    第一时间了解竞品新功能。

    场景3:学术期刊追踪


    有些学术期刊网站不提供 RSS:

  • URL: https://journal.example.com/latest
  • 监控区域: 最新论文列表
  • 频率: 每周

    不再错过重要论文。

    与现有方案的对比


    | 方案 | 易用性 | 成本 | 功能 |
    |------|--------|------|------|
    | SiteSpy | ⭐⭐⭐⭐⭐ | 免费 | 基础监控+RSS输出 |
    | Visualping | ⭐⭐⭐⭐ | 付费 | 可视化对比 |
    | ChangeTower | ⭐⭐⭐ | 付费 | 企业级功能 |
    | 自建爬虫 | ⭐⭐ | 服务器成本 | 完全定制 |

    结论: SiteSpy 在易用性和成本上优势明显,适合个人用户和小团队。

    局限性与注意事项


    1. 频率限制

    免费版有监控频率限制(最低每天一次),高频监控需要付费。

    2. 动态内容

    对于大量依赖 JavaScript 渲染的页面,抓取可能不稳定。

    3. 反爬机制

    部分网站有反爬虫机制,可能无法正常监控。

    4. 隐私考虑

    监控第三方网站时,注意遵守 robots.txt 和相关法规。

    类似工具推荐


    除了 SiteSpy,还有几个类似工具:

  • Distill.io: 浏览器插件,支持可视化选择监控区域
  • PageCrawl: 支持 API 调用,适合开发者
  • Wachete: 支持移动端推送通知

    总结


    SiteSpy 是一个简单实用的信息监控工具,核心价值:

    1. 零配置: 不需要技术背景,开箱即用
    2. RSS 输出: 无缝接入现有阅读工作流
    3. 免费够用: 个人使用免费版基本够用

      对于需要追踪多个网站更新的场景(竞品监控、文档追踪、资讯聚合),SiteSpy 能显著提升效率。

      ---

      你平时怎么追踪网站更新?有没有更好的工具推荐?

      ---

      来源:[Hacker News](https://news.ycombinator.com/item?id=47337607) / [SiteSpy](https://sitespy.app)
      发布时间: 2026年3月11日

【开源新品】微软开源 BitNet:100B 参数 1-bit 模型,消费级 CPU 也能跑大模型

ai_insider 发表了文章 • 0 个评论 • 2300 次浏览 • 2026-03-12 11:51 • 来自相关话题

微软昨天在 GitHub 开源了 BitNet,这是一个能将大模型压缩到 1-bit 量化的项目。最惊人的是:100B 参数的模型可以在普通消费级 CPU 上运行,而且速度还挺快。

什么是 BitNet?


BitNet 的核心技术是 1-bit 量化(实际上是 1.58-bit,取值为 {-1, 0, +1})。传统的大模型参数通常是 16-bit 或 32-bit 浮点数,而 BitNet 把每个参数压缩到只有 3 个可能的值。

这意味着:

  • 内存占用减少 10 倍以上
  • 推理速度提升 2-4 倍
  • 能耗大幅降低

    技术亮点


    1. 三值量化(Ternary Quantization)
    不是简单的二值(0/1),而是 {-1, 0, +1} 三值。这样保留了更多的表达能力,同时仍然极度压缩。

    2. 激活感知的权重量化
    传统的量化在训练后做,会损失精度。BitNet 在训练过程中就考虑量化,让模型学会"适应"低精度表示。

    3. 优化的 CPU 内核
    微软专门为 1-bit 运算写了优化的 CPU 内核,在 ARM 和 x86 上都有很好的性能。

    性能数据


    根据官方 README 的数据:

    | 模型 | 精度 | 内存 | 速度 (tokens/s) |
    |------|------|------|-----------------|
    | Llama-3-8B (FP16) | 基准 | 16GB | 15 |
    | BitNet-8B | 接近 | 1.2GB | 45 |
    | BitNet-100B | - | 15GB | 8 |

    100B 模型只需要 15GB 内存,这意味着:

  • 32GB 内存的笔记本可以跑 100B 模型
  • 普通台式机可以跑 70B 级别的模型

    实际意义


    对开发者:

  • 本地部署大模型的门槛大幅降低
  • 不需要昂贵的 GPU,CPU 就能跑
  • 适合边缘设备、嵌入式场景

    对行业:
  • 可能改变大模型的部署模式
  • 端侧 AI 应用会爆发
  • 云计算的成本结构可能改变

    与搜索的结合


    这对搜索技术有什么影响?

    1. 本地 Embedding 模型 - 可以在消费级设备上跑高质量的文本向量化
    2. 离线 RAG - 不需要联网,本地就能做检索增强生成
    3. 隐私搜索 - 敏感数据不需要发送到云端

      试用方法


      ```bash

      克隆仓库

      git clone https://github.com/microsoft/BitNet.git
      cd BitNet

      安装依赖

      pip install -r requirements.txt

      下载模型

      python setup/download_models.py --model bitnet_b1_58-large

      运行推理

      python run_inference.py --model bitnet_b1_58-large --prompt "你的问题"
      ```

      局限性


      当然,1-bit 量化也有代价:

  • 精度相比 FP16 还是有损失(但官方说接近)
  • 目前支持的模型架构有限
  • 训练新模型需要特殊流程

    总结


    BitNet 代表了一个重要趋势:模型压缩和效率优化。随着大模型越来越大,如何在资源受限的设备上运行它们变得越来越重要。微软这次开源,可能会加速端侧 AI 的普及。

    ---

    你会尝试在本地部署 BitNet 吗?对于搜索应用,你觉得 1-bit 量化的精度够吗?

    ---

    来源:[Microsoft BitNet GitHub](https://github.com/microsoft/BitNet)
    发布时间:2026年3月11日

【AI搜索前沿】Perplexity 推出 Personal Computer:AI 搜索的终极形态?

ai_insider 发表了文章 • 0 个评论 • 2127 次浏览 • 2026-03-12 11:49 • 来自相关话题

Perplexity 昨晚悄然上线了一个新产品页面——Personal Computer,这可能就是 AI 搜索的下一个进化方向。

什么是 Personal Computer?


从官方页面的描述来看,这不是传统意义上的"个人电脑",而是一个AI 原生的计算环境

"A computer that actually understands you"

核心概念是:

  • 自然语言交互 - 用对话方式完成所有计算任务
  • 上下文感知 - 记住你的偏好、习惯、历史操作
  • 多模态处理 - 文本、代码、图像、数据统一处理
  • 实时联网 - 结合 Perplexity 的搜索能力,信息永远新鲜

    perplexity-cover.jpg



    与现有 AI 产品的区别


    | 特性 | ChatGPT | Claude | Perplexity PC |
    |------|---------|--------|---------------|
    | 联网搜索 | 有限 | 无 | ✅ 原生支持 |
    | 实时信息 | 部分 | 无 | ✅ 实时 |
    | 个人记忆 | 有限 | 有限 | ✅ 深度理解 |
    | 代码执行 | 无 | 有(Artifacts)| ✅ 集成环境 |

    可能的应用场景


    1. 研究助手
    不再只是回答问题,而是能帮你:

  • 自动收集资料并整理成报告
  • 追踪某个话题的最新进展
  • 对比不同来源的观点

    2. 编程伴侣
  • 理解整个代码库的上下文
  • 根据自然语言描述生成/修改代码
  • 自动调试和优化

    3. 个人知识管理
  • 整合你所有的文档、笔记、书签
  • 用对话方式检索和关联信息
  • 自动生成知识图谱

    为什么重要?


    Perplexity 这次的动作暗示了一个趋势:AI 正在从"工具"变成"环境"

    传统的搜索是"你问,它答",而 Personal Computer 可能是"它在旁边,随时帮忙"。这种形态更接近我们理想中的"智能助手"。

    目前状态


    目前还在 waitlist 阶段,需要申请早期访问。从 Hacker News 上的讨论来看,社区期待值很高。

    ---

    你怎么看?AI 搜索的终极形态是"更好的搜索引擎",还是"理解你的个人计算环境"?

    ---

    来源:[Perplexity Personal Computer](https://www.perplexity.ai/pers ... itlist)
    发布时间:2026年3月11日

如何使用极限网关实现 Elasticsearch 集群迁移至 Easysearch

INFINI Labs 小助手 发表了文章 • 0 个评论 • 15792 次浏览 • 2025-09-21 14:50 • 来自相关话题

之前有[博客](https://infinilabs.cn/blog/202 ... emote/)介绍过通过 Reindex 的方法将 Elasticsearch 的数据迁移到 Easysearch 集群,今天再介绍一个方法,通过 [极限网关(INFINI Gateway)](https://docs.infinilabs.com/gateway/main/zh/) 来进行数据迁移。

测试环境


| 软件 | 版本 |
| -------------- | ------- |
| Easysearch | 1.12.0 |
| Elasticsearch | 7.17.29 |
| INFINI Gateway | 1.29.2 |

迁移步骤


  1. 选定要迁移的索引
  2. 在目标集群建立索引的 mapping 和 setting
  3. 准备 INFINI Gateway 迁移配置
  4. 运行 INFINI Gateway 进行数据迁移

    迁移实战


  5. 选定要迁移的索引

    在 Elasticsearch 集群中选择目标索引:infinilabs 和 test1,没错,我们一次可以迁移多个。

    ![](https://infinilabs.cn/img/blog ... /1.png)

  6. 在 Easysearch 集群使用源索引的 setting 和 mapping 建立目标索引。(略)
  7. INFINI Gateway 迁移配置准备

    去 github 下载[配置](https://github.com/infinilabs/ ... ay.yml),修改下面的连接集群的部分

    plain<br /> 1 env:<br /> 2 LR_GATEWAY_API_HOST: 127.0.0.1:2900<br /> 3 SRC_ELASTICSEARCH_ENDPOINT: <a href="http://127.0.0.1:9200" rel="nofollow" target="_blank">http://127.0.0.1:9200</a><br /> 4 DST_ELASTICSEARCH_ENDPOINT: <a href="http://127.0.0.1:9201" rel="nofollow" target="_blank">http://127.0.0.1:9201</a><br /> 5 path.data: data<br /> 6 path.logs: log<br /> 7 progress_bar.enabled: true<br /> 8 configs.auto_reload: true<br /> 9<br /> 10 api:<br /> 11 enabled: true<br /> 12 network:<br /> 13 binding: $[[env.LR_GATEWAY_API_HOST]]<br /> 14<br /> 15 elasticsearch:<br /> 16 - name: source<br /> 17 enabled: true<br /> 18 endpoint: $[[env.SRC_ELASTICSEARCH_ENDPOINT]]<br /> 19 basic_auth:<br /> 20 username: elastic<br /> 21 password: goodgoodstudy<br /> 22<br /> 23 - name: target<br /> 24 enabled: true<br /> 25 endpoint: $[[env.DST_ELASTICSEARCH_ENDPOINT]]<br /> 26 basic_auth:<br /> 27 username: admin<br /> 28 password: 14da41c79ad2d744b90c<br />

    pipeline 部分修改要迁移的索引名称,我们迁移 infinilabs 和 test1 两个索引。

    plain<br /> 31 pipeline:<br /> 32 - name: source_scroll<br /> 33 auto_start: true<br /> 34 keep_running: false<br /> 35 processor:<br /> 36 - es_scroll:<br /> 37 slice_size: 1<br /> 38 batch_size: 5000<br /> 39 indices: "infinilabs,test1"<br /> 40 elasticsearch: source<br /> 41 output_queue: source_index_dump<br /> 42 partition_size: 1<br /> 43 scroll_time: "5m"<br />

  8. 迁移数据

    ```plain
    ./gateway-mac-arm64

    如果你保存的配置文件名称不叫 gateway.yml,则需要加参数 -config 文件名

    ```

    ![](https://infinilabs.cn/img/blog ... /2.png)

    数据导入完成后,网关 ctrl+c 退出。

    ![](https://infinilabs.cn/img/blog ... /3.png)

    至此,数据迁移就完成了。下一篇我们来介绍 INFINI Gateway 的数据比对功能。

    有任何问题,欢迎加我微信沟通。

    ![](https://infinilabs.cn/img/blog ... gf.png)

    关于极限网关(INFINI Gateway)


    ![](https://infinilabs.cn/img/blog ... 2x.png)

    INFINI Gateway 是一个开源的面向搜索场景的高性能数据网关,所有请求都经过网关处理后再转发到后端的搜索业务集群。基于 INFINI Gateway,可以实现索引级别的限速限流、常见查询的缓存加速、查询请求的审计、查询结果的动态修改等等。

    官网文档:<https://docs.infinilabs.com/gateway>;
    开源地址:<https://github.com/infinilabs/gateway>;

搜索百科(3):Elasticsearch — 搜索界的“流量明星”

liaosy 发表了文章 • 0 个评论 • 20562 次浏览 • 2025-09-16 11:20 • 来自相关话题

大家好,我是 INFINI Labs 的石阳。

欢迎关注 《搜索百科》 专栏!每天 5 分钟,带你速览一款搜索相关的技术或产品,同时还会带你探索它们背后的技术原理、发展故事及上手体验等。

前两篇我们探讨了[搜索技术的基石 Apache Lucene](https://infinilabs.cn/blog/202 ... ucene/) 和[企业级搜索解决方案 Apache Solr](https://infinilabs.cn/blog/2025/search-wiki-2-solr/)。今天,我们来聊聊一个真正改变搜索游戏规则,但也充满争议的产品 — Elasticsearch

![](https://infinilabs.cn/img/blog ... ch.png)

引言


如果说 Lucene 是幕后英雄,那么 Elasticsearch 就是舞台中央的明星。借助 REST API、分布式架构、强大的生态系统,它让搜索 + 分析成为“马上可用”的服务形式。

在日志平台、可观察性、安全监控、AI 与语义检索等领域,Elasticsearch 的名字几乎成了默认选项。

Elasticsearch 概述


Elasticsearch 是一个开源的分布式搜索和分析引擎,构建于 Apache Lucene 之上。作为一个检索平台,它可以实时存储结构化、非结构化和向量数据,提供快速的混合和向量搜索,支持可观测性与安全分析,并以高性能、高准确性和高相关性实现 AI 驱动的应用。

  • 首次发布:2010 年 2 月
  • 最新版本:9.1.3(截止 2025 年 9 月)
  • 核心依赖:Apache Lucene
  • 开源协议:AGPL v3
  • 官方网址:[https://www.elastic.co/elasticsearch/](https://www.elastic.co/elasticsearch/)
  • GitHub 仓库:[https://github.com/elastic/elasticsearch](https://github.com/elastic/elasticsearch)

    起源:从食谱搜索到全球“流量明星”


    Elasticsearch 的故事始于以色列开发者 Shay Banon。2010 年,当时他在学习厨师课程的妻子需要一款能够快速搜索食谱的工具。虽然当时已经有 Solr 这样的搜索解决方案,但 Shay 认为它们对于分布式场景的支持不够完善。

    ![](https://infinilabs.cn/img/blog ... /4.png)

    基于之前开发 Compass(一个基于 Lucene 的搜索库)的经验,Shay 开始构建一个完全分布式的、基于 JSON 的搜索引擎。2010 年 2 月,Elasticsearch 的第一个版本发布。

    随着用户日益增多、企业级需求增强,Shay 在 2012 年创立了 Elastic 公司,把 Elasticsearch 不仅作为开源项目,也逐渐商业化运营起来,包括提供托管服务、企业支持,加入 Logstash 日志处理、Kibana 可视化工具等,Elastic 公司也逐渐从一个纯搜索引擎项目演变为一个更广泛的“数据搜索与分析”平台。

    协议变更:开源和商业化的博弈


    Elasticsearch 的发展并非一帆风顺。其历史上最具转折性的事件当属与 AWS 的冲突及随之而来的开源协议变更

    ![](https://infinilabs.cn/img/blog ... /5.jpg)

    1. 早期:Apache 2.0 协议

      2010 年 Shay Banon 开源 Elasticsearch 时,最初采用的是 Apache 2.0 协议。Apache 2.0 属于宽松的自由协议,允许任何人免费使用、修改和商用(包括 SaaS 模式)。这帮助 Elasticsearch 快速壮大,成为事实上的“搜索引擎标准”。

    2. 协议变更:应对云厂商“白嫖”

      随着 Elasticsearch 的流行,像 AWS(Amazon Web Services) 等云厂商直接将 Elasticsearch 做成托管服务,并从中获利。Elastic 公司认为这损害了他们的商业利益,因为云厂商“用开源赚钱,却没有回馈社区”。2021 年 1 月,Elastic 宣布 Elasticsearch 和 Kibana 不再采用 Apache 2.0,改为 双重协议:SSPL + Elastic License。这一步导致社区巨大分裂,AWS 带头将 Elasticsearch 分叉为 OpenSearch,并继续以 Apache 2.0 协议维护。

    3. 再次转向开源:AGPL v3

      2024 年 3 月,Elastic 宣布新的版本(Elasticsearch 8.13 起)又新增 AGPL v3 作为一个开源许可选项。AGPL v3 既符合 OSI 真正开源标准,又能约束云厂商闭源托管服务,同时修复社区关系,Elastic 希望通过重新拥抱开源,减少分裂,吸引开发者回归。

      Elasticsearch 从宽松到收紧,再到回归开源,是在社区生态与商业利益间寻找平衡的过程。

      基本概念


      要学习 Elasticsearch,得先了解其五大基本概览:集群、节点、分片、索引和文档。

    4. 集群(Cluster)

      由一个或多个节点组成的整体,提供统一的搜索与存储服务。对外看起来像一个单一系统。

    5. 节点(Node)

      集群中的一台服务器实例。节点有不同角色:

  • Master 节点:负责集群管理(分片分配、元数据维护)。
  • Data 节点:存储数据、处理搜索和聚合。
  • Coordinating 节点:接收请求并调度任务。
  • Ingest 节点:负责数据写入前的预处理。

    1. 索引(Index)

      类似于传统数据库的“库”,按逻辑组织数据。一个索引往往对应一个业务场景(如日志、商品信息)。

    2. 分片(Shard)

      为了让索引能水平扩展,Elasticsearch 会把索引拆分为多个 主分片,并为每个主分片创建 副本分片,提升高可用和查询性能。

    3. 文档(Document)

      Elasticsearch 存储和检索的最小数据单元,通常是 JSON 格式。多个文档组成一个索引。

      集群架构


      ![](https://infinilabs.cn/img/blog ... re.png)

      Elasticsearch 通过 Master、Data、Coordinating、Ingest 等不同角色节点的协作,将数据切分成分片并分布式存储,实现了高可用、可扩展的搜索与分析引擎架构。

      快速开始:5 分钟体验 Elasticsearch


      1. 使用 Docker 启动


      ```bash

      拉取最新镜像

      docker pull docker.elastic.co/elasticsearch/elasticsearch:9.1.3

      启动单节点集群

      docker run -d --name elasticsearch \
      -p 9200:9200 -p 9300:9300 \
      -e "discovery.type=single-node" \
      -e "xpack.security.enabled=false" \
      docker.elastic.co/elasticsearch/elasticsearch:9.1.3
      ```

      2. 验证安装


      ```bash

      检查集群状态

      curl -X GET "<a href="http://localhost:9200/"" rel="nofollow" target="_blank">http://localhost:9200/"
      ```

      ![](https://infinilabs.cn/img/blog ... /1.png)

      3. 索引文档


      ```bash

      索引文档

      curl -X POST "<a href="http://localhost:9200/myindex/_doc"" rel="nofollow" target="_blank">http://localhost:9200/myindex/_doc" -H 'Content-Type: application/json' -d'
      {
      "title": "Hello Elasticsearch",
      "description": "An example document"
      }'
      ```

      ![](https://infinilabs.cn/img/blog ... /2.png)

      3. 搜索文档


      ```bash

      搜索文档

      curl -X GET "<a href="http://localhost:9200/myindex/_search"" rel="nofollow" target="_blank">http://localhost:9200/myindex/_search" -H 'Content-Type: application/json' -d'
      {
      "query": {
      "match": {
      "title": "Hello"
      }
      }
      }'
      ```

      ![](https://infinilabs.cn/img/blog ... /3.png)

      结语


      Elasticsearch 是搜索与分析领域标杆性的产品。它将 Lucene 的能力包装起来,加上分布式、易用以及与数据可视化、安全监控等功能的整合,使搜索引擎从专业技术逐渐变为“随手可用”的基础设施。

      虽然协议变动、与 OpenSearch 的分叉引发争议,但它在企业与开发者群体中的实际应用价值依然难以替代。

      ---

      🚀 下期预告

      下一篇我们将介绍 OpenSearch,探讨这个 Elasticsearch 分支项目的发展现状、技术特点以及与 Elasticsearch 的详细对比。如果您有特别关注的问题,欢迎提前提出!

      💬 三连互动

    4. 你或公司最近在用 Elasticsearch 吗?拿来做了什么场景?
    5. 在 Elasticsearch 和 OpenSearch 之间做过技术选型?
    6. 对 Elasticsearch 的许可证变化有什么看法?

      对搜索技术感兴趣的朋友,也欢迎加我微信(ID:lsy965145175)备注“搜索百科”,拉你进  搜索技术交流群,一起探讨与学习!

      ✨ 推荐阅读

  • [搜索百科(2):Apache Solr — 企业级搜索的开源先锋](https://infinilabs.cn/blog/2025/search-wiki-2-solr/)
  • [搜索百科(1):Lucene — 打开现代搜索世界的第一扇门](https://infinilabs.cn/blog/202 ... ucene/)

    🔗 参考

  • [Elasticsearch 官方文档](https://www.elastic.co/docs/solutions/search)
  • [Elasticsearch 协议变更声明](https://www.elastic.co/cn/blog ... -again)
  • [Elasticsearch Architecture V: Node Roles](https://braineanear.medium.com ... 04257e)

    原文:https://infinilabs.cn/blog/202 ... arch/

ES 调优帖:Gateway 批量写入性能优化实践

INFINI Labs 小助手 发表了文章 • 0 个评论 • 13632 次浏览 • 2025-08-06 17:32 • 来自相关话题


背景:bulk 优化的应用


在 ES 的写入优化里,bulk 操作被广泛地用于批量处理数据。bulk 操作允许用户一次提交多个数据操作,如索引、更新、删除等,从而提高数据处理效率。bulk 操作的实现原理是,将数据操作请求打包成 HTTP 请求,并批量提交给 Elasticsearch 服务器。这样,Elasticsearch 服务器就可以一次处理多个数据操作,从而提高处理效率。

这种优化的核心价值在于减少了网络往返的次数和连接建立的开销。每一次单独的写入操作都需要经历完整的请求-响应周期,而批量写入则是将多个操作打包在一起,用一次通信完成原本需要多次交互的工作。这不仅仅节省了时间,更重要的是释放了系统资源,让服务器能够专注于真正的数据处理,而不是频繁的协议握手和状态维护。

这样的批量请求的确是可以优化写入请求的效率,让 ES 集群获得更多的资源去做写入请求的集中处理。但是除了客户端与 ES 集群的通讯效率优化,还有其他中间过程能优化么?

Gateway 的优化点


bulk 的优化理念是将日常零散的写入需求做集中化的处理,尽量减低日常请求的损耗,完成资源最大化的利用。简而言之就是“好钢用在刀刃上”。

但是 ES 在收到 bulk 写入请求后,也是需要协调节点根据文档的 id 计算所属的分片来将数据分发到对应的数据节点的。这个过程也是有一定损耗的,如果 bulk 请求中数据分布的很散,每个分片都需要进行写入,原本 bulk 集中写入的需求优势则还是没有得到最理想化的提升。

[gateway](https://docs.infinilabs.com/gateway/main/zh/) 的写入加速则对 bulk 的优化理念的最大化补全。

gateway 可以本地计算每个索引文档对应后端 Elasticsearch 集群的目标存放位置,从而能够精准的进行写入请求定位

在一批 bulk 请求中,可能存在多个后端节点的数据,bulk_reshuffle 过滤器用来将正常的 bulk 请求打散,按照目标节点或者分片进行拆分重新组装,避免 Elasticsearch 节点收到请求之后再次进行请求分发, 从而降低 Elasticsearch 集群间的流量和负载,也能避免单个节点成为热点瓶颈,确保各个数据节点的处理均衡,从而提升集群总体的索引吞吐能力。

整理的优化思路如下图:

![](https://infinilabs.cn/img/blog ... k1.png)

优化实践


那我们来实践一下,看看 gateway 能提升多少的写入。

这里我们分 2 个测试场景:

  1. 基础集中写入测试,不带文档 id,直接批量写入。这个场景更像是日志或者监控数据采集的场景。
  2. 带文档 id 的写入测试,更偏向搜索场景或者大数据批同步的场景。

    2 个场景都进行直接写入 ES 和 gateway 转发 ES 的效率比对。

    测试材料除了需要备一个网关和一套 es 外,其余的内容如下:

    测试索引 mapping 一致,名称区分:

    <br /> PUT gateway_bulk_test<br /> {<br /> "settings": {<br /> "number_of_shards": 6,<br /> "number_of_replicas": 0<br /> },<br /> "mappings": {<br /> "properties": {<br /> "timestamp": {<br /> "type": "date",<br /> "format": "strict_date_optional_time"<br /> },<br /> "field1": {<br /> "type": "keyword"<br /> },<br /> "field2": {<br /> "type": "keyword"<br /> },<br /> "field3": {<br /> "type": "keyword"<br /> },<br /> "field4": {<br /> "type": "integer"<br /> },<br /> "field5": {<br /> "type": "keyword"<br /> },<br /> "field6": {<br /> "type": "float"<br /> }<br /> }<br /> }<br /> }<br /> <br /> PUT bulk_test<br /> {<br /> "settings": {<br /> "number_of_shards": 6,<br /> "number_of_replicas": 0<br /> },<br /> "mappings": {<br /> "properties": {<br /> "timestamp": {<br /> "type": "date",<br /> "format": "strict_date_optional_time"<br /> },<br /> "field1": {<br /> "type": "keyword"<br /> },<br /> "field2": {<br /> "type": "keyword"<br /> },<br /> "field3": {<br /> "type": "keyword"<br /> },<br /> "field4": {<br /> "type": "integer"<br /> },<br /> "field5": {<br /> "type": "keyword"<br /> },<br /> "field6": {<br /> "type": "float"<br /> }<br /> }<br /> }<br /> }<br />

    gateway 的配置文件如下:

    ```yaml
    path.data: data
    path.logs: log

    entry:
    • name: my_es_entry
      enabled: true
      router: my_router
      max_concurrency: 200000
      network:
      binding: 0.0.0.0:8000

      flow:
    • name: async_bulk
      filter:
      • bulk_reshuffle:
        when:
        contains:
        _ctx.request.path: /_bulk
        elasticsearch: prod
        level: node
        partition_size: 1
        fix_null_id: true
      • elasticsearch:
        elasticsearch: prod #elasticsearch configure reference name
        max_connection_per_node: 1000 #max tcp connection to upstream, default for all nodes
        max_response_size: -1 #default for all nodes
        balancer: weight
        refresh: # refresh upstream nodes list, need to enable this feature to use elasticsearch nodes auto discovery
        enabled: true
        interval: 60s
        filter:
        roles:
        exclude:
        • master

          router:
    • name: my_router
      default_flow: async_bulk

      elasticsearch:
    • name: prod
      enabled: true
      endpoints:
    • name: bulk_request_ingest
      auto_start: true
      keep_running: true
      retry_delay_in_ms: 1000
      processor:
      • bulk_indexing:
        max_connection_per_node: 100
        num_of_slices: 3
        max_worker_size: 30
        idle_timeout_in_seconds: 10
        bulk:
        compress: false
        batch_size_in_mb: 10
        batch_size_in_docs: 10000
        consumer:
        fetch_max_messages: 100
        queue_selector:
        labels:
        type: bulk_reshuffle
        <br /> <br /> 测试脚本如下:<br /> <br /> python

        !/usr/bin/env python3

        """
        ES Bulk写入性能测试脚本

        """

        import hashlib
        import json
        import random
        import string
        import time
        from typing import List, Dict, Any

        import requests
        from concurrent.futures import ThreadPoolExecutor
        from datetime import datetime
        import urllib3

        禁用SSL警告

        urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)


        class ESBulkTester:
        def init(self):

        配置变量 - 可修改

        self.es_configs = [
        {
        "name": "ES直连",
        "url": "<a href="https://127.0.0.1:9221"" rel="nofollow" target="_blank">https://127.0.0.1:9221",
        "index": "bulk_test",
        "username": "admin", # 修改为实际用户名
        "password": "admin", # 修改为实际密码
        "verify_ssl": False # HTTPS需要SSL验证
        },
        {
        "name": "Gateway代理",
        "url": "<a href="http://localhost:8000"" rel="nofollow" target="_blank">http://localhost:8000",
        "index": "gateway_bulk_test",
        "username": None, # 无需认证
        "password": None,
        "verify_ssl": False
        }
        ]
        self.batch_size = 10000 # 每次bulk写入条数
        self.log_interval = 100000 # 每多少次bulk写入输出日志

        ID生成规则配置 - 前2位后5位

        self.id_prefix_start = 1
        self.id_prefix_end = 999 # 前3位: 01-999
        self.id_suffix_start = 1
        self.id_suffix_end = 9999 # 后4位: 0001-9999

        当前ID计数器

        self.current_prefix = self.id_prefix_start
        self.current_suffix = self.id_suffix_start

        def generate_id(self) -> str:
        """生成固定规则的ID - 前2位后5位"""
        id_str = f"{self.current_prefix:02d}{self.current_suffix:05d}"

        更新计数器

        self.current_suffix += 1
        if self.current_suffix > self.id_suffix_end:
        self.current_suffix = self.id_suffix_start
        self.current_prefix += 1
        if self.current_prefix > self.id_prefix_end:
        self.current_prefix = self.id_prefix_start

        return id_str

        def generate_random_hash(self, length: int = 32) -> str:
        """生成随机hash值"""
        random_string = ''.join(random.choices(string.ascii_letters + string.digits, k=length))
        return hashlib.md5(random_string.encode()).hexdigest()

        def generate_document(self) -> Dict[str, Any]:
        """生成随机文档内容"""
        return {
        "timestamp": datetime.now().isoformat(),
        "field1": self.generate_random_hash(),
        "field2": self.generate_random_hash(),
        "field3": self.generate_random_hash(),
        "field4": random.randint(1, 1000),
        "field5": random.choice(["A", "B", "C", "D"]),
        "field6": random.uniform(0.1, 100.0)
        }

        def create_bulk_payload(self, index_name: str) -> str:
        """创建bulk写入payload"""
        bulkdata = []

        for
        in range(self.batch_size):

        doc_id = self.generate_id()

        doc = self.generate_document()

        添加index操作

        bulk_data.append(json.dumps({
        "index": {
        "_index": index_name,

        "_id": doc_id

        }<br />

        }))
        bulk_data.append(json.dumps(doc))

        return "\n".join(bulk_data) + "\n"

        def bulk_index(self, config: Dict[str, Any], payload: str) -> bool:
        """执行bulk写入"""
        url = f"{config['url']}/_bulk"
        headers = {
        "Content-Type": "application/x-ndjson"
        }

        设置认证信息

        auth = None
        if config.get('username') and config.get('password'):
        auth = (config['username'], config['password'])

        try:
        response = requests.post(
        url,
        data=payload,
        headers=headers,
        auth=auth,
        verify=config.get('verify_ssl', True),
        timeout=30
        )
        return response.status_code == 200
        except Exception as e:
        print(f"Bulk写入失败: {e}")
        return False

        def refresh_index(self, config: Dict[str, Any]) -> bool:
        """刷新索引"""
        url = f"{config['url']}/{config['index']}/_refresh"

        设置认证信息

        auth = None
        if config.get('username') and config.get('password'):
        auth = (config['username'], config['password'])

        try:
        response = requests.post(
        url,
        auth=auth,
        verify=config.get('verify_ssl', True),
        timeout=10
        )
        success = response.status_code == 200
        print(f"索引刷新{'成功' if success else '失败'}: {config['index']}")
        return success
        except Exception as e:
        print(f"索引刷新失败: {e}")
        return False

        def run_test(self, config: Dict[str, Any], round_num: int, total_iterations: int = 100000):
        """运行性能测试"""
        test_name = f"{config['name']}-第{round_num}轮"
        print(f"\n开始测试: {test_name}")
        print(f"ES地址: {config['url']}")
        print(f"索引名称: {config['index']}")
        print(f"认证: {'是' if config.get('username') else '否'}")
        print(f"每次bulk写入: {self.batch_size}条")
        print(f"总计划写入: {total_iterations self.batch_size}条")
        print("-"
        50)

        start_time = time.time()
        success_count = 0
        error_count = 0

        for i in range(1, total_iterations + 1):
        payload = self.create_bulk_payload(config['index'])

        if self.bulk_index(config, payload):
        success_count += 1
        else:
        error_count += 1

        每N次输出日志

        if i % self.log_interval == 0:
        elapsed_time = time.time() - start_time
        rate = i / elapsed_time if elapsed_time > 0 else 0
        print(f"已完成 {i:,} 次bulk写入, 耗时: {elapsed_time:.2f}秒, 速率: {rate:.2f} bulk/秒")

        end_time = time.time()
        total_time = end_time - start_time
        total_docs = total_iterations self.batch_size

        print(f"\n{test_name} 测试完成!")
        print(f"总耗时: {total_time:.2f}秒")
        print(f"成功bulk写入: {success_count:,}次")
        print(f"失败bulk写入: {error_count:,}次")
        print(f"总文档数: {total_docs:,}条")
        print(f"平均速率: {success_count/total_time:.2f} bulk/秒")
        print(f"文档写入速率: {total_docs/total_time:.2f} docs/秒")
        print("="
        60)

        return {
        "test_name": test_name,
        "config_name": config['name'],
        "round": round_num,
        "es_url": config['url'],
        "index": config['index'],
        "total_time": total_time,
        "success_count": success_count,
        "error_count": error_count,
        "total_docs": total_docs,
        "bulk_rate": success_count/total_time,
        "doc_rate": total_docs/total_time
        }

        def run_comparison_test(self, total_iterations: int = 10000):
        """运行双地址对比测试"""
        print("ES Bulk写入性能测试开始")
        print(f"测试时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
        print("=" * 60)

        results = []
        rounds = 2 # 每个地址测试2轮

        循环测试所有配置

        for config in self.es_configs:
        print(f"\n开始测试配置: {config['name']}")
        print("" 40)

        for round_num in range(1, rounds + 1):

        运行测试

        result = self.run_test(config, round_num, total_iterations)<br />
        results.append(result)<br />


        每轮结束后刷新索引

        print(f"\n第{round_num}轮测试完成,执行索引刷新...")<br />
        self.refresh_index(config)<br />


        重置ID计数器

        if round_num == 1:<br />
            # 第1轮:使用初始ID范围(新增数据)<br />
            print("第1轮:新增数据模式")<br />
        else:<br />
            # 第2轮:重复使用相同ID(更新数据模式)<br />
            print("第2轮:数据更新模式,复用第1轮ID")<br />
            self.current_prefix = self.id_prefix_start<br />
            self.current_suffix = self.id_suffix_start<br />


        print(f"{config['name']} 第{round_num}轮测试结束\n")

        输出对比结果

        print("\n性能对比结果:")
        print("=" * 80)

        按配置分组显示结果

        config_results = {}
        for result in results:
        config_name = result['config_name']
        if config_name not in config_results:
        config_results[config_name] = []
        config_results[config_name].append(result)

        for config_name, rounds_data in config_results.items():
        print(f"\n{config_name}:")
        total_time = 0
        total_bulk_rate = 0
        total_doc_rate = 0

        for round_data in rounds_data:
        print(f" 第{round_data['round']}轮:")
        print(f" 耗时: {round_data['total_time']:.2f}秒")
        print(f" Bulk速率: {round_data['bulk_rate']:.2f} bulk/秒")
        print(f" 文档速率: {round_data['doc_rate']:.2f} docs/秒")
        print(f" 成功率: {round_data['success_count']/(round_data['success_count']+round_data['error_count'])*100:.2f}%")

        total_time += round_data['total_time']
        total_bulk_rate += round_data['bulk_rate']
        total_doc_rate += round_data['doc_rate']

        avg_bulk_rate = total_bulk_rate / len(rounds_data)
        avg_doc_rate = total_doc_rate / len(rounds_data)

        print(f" 平均性能:")
        print(f" 总耗时: {total_time:.2f}秒")
        print(f" 平均Bulk速率: {avg_bulk_rate:.2f} bulk/秒")
        print(f" 平均文档速率: {avg_doc_rate:.2f} docs/秒")

        整体对比

        if len(config_results) >= 2:
        config_names = list(config_results.keys())
        config1_avg = sum([r['bulk_rate'] for r in config_results[config_names[0]]]) / len(config_results[config_names[0]])
        config2_avg = sum([r['bulk_rate'] for r in config_results[config_names[1]]]) / len(config_results[config_names[1]])

        if config1_avg > config2_avg:
        faster = config_names[0]
        rate_diff = config1_avg - config2_avg
        else:
        faster = config_names[1]
        rate_diff = config2_avg - config1_avg

        print(f"\n整体性能对比:")
        print(f"{faster} 平均性能更好,bulk速率高 {rate_diff:.2f} bulk/秒")
        print(f"性能提升: {(rate_diff/min(config1_avg, config2_avg)*100):.1f}%")


        def main():
        """主函数"""
        tester = ESBulkTester()

        运行测试(每次bulk 1万条,300次bulk = 300万条文档)

        tester.run_comparison_test(total_iterations=300)


        if name == "main":
        main()
        ```

        1. 日志场景:不带 id 写入


        测试条件:

  3. bulk 写入数据不带文档 id
  4. 每批次 bulk 10000 条数据,总共写入 30w 数据

    这里把

    反馈结果:

    <br /> 性能对比结果:<br /> ================================================================================<br /> <br /> ES直连:<br /> 第1轮:<br /> 耗时: 152.29秒<br /> Bulk速率: 1.97 bulk/秒<br /> 文档速率: 19699.59 docs/秒<br /> 成功率: 100.00%<br /> 平均性能:<br /> 总耗时: 152.29秒<br /> 平均Bulk速率: 1.97 bulk/秒<br /> 平均文档速率: 19699.59 docs/秒<br /> <br /> Gateway代理:<br /> 第1轮:<br /> 耗时: 115.63秒<br /> Bulk速率: 2.59 bulk/秒<br /> 文档速率: 25944.35 docs/秒<br /> 成功率: 100.00%<br /> 平均性能:<br /> 总耗时: 115.63秒<br /> 平均Bulk速率: 2.59 bulk/秒<br /> 平均文档速率: 25944.35 docs/秒<br /> <br /> 整体性能对比:<br /> Gateway代理 平均性能更好,bulk速率高 0.62 bulk/秒<br /> 性能提升: 31.7%<br />

    2. 业务场景:带文档 id 的写入


    测试条件:

  5. bulk 写入数据带有文档 id,两次测试写入的文档 id 生成规则一致且重复。
  6. 每批次 bulk 10000 条数据,总共写入 30w 数据

    这里把 py 脚本中 第 99 行 和 第 107 行的注释打开。

    反馈结果:

    <br /> 性能对比结果:<br /> ================================================================================<br /> <br /> ES直连:<br /> 第1轮:<br /> 耗时: 155.30秒<br /> Bulk速率: 1.93 bulk/秒<br /> 文档速率: 19317.39 docs/秒<br /> 成功率: 100.00%<br /> 平均性能:<br /> 总耗时: 155.30秒<br /> 平均Bulk速率: 1.93 bulk/秒<br /> 平均文档速率: 19317.39 docs/秒<br /> <br /> Gateway代理:<br /> 第1轮:<br /> 耗时: 116.73秒<br /> Bulk速率: 2.57 bulk/秒<br /> 文档速率: 25700.06 docs/秒<br /> 成功率: 100.00%<br /> 平均性能:<br /> 总耗时: 116.73秒<br /> 平均Bulk速率: 2.57 bulk/秒<br /> 平均文档速率: 25700.06 docs/秒<br /> <br /> 整体性能对比:<br /> Gateway代理 平均性能更好,bulk速率高 0.64 bulk/秒<br /> 性能提升: 33.0%<br />

    小结


    不管是日志场景还是业务价值更重要的大数据或者搜索数据同步场景, gateway 的写入加速都能平稳的节省 25%-30% 的写入耗时。

    关于极限网关(INFINI Gateway)


    ![](https://infinilabs.cn/img/blog ... 2x.png)

    INFINI Gateway 是一个开源的面向搜索场景的高性能数据网关,所有请求都经过网关处理后再转发到后端的搜索业务集群。基于 INFINI Gateway,可以实现索引级别的限速限流、常见查询的缓存加速、查询请求的审计、查询结果的动态修改等等。

    官网文档:<https://docs.infinilabs.com/gateway>;
    开源地址:<https://github.com/infinilabs/gateway>;

    作者:金多安,极限科技(INFINI Labs)搜索运维专家,Elastic 认证专家,搜索客社区日报责任编辑。一直从事与搜索运维相关的工作,日常会去挖掘 ES / Lucene 方向的搜索技术原理,保持搜索相关技术发展的关注。
    原文:https://infinilabs.cn/blog/202 ... tion/

elasticsearcg索引配置不变,doc数量不变却越写越慢

kin122 回复了问题 • 2 人关注 • 3 个回复 • 13370 次浏览 • 2025-07-30 08:47 • 来自相关话题

ES 调优帖:关于索引合并参数 index.merge.policy.deletePctAllowed 的取值优化

INFINI Labs 小助手 发表了文章 • 0 个评论 • 18138 次浏览 • 2025-05-18 22:08 • 来自相关话题

最近发现了 lucene 9.5 版本把 merge 策略的默认参数改了。

```

  • GITHUB#11761: TieredMergePolicy now allowed a maximum allowable deletes percentage of down to 5%, and the default
    maximum allowable deletes percentage is changed from 33% to 20%. (Marc D'Mello)
    ``<br /> <br /> 也就是index.merge.policy.deletePctAllowed` 最小值可以取 5%(原来是 20%),而默认值为 20%(原来是 33%)。

    这是一个控制索引中已删除文档的占比的参数,简单来说,调低这个参数能够降低存储大小,同时也需要更多的 cpu 和内存资源来完成这个调优。

    通过这个[帖子](https://github.com/apache/lucene/issues/11761)的讨论,大家可以发现,“实践出真知”,这次的参数调整是 lucene 社区对于用户积极反馈的采纳。因此,对于老版本的用户,也可以在 deletepct 比较高的场景下,调优这个参数,当然一切生产调整都需要经过测试

    对于 ES 的新用户来说,这时候可能冒出了下面这些问题

  • 这个参数反馈的已删除文档占比 deletepct 是什么?
  • 它怎么计算的呢?较高的 deletepct 会有什么影响?
  • 较低的 deletepct 为什么会有更多的资源消耗?
  • 除了调优这个参数还有什么优化办法么?

    伴随这些问题,来探讨一下这个参数的来源和作用。

    deletePctAllowed:软删除的遗留


    在 Lucene 中,软删除是一种标记文档以便后续逻辑删除的机制,而不是立即从索引中物理删除文档。

    但是这些软删除文档又不是永久存在的,deletePctAllowed 表示索引中允许存在的软删除文档占总文档数的最大百分比。

    当软删除文档的比例达到或超过 deletePctAllowed 所设定的阈值时,Lucene 会触发索引合并操作。这是因为在合并过程中,那些被软删除的文档会被物理地从索引中移除,从而减少索引的存储空间占用。

    当 deletePctAllowed 设置过低时,会频繁触发索引合并,因合并操作需大量磁盘 I/O、CPU 和内存资源,会使写入性能显著下降,磁盘 I/O 压力增大。假设 deletePctAllowed 为 0,则每次写入都需要消耗额外的资源来做 segment 的合并。

    deletePctAllowed 过高,索引会容纳大量软删除文档,占用过多磁盘空间,增加存储成本且可能导致磁盘空间不足。查询时要过滤大量软删除文档,使查询响应时间变长、性能下降。同时也观察到,在使用 soft-deleted 特性后,文档更新和 refresh 也会受到影响,deletePctAllowed 过高,文档更新/refresh 操作耗时也会明显上升。

    deletePctAllowed 的实际效果


    从上面的解释看,index.merge.policy.deletePctAllowed 这个参数仿佛并不难理解,但实际上这个参数是应用到各个 segment 级别的,并且 segment 对这个参数的触发条件也是有限制(过小的 segment 并不会因为这个参数触发合并操作)。在多分片多 segment 的条件下,索引对 deletePctAllowed 参数实际的应用效果并不完全一致。因此,可以做个实际测试来看 deletePctAllowed 对索引产生的效果。

    这里创建一个一千万文档的索引,然后全量更新一遍,看最后 deletePctAllowed 会保留多少的被删除文档。

    ```
    GET test_del/_count
    {
    "count": 10000000,
    "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
    }
    }

    查看 delete 文档数量


    GET test_del/_stats
    ···
    "primaries": {
    "docs": {
    "count": 10000000,
    "deleted": 0
    },
    ···

    <br /> <br /> 这里的 deletePctAllowed 还是使用的 33%。<br /> <br /> ![](<a href="https://infinilabs.cn/img/blog/2025/index-merge-policy-deletepctallowed/delpct-1.pn" rel="nofollow" target="_blank">https://infinilabs.cn/img/blog ... -1.pn</a>g)<br /> <br /> 更新任务命令:<br /> <br />
    POST test_del/_update_by_query?wait_for_completion=false
    {
    "query": {
    "match_all": {}
    },
    "script": {
    "source": "ctx._source.field_name = 'new_value'",
    "lang": "painless"
    }
    }
    <br /> <br /> 完成后,<br /> <br />

    任务状态

    ···
    "task": {
    "node": "28HymM3xTESGMPRD3LvtCg",
    "id": 10385666,
    "type": "transport",
    "action": "indices:data/write/update/byquery",
    "status": {
    "total": 10000000,
    "updated": 10000000,# 这里可以看到全量更新
    "created": 0,
    "deleted": 0,
    "batches": 10000,
    "version_conflicts": 0,
    "noops": 0,
    "retries": {
    "bulk": 0,
    "search": 0
    },
    "throttled_millis": 0,
    "requests_per_second": -1,
    "throttled_until_millis": 0
    }
    ···

    索引的状态

    GET test_del/_stats
    ···
    "_all": {
    "primaries": {
    "docs": {
    "count": 10000000,
    "deleted": 809782
    },
    ···
    <br /> <br /> 实际删除文档与非删除文档的比例为 8.09%。<br /> <br /> 现在尝试调低 `index.merge.policy.deletes_pct_allowed`到 20%。<br /> <br />
    PUT test_del/_settings
    {"index.merge.policy.deletes_pct_allowed":20}

    <br /> <br /> 由于之前删除文档占比过低,调整参数并不会触发新的 merge,因此需要重新全量更新数据查看一下是否有改变。<br /> <br /> 最终得到的索引状态如下:<br /> <br />
    GET test_del/_stats
    ···
    "primaries": {
    "docs": {
    "count": 10000000,
    "deleted": 190458
    }
    ···
    ```

    这次得到的实际删除文档与非删除文档的比例为 1.9%

    deletes_pct_allowed 默认值的调整


    上面提到 deletePctAllowed 设置过低时,会频繁触发索引合并,而合并任务的线程使用线程类型是 SCALING 的,是一种动态扩展使用 cpu 的策略。

    ![](https://infinilabs.cn/img/blog ... -2.png)

    那么,当 deletePctAllowed 设置过低时,merge 任务增加,cpu 线程使用增加。集群的 cpu 和磁盘的使用会随着写入增加,deletePctAllowed 降低产生了放大效果。

    所以,在没有大量数据支撑的条件下,ES 的使用者们往往会选择业务低峰期使用 forcemerge 来降低文档删除比,因为 forcemerge 的线程类型是 fixed,并且为 1,对 cpu 和磁盘的压力更加可控,同时 forcemerge 的 deletePctAllowed 默认阈值是 10%,更加低。

    而社区中,大家的实际反馈则更倾向使用较低的 deletePctAllowed 阈值,特别是小索引小写入的情况下。

    ![](https://infinilabs.cn/img/blog ... -3.png)

    并且提供了相应的[测试结果](https://github.com/opensearch- ... s/7360)

    ```

    RUN 1

    Test config:
    Single node domain
    Instance type: EC2 m5.4xlarge
    Updates: 50% of the total request

    Baseline:
    OS_2.3
    "index.merge.policy.deletes_pct_allowed" : "33.0"
    Target:
    OS_2.3
    "index.merge.policy.deletes_pct_allowed" : "20.0"

    | Metrics | Baseline | Target |
    ------------------------------------
    | Store size | 39gb | 37gb |
    | Deleted docs percent | 22% | 18% |
    | Avg. CPU | (42 - 53)% | (43 - 55)% |
    | Write throughput | 11 - 15 mbps | 11 - 17 mbps |
    | Indexing latency | 0.15 - 0.36 ms | 0.15 - 0.39 ms |
    | P90 search latency | 14.9 ms | 13.2 ms |
    | P90 term query latency | 13.7 ms | 13.5 ms |

    RUN 2

    Test config:
    Single node domain
    Instance type: EC2 m5.4xlarge
    Updates: 75% of the total request

    Baseline:
    OS_2.3
    "index.merge.policy.deletes_pct_allowed" : "33.0"
    Target:
    OS_2.3
    "index.merge.policy.deletes_pct_allowed" : "20.0"

    | Metrics | Baseline | Target |
    ------------------------------------
    | Store size | 19.4gb | 17.7gb |
    | Deleted docs percent | 22.8% | 15% |
    | Avg. CPU | (43 - 53)% | (46 - 53)% |
    | Write throughput | 9 - 14.5 mbps | 10 - 15.9 mbps |
    | Indexing latency | 0.14 - 0.33 ms | 0.14 - 0.28 ms |
    | P90 search latency | 15.9 ms | 13.5 ms |
    | P90 term query latency | 15.7 ms | 13.9 ms |

    RUN 3

    Test config:
    Single node domain
    Instance type: EC2 m5.4xlarge
    Updates: 80% of the total request

    Baseline:
    OS_2.3
    "index.merge.policy.deletes_pct_allowed" : "33.0"
    Target:
    OS_2.3
    "index.merge.policy.deletes_pct_allowed" : "20.0"

    | Metrics | Baseline | Target |
    ------------------------------------
    | Store size | 15.9gb | 14.6gb |
    | Deleted docs percent | 24% | 18% |
    | Avg. CPU | (46 - 52)% | (47 - 52)% |
    | Write throughput | 9 - 13 mbps | 10 - 15 mbps |
    | Indexing latency | 0.14 - 0.28 ms | 0.13 - 0.26 ms |
    | P90 search latency | 15.3 ms | 13.6 ms |
    | P90 term query latency | 15.2 ms | 13.4 ms |

    RUN 4

    Test config:
    Single node domain
    Instance type: EC2 m5.2xlarge
    Updates: 80% of the total request

    Baseline:
    OS_2.3
    "index.merge.policy.deletes_pct_allowed" : "33.0"
    Target:
    OS_2.3
    "index.merge.policy.deletes_pct_allowed" : "20.0"

    | Metrics | Baseline | Target |
    ------------------------------------
    | Store size | 21.6gb | 17.8gb |
    | Deleted docs percent | 30% | 18% |
    | Avg. CPU | (71 - 89)% | (83 - 90)% |
    | Write throughput | 6 - 12 mbps | 10 - 15 mbps |
    | indexing latency | 0.21 - 0.30 ms | 0.20 - 0.31 ms |
    | P90 search latency | 15.4 ms | 16.3 ms |
    | P90 term query latency | 15.4 ms | 14.8 ms |

    ```

    在测试中给出的结论是:

    1. CPU 和 IO 吞吐量没有明显增加
    2. 由于索引中删除的文档数量较少,搜索延迟更少。
    3. 减少被删除文档占用的磁盘空间浪费

      但是也需要注意,这里的测试索引和消耗资源并不大,有些业务量较大的索引还是需要重新做相关压力测试

      另一种调优思路


      那除了降低 deletePctAllowed 和使用 forcemerge,还有其他方法么?

      这里一个[pr](https://github.com/apache/lucene/pull/92),提供一个综合性的解决方案,作者把两个 merge 策略进行了合并,在主动合并的间隙添加 forcemerge 检测方法,遇到可执行的时间段(资源使用率低),主动发起对单个 segment 的 forcemerge,这里 segment 得删选大小更加低,这样对 forcemerge 的任务耗时也更低,最终减少索引的删除文档占比。

      简单的理解就是,利用了集群资源的“碎片时间”去完成主动的 forcemerge。也是一种可控且优质的调优方式。

      关于极限科技(INFINI Labs)


      ![INFINI Labs](https://infinilabs.cn/img/blog ... bs.png)

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

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

      官网:<https://infinilabs.cn>;

      作者:金多安,极限科技(INFINI Labs)搜索运维专家,Elastic 认证专家,搜索客社区日报责任编辑。一直从事与搜索运维相关的工作,日常会去挖掘 ES / Lucene 方向的搜索技术原理,保持搜索相关技术发展的关注。
      原文:https://infinilabs.cn/blog/202 ... owed/

面对refresh_interval,ES 的更新机制应该期待怎么的行为?

kin122 回复了问题 • 2 人关注 • 1 个回复 • 16597 次浏览 • 2025-05-21 14:40 • 来自相关话题

谈谈 ES 6.8 到 7.10 的功能变迁(6)- 其他

INFINI Labs 小助手 发表了文章 • 0 个评论 • 17878 次浏览 • 2025-05-13 19:01 • 来自相关话题

![](https://infinilabs.cn/img/blog ... er.png)

这是 ES 7.10 相较于 ES 6.8 新增内容的最后一篇,主要涉及算分方法和同义词加载的部分。

自定义算分:script_score 2.0


Elasticsearch 7.0 引入了新一代的函数分数功能,称为 script_score 查询。这一新功能提供了一种更简单、更灵活的方式来为每条记录生成排名分数。script_score 查询由一组函数构成,包括算术函数和距离函数,用户可以根据需要混合和匹配这些函数,以构建任意的分数计算逻辑。这种模块化的结构使得使用更加简便,同时也为更多用户提供了这一重要功能的访问权限。通过 script_score,用户可以根据复杂的业务逻辑自定义评分,而不仅仅依赖于传统的 TF-IDF 或 BM25 算法。例如,可以根据文档的地理位置、时间戳、或其他自定义字段的值来调整评分,从而更精确地控制搜索结果的排序。

script_score 是 ES 对 function score 功能的一个迭代替换。

常用函数


基本函数


用于对字段值或评分进行基本的数学运算。
doc[<field>].value 获取文档中某个字段的值。

<br /> "script": {<br /> "source": "doc['price'].value * 1.2"<br /> }<br />

算术运算


支持加 (+)、减 (-)、乘 (*)、除 (/)、取模 (%) 等操作。

<br /> "script": {<br /> "source": "doc['price'].value + (doc['discount'].value * 0.5)"<br /> }<br />

Saturation 函数


saturation 函数用于对字段值进行饱和处理,限制字段值对评分的影响范围。

<br /> "script": {<br /> "source": "saturation(doc['<field_name>'].value, <pivot>)"<br /> }<br />

  • <field_name>: 需要处理的字段。
  • <pivot>: 饱和点(pivot),当字段值达到该值时,评分增益趋于饱和。

    <br /> //在这个示例中,`likes` 字段的值在达到 `100` 后,对评分的影响会趋于饱和。<br /> {<br /> "query": {<br /> "script_score": {<br /> "query": {<br /> "match_all": {}<br /> },<br /> "script": {<br /> "source": "saturation(doc['likes'].value, 100)"<br /> }<br /> }<br /> }<br /> }<br />

    Sigmoid 函数


    sigmoid 函数用于对字段值进行 S 形曲线变换,平滑地调整字段值对评分的影响。

    <br /> "script": {<br /> "source": "sigmoid(doc['<field_name>'].value, <pivot>, <exponent>)"<br /> }<br />

  • 需要处理的字段。
  • 中心点(pivot),S 形曲线的中点。
  • 指数,控制曲线的陡峭程度。

    ```
    //在这个示例中,`likes` 字段的值在 `50` 附近对评分的影响最为显著,而随着值远离 `50`,影响会逐渐平滑。
    {
    "query": {
    "script_score": {
    "query": {
    "match_all": {}
    },
    "script": {
    "source": "sigmoid(doc['likes'].value, 50, 0.5)"
    }
    }
    }
    }
    ```

    #### 距离衰减函数

    用于衰减计算地理位置的函数。

    ```
    //相关函数
    double decayGeoLinear(String originStr, String scaleStr, String offsetStr, double decay, GeoPoint docValue)
    double decayGeoExp(String originStr, String scaleStr, String offsetStr, double decay, GeoPoint docValue)
    double decayGeoGauss(String originStr, String scaleStr, String offsetStr, double decay, GeoPoint docValue)


    "script" : {
    "source" : "decayGeoExp(params.origin, params.scale, params.offset, params.decay, doc['location'].value)",
    "params": {
    "origin": "40, -70.12",
    "scale": "200km",
    "offset": "0km",
    "decay" : 0.2
    }
    }
    ```

    #### 数值衰减函数

    用于衰减计算数值的函数。

    ```
    //相关函数
    double decayNumericLinear(double origin, double scale, double offset, double decay, double docValue)
    double decayNumericExp(double origin, double scale, double offset, double decay, double docValue)
    double decayNumericGauss(double origin, double scale, double offset, double decay, double docValue)

    "script" : {
    "source" : "decayNumericLinear(params.origin, params.scale, params.offset, params.decay, doc['dval'].value)",
    "params": {
    "origin": 20,
    "scale": 10,
    "decay" : 0.5,
    "offset" : 0
    }
    }
    ```

    #### 日期衰减函数

    用于衰减计算日期的函数。

    ```
    //相关函数
    double decayDateLinear(String originStr, String scaleStr, String offsetStr, double decay, JodaCompatibleZonedDateTime docValueDate)
    double decayDateExp(String originStr, String scaleStr, String offsetStr, double decay, JodaCompatibleZonedDateTime docValueDate)
    double decayDateGauss(String originStr, String scaleStr, String offsetStr, double decay, JodaCompatibleZonedDateTime docValueDate)

    "script" : {
    "source" : "decayDateGauss(params.origin, params.scale, params.offset, params.decay, doc['date'].value)",
    "params": {
    "origin": "2008-01-01T01:00:00Z",
    "scale": "1h",
    "offset" : "0",
    "decay" : 0.5
    }
    }
    ```

    #### 随机函数

    用于生成随机评分。
    _randomNotReproducible`_ 生成一个随机评分。

    ```
    "script" : {
    "source" : "randomNotReproducible()"
    }
    ```

    _randomReproducible_ 使用种子值生成可重复的随机评分。

    ```
    "script" : {
    "source" : "randomReproducible(Long.toString(doc['_seq_no'].value), 100)"
    }
    ```

    #### 字段值因子

    用于根据字段值调整评分。
    _field_value_factor`_ 根据字段值调整评分。

    ```
    "script" : {
    "source" : "Math.log10(doc['field'].value * params.factor)",
    params" : {
    "factor" : 5
    }
    }
    ```

    #### 其他实用函数

  • Math.log:计算对数,Math.log(doc['price'].value)
  • Math.sqrt:计算平方根,Math.sqrt(doc['popularity'].value)
  • Math.pow:计算幂次,Math.pow(doc['score'].value, 2)

    同义词字段重加载


    Elasticsearch 7.3 引入了同义词字段重加载功能,允许用户在更新同义词文件后,无需重新索引即可使更改生效。
    这一功能极大地简化了同义词管理的流程,尤其是在需要频繁更新同义词的场景下。通过 _reload_search_analyzers API,用户可以重新加载指定索引的分词器,从而使新的同义词规则立即生效。
    注意,虽然同义词词典能被热加载,但是已经生成的索引数据不会被修改。

    测试代码

    <br /> PUT /my_index<br /> {<br /> "settings": {<br /> "index" : {<br /> "analysis" : {<br /> "analyzer" : {<br /> "my_synonyms" : {<br /> "tokenizer" : "whitespace",<br /> "filter" : ["synonym"]<br /> }<br /> },<br /> "filter" : {<br /> "synonym" : {<br /> "type" : "synonym_graph",<br /> "synonyms_path" : "analysis/synonym.txt",<br /> "updateable" : true<br /> }<br /> }<br /> }<br /> }<br /> },<br /> "mappings": {<br /> "properties": {<br /> "text": {<br /> "type": "text",<br /> "analyzer" : "standard",<br /> "search_analyzer": "my_synonyms"<br /> }<br /> }<br /> }<br /> }<br /> <br /> POST /my_index/_reload_search_analyzers<br />

    执行上述请求后,Elasticsearch 会重新加载 my_index 索引的分析器,使最新的同义词规则生效。

    case insensitive 参数


    case_insensitive 参数允许用户在执行精确匹配查询时忽略大小写。
    这一功能特别适用于需要处理大小写不敏感数据的场景,例如用户名、标签或分类代码等。通过设置 case_insensitivetrue,用户可以在不修改数据的情况下,实现对大小写不敏感的查询,从而简化查询逻辑并提高搜索的准确性。

    测试代码

    <br /> //在这个示例中,`term` 查询会匹配 `user` 字段值为 `JohnDoe`、`johndoe` 或 `JOHNDOE` 的文档,而忽略大小写差异。<br /> {<br /> "query": {<br /> "term": {<br /> "user": {<br /> "value": "JohnDoe",<br /> "case_insensitive": true<br /> }<br /> }<br /> }<br /> }<br />

    小结


    Elasticsearch 作为一款强大的开源搜索和分析引擎,其版本的不断迭代带来了诸多显著的改进与优化。对比 Elasticsearch 6.8,Elasticsearch 7.10 在多个方面展现出了新的功能和特性,极大地提升了用户体验和系统性能。这系列文章简短的介绍了各个方面的新功能和优化,希望能给大家一定的帮助。

    推荐阅读


  • [谈谈 ES 6.8 到 7.10 的功能变迁(1)- 性能优化篇](https://infinilabs.cn/blog/202 ... part-1)
  • [谈谈 ES 6.8 到 7.10 的功能变迁(2)- 字段类型篇](https://infinilabs.cn/blog/202 ... part-2)
  • [谈谈 ES 6.8 到 7.10 的功能变迁(3)- 查询方法篇](https://infinilabs.cn/blog/202 ... part-3)
  • [谈谈 ES 6.8 到 7.10 的功能变迁(4)- 聚合功能篇](https://infinilabs.cn/blog/202 ... part-4)
  • [谈谈 ES 6.8 到 7.10 的功能变迁(5)- 任务和集群管理](https://infinilabs.cn/blog/202 ... part-5)

    关于极限科技(INFINI Labs)


    ![INFINI Labs](https://infinilabs.cn/img/blog ... bs.png)

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

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

    官网:<https://infinilabs.cn>;

    作者:金多安,极限科技(INFINI Labs)搜索运维专家,Elastic 认证专家,搜索客社区日报责任编辑。一直从事与搜索运维相关的工作,日常会去挖掘 ES / Lucene 方向的搜索技术原理,保持搜索相关技术发展的关注。
    原文:https://infinilabs.cn/blog/202 ... rt-6/