Observability:识别生成式 AI 搜索体验中的慢速查询

news2025/2/27 17:06:52

作者:Philipp Kahr

Elasticsearch Service 用户的重要注意事项:目前,本文中描述的 Kibana 设置更改仅限于 Cloud 控制台,如果没有我们支持团队的手动干预,则无法进行配置。 我们的工程团队正在努力消除对这些设置的限制,以便我们的所有用户都可以启用内部 APM。 本地部署不受此问题的影响。 

不久前,我们在 Elasticsearch® 中引入了检测,让你能够识别它在幕后所做的事情。 通过在 Elasticsearch 中进行追踪,我们获得了前所未有的见解。

当我们想要利用 Elastic 的学习稀疏编码器模型进行语义搜索时,本博客将引导你了解各种 API 和 transaction。 该博客本身可以应用于 Elasticsearch 内运行的任何机器学习模型- 你只需相应地更改命令和搜索即可。 本指南中的说明使用我们的稀疏编码器模型(请参阅文档)。

对于以下测试,我们的数据语料库是 OpenWebText,它提供大约 40GB 的纯文本和大约 800 万个单独的文档。 此设置在具有 32GB RAM 的 M1 Max Macbook 上本地运行。 以下任何交易持续时间、查询时间和其他参数仅适用于本博文。 不应对生产用途或你的安装进行任何推断。

让我们动手吧!

在 Elasticsearch 中激活跟踪是通过静态设置(在 elasticsearch.yml 中配置)和动态设置来完成的,动态设置可以在运行时使用 PUT _cluster/settings 命令进行切换(动态设置之一是采样率)。 某些设置可以在 runtime 时切换,例如采样率。 在elasticsearch.yml中,我们要设置以下内容:

tracing.apm.enabled: true
tracing.apm.agent.server_url: "url of the APM server"

秘密令牌(或 API 密钥)必须位于 Elasticsearch 密钥库中。 使用以下命令 elasticsearch-keystore add Tracing.apm.secret_token 或 tracing.apm.api_key ,密钥库工具应该可以在 <你的 elasticsearch 安装目录>/bin/elasticsearch-keystore 中使用。 之后,你需要重新启动 Elasticsearch。 有关跟踪的更多信息可以在我们的跟踪文档中找到。

激活后,我们可以在 APM 视图中看到 Elasticsearch 自动捕获各种 API 端点。 GET、POST、PUT、DELETE 调用。 整理好之后,让我们创建索引:

PUT openwebtext-analyzed
{
  "settings": {
    "number_of_replicas": 0,
    "number_of_shards": 1,
    "index": {
      "default_pipeline": "openwebtext"
    }
  },
  "mappings": {
    "properties": {
      "ml.tokens": {
        "type": "rank_features"
      },
      "text": {
        "type": "text",
        "analyzer": "english"
      }
    }
  }
}

这应该给我们一个名为 PUT /{index} 的单个 transaction。 正如我们所看到的,当我们创建索引时发生了很多事情。 我们有创建调用,我们需要将其发布到集群状态并启动分片。

我们需要做的下一件事是创建一个摄取管道 —— 我们称之为 openwebtext。 管道名称必须在上面的索引创建调用中引用,因为我们将其设置为默认管道。 这可确保如果请求中未指定其他管道,则针对索引发送的每个文档都将自动通过此管道运行。

PUT _ingest/pipeline/openwebtext
{
  "description": "Elser",
  "processors": [
    {
      "inference": {
        "model_id": ".elser_model_1",
        "target_field": "ml",
        "field_map": {
          "text": "text_field"
        },
        "inference_config": {
          "text_expansion": {
            "results_field": "tokens"
          }
        }
      }
    }
  ]
}

我们得到一个 PUT /_ingest/pipeline/{id} transaction。 我们看到集群状态更新和一些内部调用。 至此,所有准备工作都已完成,我们可以开始使用 openwebtext 数据集运行批量索引。

在开始批量摄入之前,我们需要启动 ELSER 模型。 转到 “Maching Learning(机器学习)”、“Trained Models(训练模型)”,然后单击 “Play(播放)”。 你可以在此处选择分配和线程的数量。

模型启动被捕获为 POST /_ml/trained_models/{model_id}/deployment/_start。 它包含一些内部调用,可能不如其他事务那么有趣。

现在,我们想通过运行以下命令来验证一切是否正常。 Kibana 开发工具有一个很酷的小技巧,你可以在文本的开头和结尾使用三引号(如”””),告诉 Kibana® 将其视为字符串并在必要时转义。 不再需要手动转义 JSON 或处理换行符。 只需输入你的文字即可。 这应该返回一个文本和一个显示所有令牌的 ml.tokens 字段。 

POST _ingest/pipeline/openwebtext/_simulate
{
  "docs": [
    {
      "_source": {
        "text": """This is a sample text"""
      }
    }
  ]
}

此调用也被捕获为 transaction POST _ingest/pipeline/{id}/_simulate。 有趣的是,我们看到推理调用花费了 338 毫秒。 这是模型创建向量所需的时间。

Bulk 摄入

openwebtext 数据集有一个文本文件,代表 Elasticsearch 中的单个文档。 这个相当 hack 的 Python 代码读取所有文件并使用简单的批量助手将它们发送到 Elasticsearch。 请注意,你不想在生产中使用它,因为它以序列化方式运行,因此速度相对较慢。 我们有并行批量帮助程序,允许你一次运行多个批量请求。

import os
from elasticsearch import Elasticsearch, helpers

# Elasticsearch connection settings
ES_HOST = 'https://localhost:9200'  # Replace with your Elasticsearch host
ES_INDEX = 'openwebtext-analyzed'  # Replace with the desired Elasticsearch index name

# Path to the folder containing your text files
TEXT_FILES_FOLDER = 'openwebtext'

# Elasticsearch client
es = Elasticsearch(hosts=ES_HOST, basic_auth=('elastic', 'password'))

def read_text_files(folder_path):
    for root, _, files in os.walk(folder_path):
        for filename in files:
            if filename.endswith('.txt'):
                file_path = os.path.join(root, filename)
                with open(file_path, 'r', encoding='utf-8') as file:
                    content = file.read()
                    yield {
                        '_index': ES_INDEX,
                        '_source': {
                            'text': content,
                        }
                    }

def index_to_elasticsearch():
    try:
        helpers.bulk(es, read_text_files(TEXT_FILES_FOLDER), chunk_size=25)
        print("Indexing to Elasticsearch completed successfully.")
    except Exception as e:
        print(f"Error occurred while indexing to Elasticsearch: {e}")

if __name__ == "__main__":
    index_to_elasticsearch()

我们看到这 25 个文档需要 11 秒才能被索引。 每次摄取管道调用推理处理器(进而调用机器学习模型)时,我们都会看到该特定处理器需要多长时间。 在本例中,大约需要 500 毫秒 — 25 个文档,每个文档约 500 毫秒,总共需约 12.5 秒来完成处理。 一般来说,这是一个有趣的观点,因为较长的文件可能会花费更多的时间,因为与较短的文件相比,需要分析的内容更多。 总体而言,整个批量请求持续时间还包括返回给 Python 代理的答案以及 “确定” 索引。 现在,我们可以创建一个仪表板并计算平均批量请求持续时间。 我们将在 Lens 中使用一些小技巧来计算每个文档的平均时间。 我会告诉你如何做。

首先,在事务中捕获了一个有趣的元数据 - 该字段称为 labels.http_request_headers_content_length。 该字段可能被映射为关键字,因此不允许我们运行求和、求平均值和除法等数学运算。 但由于运行时字段,我们不介意这一点。 我们可以将其转换为 Double。 在 Kibana 中,转到包含 traces-apm 数据流的数据视图,并执行以下操作作为值:

emit(Double.parseDouble($('labels.http_request_headers_content_length','0.0')))

如果该字段不存在和/或丢失,则将现有值作为 Double 发出(emit),并将报告为 0.0。 此外,将格式设置为 Bytes。 这将使它自动美化! 它应该看起来像这样:

创建一个新的仪表板,并从新的可视化开始。 我们想要选择指标可视化并使用此 KQL 过滤器:data_stream.type: "traces" AND service.name: "elasticsearch" AND transaction.name: "PUT /_bulk"。 在数据视图中,选择包含 traces-apm 的那个,与我们在上面添加字段的位置基本相同。 单击 Prmary metricfomula: 

sum(labels.http_request_headers_content_length_double)/(count()*25)

由于我们知道每个批量请求包含 25 个文档,因此我们只需将记录数(transaction 数)乘以 25,然后除以字节总和即可确定单个文档有多大。 但有一些注意事项 - 首先,批量请求会产生开销。 批量看起来像这样:

{ "index": { "_index": "openwebtext" }
{ "_source": { "text": "this is a sample" } }

对于要索引的每个文档,你都会获得 JSON 中的第二行,该行会影响总体大小。 更重要的是,第二个警告是压缩。 当使用任何压缩时,我们只能说 “这批文档的大小为 x”,因为压缩的工作方式会根据批量内容而有所不同。 当使用高压缩值时,我们发送 500 个文档时可能会得到与现在发送 25 个文档相同的大小。 尽管如此,这是一个有趣的指标。

 

我们可以使用 transaction.duration.us 提示! 将 Kibana 数据视图中的格式更改为 Duration 并选择 microseconds,确保其渲染良好。 很快,我们可以看到,批量请求的平均大小约为 125kb,每个文档约为 5kb,耗时 9.6 秒,其中 95% 的批量请求在 11.8 秒内完成。

 

查询时间!

现在,我们已经对许多文档建立了索引,终于准备好对其进行查询了。 让我们执行以下查询:

GET /openwebtext/_search
{
   "query":{
      "text_expansion":{
         "ml.tokens":{
            "model_id":".elser_model_1",
            "model_text":"How can I give my cat medication?"
         }
      }
   }
}

我正在向 openwebtext 数据集询问有关给我的猫喂药的文章。 我的 REST 客户端告诉我,整个搜索(从开始到解析响应)花费了:94.4 毫秒。 响应中的语句为 91 毫秒,这意味着在 Elasticsearch 上的搜索花费了 91 毫秒(不包括一些内容)。 现在让我们看看 GET /{index}/_search transaction。

我们可以发现,机器学习(基本上是动态创建令牌)的影响占总请求的 74 毫秒。 是的,这大约占整个交易持续时间的 3/4。 有了这些信息,我们就可以就如何扩展机器学习节点以缩短查询时间做出明智的决策。

结论

这篇博文向你展示了将 Elasticsearch 作为仪表化应用程序并更轻松地识别瓶颈是多么重要。 此外,你还可以使用事务持续时间作为异常检测的指标,为你的应用程序进行 A/B 测试,并且再也不用怀疑 Elasticsearch 现在是否感觉更快了。 你有数据支持这一点。 此外,这广泛地关注了机器学习方面的问题。 查看一般慢日志查询调查博客文章以获取更多想法。

仪表板和数据视图可以从我的 Github 存储库导入。

原文:Identify slow queries in generative AI search experiences | Elastic Blog

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

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

相关文章

【产品人卫朋】专栏及配套资料更新:华为流程体系、产品经理、IPD与BLM模型

目录 前言 01 华为流程体系专栏 CSDN学院 02 产品经理进阶专栏 CSDN学院 03 华为战略方法论专栏 04 IPD 进阶 100 例专栏 作者介绍 前言 截止目前&#xff0c;本号已上线四大干货专栏&#xff0c;内容涉及&#xff1a; 01 华为流程体系&#xff08;图文视频&#xff0…

为什么DNS协议运行在UDP之上?

DNS (Domain Name System) 运行在 UDP (User Datagram Protocol) 上主要是出于以下原因&#xff1a; 简单性和效率&#xff1a;UDP 是无连接的&#xff0c;这意味着与建立和维护 TCP 连接相比&#xff0c;UDP 有更少的开销。当 DNS 查询被发送时&#xff0c;它只需要一个小的请…

MRO工业品采购过程中,采购人员要注意哪些事项

MRO工业品指工厂或企业对其生产和工作设施、设备进行保养、维修&#xff0c;保证其运行所需要的非生产性物料&#xff0c;这些物料可能是用于设备保养、维修的备品备件&#xff0c;也可能是保证企业正常运行的相关设备&#xff0c;耗材等物资&#xff0c;如安全防护、传媒广电、…

那些年的Android开发经验记录

Android Studio 新版Logcat 从惊艳到放弃 AS总算更新了这个logcat了&#xff0c;原来的logcat真是使用起来贼难受&#xff0c;动不动过滤就失效&#xff0c;或者日志不打印&#xff0c;新版的logcat初步使用下来&#xff0c;那是贼舒服&#xff0c;先上一张界面图 一眼看…

金蝶云星空与四化智造MES(API)对接集成供应商查询连通新增供应商信息(BASIC-KM同步供应商-TEST)

金蝶云星空与四化智造MES&#xff08;API&#xff09;对接集成供应商查询连通新增供应商信息(BASIC-KM同步供应商-TEST) 来源系统:金蝶云星空 金蝶K/3Cloud&#xff08;金蝶云星空&#xff09;是移动互联网时代的新型ERP&#xff0c;是基于WEB2.0与云技术的新时代企业管理服务平…

Java反射机制,动态代理,hook以及在Retrofit源码中的应用

1.反射的基础知识&#xff1a; Java的反射机制是指在程序的运行状态中&#xff0c;可以构造任意一个类的对象&#xff0c;可以了解任意一个对象所属的类&#xff0c;可以了解任意一个类的成员变量和方法&#xff0c;可以调用任意一个对象的属性和方法。这种动态获取程序信息以及…

STM32CubeMX安装教程

0.前言 安装步骤&#xff1a; 参考&#xff1a;【STM32】STM32 CubeMx使用教程一--安装教程_Z小旋的博客-CSDN博客 JRE(Java Runtime Environment)&#xff1a;Java运行环境STM32CubeMXHAL库&#xff1a;STM32 HAL固件库 1. 安装Java 官网&#xff1a;https://www.java.co…

DNS部署与安全详解(下)

文章目录 前言一、指定区域解析配置二、DNS服务器对外名称显示配置三、转发器使用配置四、配置辅助&#xff08;备份&#xff09;服务器五、如何让虚拟机可以真实上网六、为DNS服务器配置别名 前言 上一篇博客我们已经在Windows server2003的虚拟机上下载了DNS软件&#xff0c;…

IDEA 实用小技巧(Scratch files(临时文件))

当你在使用IDEA编写项目代码的时候&#xff0c;是否遇到过如下一些情况&#xff1f; 1. 与别人沟通&#xff0c;需要简写某个功能的伪代码 2. 想记录一些json格式的数据&#xff0c;并且能格式化&#xff0c;即JSON文档功能 3. 想记录一些其他语言例如HTML&#xff0c;CSS&a…

SAP 批量CC11 创建物料版本(RFC:REVISION_LEVEL_INSERT)

REVISION_LEVEL_INSERT FLG_API ‘X’ 就不弹框 不直接报message 需要commit work &#xff0c;里面有句代码 perform db_insert on commit 输入输出参数如下 输入&#xff1a; 输出&#xff1a; COMMIT 后再看MM03

java实现文件的下载

系统日志的获取不可能每次都登录服务器&#xff0c;所以在页面上能够下载系统运行的日志是必须的 如何来实现日志的下载&#xff0c;这样的一个功能 前端我们用到的是window.open(...)这样可以发送一个get请求到后台 后台接收到get请求之后&#xff0c;如何实现对文件的下载 R…

mac arm 通过brew搭建 php+nginx+mysql+xdebug

1.安装nginx brew install nginx //安装brew services start nginx //启动2.安装php brew install php7.4 //安装export PATH"/opt/homebrew/opt/php7.4/bin:$PATH" //加入环境变量 export PATH"/opt/homebrew/opt/php7.4/sbin:$PATH"brew serv…

EXPLAIN使用分析

系列文章目录 文章目录 系列文章目录一、type说明二、MySQL中使用Show Profile1.查看当前profiling配置2.在会话级别修改profiling配置3.查看profile记录4.要深入查看某条查询执行时间的分布 一、type说明 我们只需要注意一个最重要的type 的信息很明显的提现是否用到索引&…

matplotlib 设置legend的位置在轴最上方,长度与图的长度相同

import matplotlib.pyplot as plt import numpy as npx1 np.linspace(0, 10, 50) x2 [6,4,3]ax plt.subplot() ax.plot(x1, label"test1") ax.plot(x2, label"test2") # 设置图例的位置 # 将左下角放置在【0, 1.02】位置处&#xff0c;横为1&#xff0c…

MySQL——Mysql安装教程- Windows

一、Mysql安装 1、下载mysql安装包 下载链接&#xff1a; 链接&#xff1a; https://pan.baidu.com/s/1rFpMqOCApiQQEwYSs9XSmg https://pan.baidu.com/s/1rFpMqOCApiQQEwYSs9XSmg 提取码&#xff1a;zt88 2、 安装 1&#xff09;选择电脑磁盘空闲的路径&#xff1a; 2&…

解决error: incompatible type for argument 1 of ‘************’报错

运行程序时出现以下错误&#xff1a; 问题分析&#xff1a;但凡出现error: incompatible type for argument 1 of ‘函数名’几乎都是该函数的参数类型不匹配导致的&#xff1b;所以检查并纠正函数参数类型即可

JUC线程池的实战问题 - 线程池参数应该如何配置?

Oracle 官方并没有给出线程池 corePoolSize 的具体参考值&#xff0c;因为这个值的大小应该根据实际业务场景和系统资源情况来进行优化调整。不同的业务场景和系统资源状况可能需要不同的 corePoolSize 设置。 在《Java并发编程实战》一书中&#xff0c;作者 Brian Goetz 等人…

试卷擦除答案的工具,几个步骤轻松搞定

在学生的学习生活中&#xff0c;考试是必不可少的一部分。然而&#xff0c;有时候我们在做完试卷后发现自己填错了答案&#xff0c;或者想要更改答案&#xff0c;但是试卷上已经有了痕迹。这时候&#xff0c;我们就需要一些工具来擦除答案。以下是几个简单的步骤&#xff0c;让…

[每周一更]-(第58期):选购佳能变焦镜头 EF-S 18-200mm F/3.5-5.6 IS的心得

参考地址&#xff1a; https://www.canon.com.cn/purchase/onlinesale/index3.html?typejdhttps://www.canon.com.cn/overview/efwidezoom.html 讲在买之前 由于没有买全画幅&#xff0c;买了残幅&#xff0c;好处是能选的镜头有限&#xff0c;不用太费钱了&#xff0c;需要…

C和C++的区别(6)字符串

目录 一&#xff0c;字符 二&#xff0c;C语言字符串 1&#xff0c;字符串的表示 2&#xff0c;输入输出 3&#xff0c;常用函数 三&#xff0c;string类 1&#xff0c;定义&#xff0c;初始化&#xff0c;输入输出 一&#xff0c;字符 类型&#xff1a;char 输入&…