使用 SpiceDB 为 Elasticsearch 检索增强生成实现细粒度授权

作者:来自 Elastic Sohan Maheshwar, Carly Richmond

工程部门第一次与销售部门共享文档时,部门筛选机制就会失效,因此,在你的 Elasticsearch 检索增强生成 流程将检索到的内容块传递给大语言模型之前,SpiceDB 会根据关系图逐一检查每个内容块。

通过这个面向搜索 人工智能 的自主式实践学习(self-paced hands-on learning),亲自尝试向量搜索。你现在就可以开始免费云试用(free cloud trial),或在本地计算机(local machine)上试用 Elastic。


你可以使用 SpiceDB 在关系图中实现细粒度授权。授权逻辑不应放在你的 k 近邻(kNN)查询中,更不应放在应用程序代码中。Elasticsearch 根据相关性检索内容,然后在大语言模型(large language model)看到这些内容之前,根据关系图检查每个内容块。共享文档只需写入一条关系,撤销共享只需删除一条关系,两者都不会改动索引。授权本身在一个确定性的 LangGraph 节点中执行,agent 无法绕过该节点,因为模型可能被诱导,在本不应授予访问权限时授予权限。

为什么粗粒度权限在检索增强生成流程中会失效

细粒度访问控制可能很难实现。例如,假设你已经基于 Elasticsearch,为内部知识库构建了一套检索增强生成(retrieval augmented generation)流程。需求相对直接:一个人工智能聊天机器人前端,从十万份经过分块并转换为 dense_vector 嵌入表示(embeddings)的文档中检索答案。权限也相当简单,只需在 kNN 查询中使用一个 department 关键字筛选条件。

现实需求往往复杂得多。也许工程团队只想与销售团队共享一份架构文档,而某位高管需要获得特殊授权,以访问其部门之外的一份文档。你会如何在检索增强生成流程中解决这些问题?

权宜之计很快就会变得难以管理。你可以为每个请求创建一个新的 department,但这会导致角色数量激增,而且系统一有变化,这些角色就会过时。你也可以添加大量条件分支语句,但这并不是个好主意。将安全决策编码到既难以审计、又难以扩展的应用程序代码中,是引发数据泄露的原因之一,也是你应该防范的做法。对于企业以及金融、公共部门等受合规监管的行业,这一点尤其重要。

最新的开放式网络应用程序安全项目大语言模型风险清单(OWASP list for LLM risks)指出了多种普遍存在于行业中、专门针对 大语言模型 应用程序的漏洞,包括:

  • 敏感信息泄露。
  • 过度代理权限。
  • 向量与嵌入弱点。

那么,如何为你的检索增强生成流程添加细粒度权限?答案在于基于关系的访问控制。

迈向基于关系的访问控制的未来:基于关系的访问控制如何运作

2019 年,谷歌发表了《Zanzibar:谷歌的一致性全球授权系统》(Zanzibar: Google's Consistent, Global Authorization System),介绍了支撑谷歌数百项服务的授权系统,包括日历、云端硬盘、地图、相册和 YouTube。如果你使用过这些服务,你的请求很可能已经接受过 Zanzibar 的检查。

这篇论文在身份与访问管理领域引起了轰动。它也被广泛认为推动了基于关系的访问控制的普及,这种方式有别于当时大多数团队使用的模型,包括基于角色的访问控制和限定作用域的令牌。

基于关系的访问控制的核心思想是:权限由_主体_(用户、 agent 、群组)与_资源_(文档、文件夹、项目)之间的_关系_决定。你可以将这些关系存储为一张图:节点代表对象,边代表 "查看者" "编辑者" 或 "所有者" 等关系。这样,权限检查就归结为一个问题:

这个操作主体(actor)是否有权对这个 资源(resource)执行这项操作(action)?

你通过检查图中是否存在一条路径来回答这个问题,无须将访问决策硬套进某个角色。

下面是一个实际示例。当 user:jordan 在谷歌文档中创建 document:somedocument 时,Zanzibar 会通过一个关系元组,记录乔丹是该文档的写入者:

document:somedocument#writer@user:jordan

如果乔丹随后将文档以只读权限共享给 user:alex,系统就会创建另一个元组:

document:somedocument#reader@user:alex

还有一条规则:每个写入者也都是读取者。从概念上看,Zanzibar 现在看到的关系图如下:

当 Jordan 尝试读取 somedocument 时,系统会查找一条从文档的 reader 关系指向乔丹的有向路径。虽然没有直接指向乔丹的 reader 边,但 reader 包含 writer,而乔丹是写入者。找到这条路径后,乔丹就可以读取文档。如果不存在这样的路径,乔丹就会看到那个让我们都头疼的"你需要访问权限"页面。

现在轮到你了。亚历克斯能_写入_同一份文档吗?

下次你在谷歌产品中打开(或无法打开)文件时,你就会知道幕后发生了什么。

这与我的检索增强生成流程有什么关系?

Zanzibar 的设计目标是针对按层级组织的机构数据,执行高吞吐量、低延迟的授权检查。事实证明,agent 和检索增强生成流程等人工智能应用恰好需要这种能力。回顾本文开头的需求,基于角色的访问控制或限定作用域的令牌等粗粒度方案,无法灵活支持逐文档共享或跨部门访问,也无法大规模处理个别例外授权。用户与其可访问资源之间的关系构成了一张不断演变的图,而这正是基于关系的访问控制所解决的问题。

但除非你在谷歌工作,否则你实际上无法使用 Zanzibar。幸运的是,它有开源实现。我们将使用 SpiceDB,它的名字源自《沙丘》中的名句:"香料必须流动/The spice must flow." 这里介绍的技术并非仅适用于检索增强生成;你也可以用它们为企业应用程序、人工智能 agent 以及其他任何你想保护的资源添加权限控制。

定义 SpiceDB 模式、关系和权限

顾名思义,基于关系的访问控制建立在系统中各对象之间的关系之上。因此,为应用程序添加权限控制时,第一步是定义 SpiceDB 模式。它描述了应用程序中的对象类型,以及这些对象之间可以建立怎样的关系。它还定义了从这些关系中派生的权限。对于我们的检索增强生成流程,模式如下:

markdown 复制代码
`

1.  definition user {}

3.  definition department {
4.      relation member: user
5.  }

7.  definition document {
8.      relation owner: user
9.      relation viewer: user | department#member

11.      permission view = viewer + owner
12.      permission edit = owner
13.  }

`AI代码解释![](https://csdnimg.cn/release/blogv2/dist/pc/img/runCode/icon-arrowwhite.png)

这里有不少内容需要逐一理解:

  • 三种对象类型分别是用户(user)、部门(department)和文档(document)。
  • 关系如下:
    • 用户(user)可以是部门(department)的成员(member)。
    • 用户(user)可以是文档(document)的所有者(owner)。
    • 用户(user)可以是文档(document)的查看者(viewer)。
  • 如果你是文档的查看者(viewer)或所有者(owner),就可以查看(view)该文档。查看者(viewer)权限可以通过两种方式授予:授予特定用户,_或_授予某个部门的所有成员(department#member)。
  • 只有文档(document)的所有者(owner)才能编辑(edit)它。

模式描述了系统的结构,而且很少发生变化。

在 SpiceDB 中,一个可运行的权限系统由模式和关系共同组成。_关系实例_是某种关系的具体实例。例如,"用户乔丹是文档 readme 的所有者/user jordan is an owner of document readme"可以写成以下关系元组:

document:readme#owner@user:jordan

如果你想表示 alice 属于 engineering,而且 engineering 中的所有人都可以查看 eng-arch-001,该怎么做?这同样只需通过关系来表达:

  • department:engineering#member@user:alice("爱丽丝是工程部门的成员。/Alice is a member of engineering.")
  • document:eng-arch-001#viewer@department:engineering#member("工程部门的每位成员都可以查看这份文档。/Every engineering member can view this doc.")

因此,当 alice 点击链接查看 eng-arch-001 时,SpiceDB 会按如下方式遍历关系图:

如果不存在路径,访问就会被拒绝。

这就是 SpiceDB 中权限检查的工作方式。在执行任何操作之前,你都要调用 CheckPermission 应用程序编程接口:

ini 复制代码
`

1.  from authzed.api.v1 import (
2.      CheckPermissionRequest,
3.      CheckPermissionResponse,
4.      Client,
5.      ObjectReference,
6.      SubjectReference,
7.  )
8.  from grpcutil import insecure_bearer_token_credentials

10.  client = Client("localhost:50051", insecure_bearer_token_credentials("devtoken"))

12.  response = client.CheckPermission(
13.      CheckPermissionRequest(
14.          resource=ObjectReference(object_type="document", object_id="eng-arch-001"),
15.          permission="view",
16.          subject=SubjectReference(
17.              object=ObjectReference(object_type="user", object_id="alice")
18.          ),
19.      )
20.  )
21.  allowed = (
22.      response.permissionship
23.      == CheckPermissionResponse.PERMISSIONSHIP_HAS_PERMISSION
24.  )

`AI代码解释![](https://csdnimg.cn/release/blogv2/dist/pc/img/runCode/icon-arrowwhite.png)

我们将在检索增强生成流程中使用同样的检查,确保用户获得的答案仅基于他们有权查看的数据。

访问规则变化时,写入关系而非角色

还记得我们的检索增强生成项目的需求是如何变化的吗?在基于角色的系统中,这意味着重构角色,或在代码中埋入更多授权逻辑。而使用基于关系的访问控制和 SpiceDB 时,每条新的访问规则都只是一条新的关系:

对比项 基于角色的访问控制/限定作用域的令牌(RBAC / scoped tokens) 使用 SpiceDB 的基于关系的访问控制(ReBAC with SpiceDB)
访问权限的表达方式 分配给用户的角色 主体与资源之间的关系
权限检查的问题 该用户是否拥有此角色? 图中是否存在路径?
为某个人授予一次性例外权限 新建角色 写入一条关系
与另一个团队共享 为每种组合新建角色 通过 department#member 写入一条关系
访问权限发生变化时 重构角色或修改筛选条件 写入或删除一条关系
逻辑所在位置 应用程序代码 SpiceDB

如果工程团队想与销售团队共享一份文档,你可以添加以下关系:

document:eng-arch-001#viewer@department:sales#member

你也可以为某位高管创建单独的例外授权,如下所示:

document:sales-proposal-001#viewer@user:ceo

在基于角色的访问控制中,你需要创建新角色或重写筛选条件,而在 SpiceDB 中,上述每项操作都只需调用一次 WriteRelationships。下面是与销售团队共享文档的示例:

markdown 复制代码
`

1.  from authzed.api.v1 import (
2.      ObjectReference,
3.      Relationship,
4.      RelationshipUpdate,
5.      SubjectReference,
6.      WriteRelationshipsRequest,
7.  )

9.  client.WriteRelationships(
10.      WriteRelationshipsRequest(
11.          updates=[
12.              RelationshipUpdate(
13.                  operation=RelationshipUpdate.Operation.OPERATION_TOUCH,
14.                  relationship=Relationship(
15.                      resource=ObjectReference(object_type="document", object_id="eng-arch-001"),
16.                      relation="viewer",
17.                      subject=SubjectReference(
18.                          object=ObjectReference(object_type="department", object_id="sales"),
19.                          optional_relation="member",
20.                      ),
21.                  ),
22.              )
23.          ]
24.      )
25.  )

`AI代码解释![](https://csdnimg.cn/release/blogv2/dist/pc/img/runCode/icon-arrowwhite.png)

这不需要创建新角色、修改代码或重新索引。OPERATION_TOUCH 使写入操作具有幂等性;也就是说,它会创建关系,如果关系已存在,则保持不变。

将 SpiceDB 接入你的 Elasticsearch 检索增强生成流程

让我们把这些整合起来。将内容块索引到 Elasticsearch 时,你会在每个嵌入向量旁存储元数据,标明它来自哪份文档。在我们的代码仓库中,这对应 doc_id 字段。它与 SpiceDB 用于 document 资源的标识符相同,也是连接这两个系统的纽带。

查询流程如下:

  1. 用户的查询经过嵌入模型(我们的代码仓库中使用 Mistral),生成查询嵌入向量。
  2. Elasticsearch 执行 k 近邻搜索,检索最相关的内容块。
  3. 在将文档传递给大语言模型之前,我们将每个内容块的 doc_id 和用户标识符发送给 SpiceDB。
  4. 根据已定义的规则,我们会丢弃所有被 SpiceDB 判定为用户无权查看的内容块。
  5. 获准访问的文档会被放入提示词中。对于基于 agent 的检索增强生成,相关文档会作为工具输出传递给大语言模型。

这种模式称为_检索后过滤授权_:先检索,再过滤。检查发生在内容传递给大语言模型之前,以确保未经授权的文档不会通过 上下文窗口 传入。这就是安全边界。任何传入模型的内容,都可能出现在它的回答中。

以下是代码仓库中的检索步骤(节选):

ini 复制代码
`

1.  # query_embedding comes from the Mistral embedding model
2.  response = es_client.search(
3.      index="documents",
4.      knn={
5.          "field": "embedding",
6.          "query_vector": query_embedding,
7.          "k": 5,
8.          "num_candidates": 50,
9.      },
10.      source=["doc_id", "title", "content"],
11.  )

13.  documents = [
14.      Document(
15.          page_content=hit["_source"]["content"],
16.          metadata={"doc_id": hit["_source"]["doc_id"], "title": hit["_source"]["title"]},
17.      )
18.      for hit in response["hits"]["hits"]
19.  ]

`AI代码解释![](https://csdnimg.cn/release/blogv2/dist/pc/img/runCode/icon-arrowwhite.png)

注意,查询中没有权限逻辑。Elasticsearch 查找相关内容,SpiceDB 决定谁有权查看。

接下来是授权步骤。下面是代码仓库中的 authorization_node。它将检索到的文档交给 langchain-spicedb 软件包中的 SpiceDBAuthorizer,后者通过一次 CheckBulkPermissions 调用,在 SpiceDB 中检查所有文档的访问权限:

python 复制代码
`

1.  async def authorization_node(state: AgenticRAGState) -> dict:
2.      """
3.      Deterministic authorization node - ALWAYS runs, cannot be bypassed.
4.      """
5.      authorizer = _get_authorizer()

7.      logger.info(
8.          "Starting authorization",
9.          extra={
10.              "subject_id": state["subject_id"],
11.              "document_count": len(state["retrieved_documents"]),
12.          },
13.      )

15.      result = await authorizer.filter_documents(
16.          documents=state["retrieved_documents"],
17.          subject_id=state["subject_id"],
18.      )

20.      logger.info(
21.          "Authorization results",
22.          extra={
23.              "authorized": result.total_authorized,
24.              "denied": len(result.denied_resource_ids),
25.              "denied_doc_ids": result.denied_resource_ids,
26.          },
27.      )

29.      return {
30.          "authorized_documents": result.authorized_documents,
31.          "denied_count": len(result.denied_resource_ids),
32.          "authorization_passed": result.total_authorized > 0,
33.          "messages": [
34.              SystemMessage(
35.                  content=f"Authorization: {result.total_authorized}/{result.total_retrieved} documents authorized"
36.              )
37.          ],
38.      }

`AI代码解释![](https://csdnimg.cn/release/blogv2/dist/pc/img/runCode/icon-arrowwhite.png)

_get_authorizer() 会一次性配置授权器,使用每份文档的 doc_id 元数据作为资源标识符,检查用户(user)主体对文档(document)资源的查看(view)权限。只有在 SpiceDB 中确认存在路径的文档,才会出现在返回的 result.authorized_documents 中。缺少 doc_id 的文档,或单项权限检查出错的文档,都会被丢弃。如果完全无法连接 SpiceDB,调用就会抛出异常,流程会在生成之前停止。

Elasticsearch 的文档级安全功能呢?

Elasticsearch 内置了文档级安全功能(Elasticsearch has document-level security built in),当访问权限可以通过针对文档字段的查询来表达时,例如 department: engineering,它就非常适用。当访问权限取决于引言中提到的关系,例如针对个别用户的例外授权或通过群组共享时,处理起来就会更加困难。其他例子还包括从文件夹和组织继承的访问权限。你必须将这张关系图反规范化,写入每份文档,并将其映射到已定义的基于角色的访问控制角色。每次共享关系发生变化时,你还必须重新索引。SpiceDB 将关系图集中保存在一处,并为你的检索增强生成流程、应用程序和 agent 提供一致的权限判断结果。

绝不要让 agent 决定是否授权

该流程遵循清晰的结构:检索 → 授权 → 生成(可包含推理循环),各步骤均构建为 LangGraph 节点。

核心规则很简单:agent 可以推理该检索什么或生成什么,甚至可以推理如何解释访问被拒绝的原因。但它绝不能推理_是否_需要执行授权检查。

大语言模型本质上具有概率性。如果由模型决定是否检查权限,精心构造的提示注入就可能诱导它跳过检查,从而泄露数据。权限强制执行逻辑位于模型之外的确定性节点中,agent 无法绕过该节点。该节点还必须在发生故障时默认拒绝访问。出现错误或不存在路径,都意味着无权访问。

下面展示了如何使用 LangGraph,通过入口、边和终点将这三个节点连接起来:

bash 复制代码
`

1.  from langgraph.graph import END, StateGraph

3.  workflow = StateGraph(AgenticRAGState)

5.  # Add nodes
6.  workflow.add_node("retrieve", retrieval_node)
7.  workflow.add_node("authorize", authorization_node)  # ALWAYS runs
8.  workflow.add_node("generate", generation_node)

10.  # Define flow - start directly at retrieval
11.  workflow.set_entry_point("retrieve")
12.  workflow.add_edge("retrieve", "authorize")  # Deterministic auth
13.  workflow.add_edge("authorize", "generate")
14.  workflow.add_edge("generate", END)

16.  graph = workflow.compile()

`AI代码解释![](https://csdnimg.cn/release/blogv2/dist/pc/img/runCode/icon-arrowwhite.png)

从 retrieve 到 generate 之间没有直接连接的边。通往大语言模型的唯一路径必须经过 authorize。代码仓库还添加了一个可选的 reason 节点用于重试(这就是 agent 发挥作用的部分),但每条路径仍然必须先经过授权检查。

每个 LangGraph 节点都只是一个函数。你在上一节中已经看过 authorization_node,下面是 generation_node:

python 复制代码
`

1.  def generation_node(state: AgenticRAGState) -> dict:
2.      """Generate final answer incorporating authorization context.

4.      This node creates the final response, ensuring transparency
5.      about what information was accessible and what was denied.
6.      """
7.      with log_node_execution(
8.          logger,
9.          "generation",
10.          {
11.              "subject_id": state["subject_id"],
12.              "authorized_count": len(state["authorized_documents"]),
13.              "denied_count": state["denied_count"],
14.          }
15.      ):
16.          llm = get_llm()

18.          # Format documents with clear boundaries
19.          if state["authorized_documents"]:
20.              doc_parts = []
21.              for i, doc in enumerate(state["authorized_documents"], 1):
22.                  doc_parts.append(
23.                      f"--- Document {i} ---\n"
24.                      f"Title: {doc.metadata['title']}\n"
25.                      f"Content: {doc.page_content}\n"
26.                      f"--- End Document {i} ---"
27.                  )
28.              docs_text = "\n\n".join(doc_parts)
29.          else:
30.              docs_text = "No authorized documents available."

32.          prompt = ChatPromptTemplate.from_messages(
33.              [
34.                  ("system", GENERATION_PROMPT),
35.              ]
36.          )

38.          chain = prompt | llm

40.          result = chain.invoke(
41.              {
42.                  "query": state["query"],
43.                  "authorized_count": len(state["authorized_documents"]),
44.                  "denied_count": state["denied_count"],
45.                  "documents": docs_text,
46.              }
47.          )

49.          logger.info(
50.              "Generated answer",
51.              extra={
52.                  "answer_length": len(result.content),
53.              },
54.          )

56.          return {
57.              "answer": result.content,
58.              "messages": [AIMessage(content=f"Answer: {result.content}")],
59.          }

`AI代码解释![](https://csdnimg.cn/release/blogv2/dist/pc/img/runCode/icon-arrowwhite.png)收起代码块![](https://csdnimg.cn/release/blogv2/dist/pc/img/arrowup-line-top-White.png)

生成节点只读取 authorized_documents,因此被拒绝的内容绝不会进入提示词。GENERATION_PROMPT 指示模型仅根据这些文档回答。它还会传递被拒绝的文档数量,让回答能够指出部分信息无法访问(而不是假装这些信息不存在)。切勿返回被拒绝文档的详细信息,因为这些细节可能泄露用户无权访问的信息。

将细粒度授权投入生产环境

如何从概念验证走向生产级实现?以下是我们的建议:

  • 通过超额检索弥补后置过滤造成的召回损失。(Overfetch to recover post-filter recall.) 后置过滤可能导致大语言模型缺乏足够的上下文。例如,用户询问"微服务模式",但排名前五的命中结果中,有四个指向其无权查看的文档,那么大语言模型就只能依据一份文档作答。解决方法是超额检索:检索 k × N 个候选结果(其中,k 是你希望获得的文档数量,N 是你调整的倍数),然后执行权限检查,保留通过检查的前 k 个结果。注意,超额检索可以提高获得足够结果的概率,但不能保证一定有 k 个结果通过检查。只有当新的 k 超过 num_candidates 时,才需要调整该参数;如果不设置,它默认采用 1.5 × k(未设置 k 时则采用 1.5 × size),并自动随之调整。候选数量参数的上限为 10,000(num_candidates is capped at 10,000),因此超额检索也有上限。如果用户只能查看语料库中极少的一部分,以至于所需候选数量超过此上限,SpiceDB 提供了 LookupResources 应用程序编程接口,可查找特定主体能够访问的某一类型的全部资源。它最适合结果集规模适中的情况:SpiceDB 文档提醒,结果数量超过约 10,000 后,开销会变得很高。在这种情况下,文档建议使用 CheckBulkPermissions 进行后置过滤。通常,你可以使用 LookupResources 获取用户可访问的文档标识符列表,然后将其作为词项预筛选条件,传入 k 近邻查询的 filter 参数(词项数量最多可达到 index.max_terms_count 的默认值 65,536)。

  • 添加粗粒度元数据预筛选条件。(Add a coarse-grained metadata pre-filter.) 授权很少是检索增强生成流程中的唯一约束。你可能还希望按部门、时间范围或分类限制结果。Elasticsearch 的 k 近邻查询会在向量搜索(vector search)过程中通过 filter 应用这些条件,避免让最终会被丢弃的文档占用前 k 个结果的名额。之后,SpiceDB 仍会作出细粒度权限判断:

bash 复制代码
`

1.  response = es_client.search(
2.      index="documents",
3.      knn={
4.          "field": "embedding",
5.          "query_vector": query_embedding,
6.          "k": 5,
7.          "num_candidates": 50,
8.          # Coarse pre-filter: this assistant never retrieves confidential docs
9.          "filter": {"terms": {"classification": ["public", "internal"]}},
10.      },
11.      source=["doc_id", "title", "content"],
12.  )

`AI代码解释![](https://csdnimg.cn/release/blogv2/dist/pc/img/runCode/icon-arrowwhite.png)
  • 让关系与权威数据源保持同步。(Keep relationships in sync with the source of truth.) 在代码仓库中,初始化脚本会预先填充关系;但在生产环境中,这些关系来自实际管理访问权限的系统,例如文档系统或人力资源目录,也可能来自身份提供商。共享文档或有人加入团队时,写入一条关系;撤销访问权限时,删除相应关系。由于权限保存在 SpiceDB 中,因此这些操作都不需要重新索引。

  • 部署 SpiceDB 和 Elasticsearch。(Deploy SpiceDB and Elasticsearch.) 代码仓库在本地 Docker 容器中运行 SpiceDB 和 Elasticsearch,其中 SpiceDB 将关系存储在内存中。生产环境中的 SpiceDB 部署需要 PostgreSQL 等持久化数据存储。你还需要选择运行 SpiceDB 的环境。目前主要有三种部署选项:

同样,Elasticsearch 也可以配套部署,采用 Elastic 云托管服务、Elastic 云无服务器服务(Serverless)或本地部署发行版,具体可参阅文档中列出的选项(options outlined in the documentation)。

Elasticsearch 负责检索,SpiceDB 负责授权

Elasticsearch 查找最相关的内容,SpiceDB 决定谁有权查看。确定性的授权节点确保用户获得的回答仅基于其有权访问的信息。

亲自尝试:

  1. 克隆示例代码仓库(sample repository),按照自述文件中的说明,使用 Docker Compose 启动 SpiceDB 和 Elasticsearch。
  2. 以两个不同用户的身份提出相同问题,比较各自得到的回答。
  3. 阅读带注释的 Zanzibar 论文(annotated Zanzibar paper)。

原文:Fine-grained authorization in Elasticsearch RAG with SpiceDB | Elasticsearch Labs

相关推荐
新*36 分钟前
ES 7.17 三节点 Docker 集群接入 IK 自定义词典:一次从丢插件到热更新的完整排障
运维·elasticsearch·docker·中文分词·ik分词
新*16 小时前
Elasticsearch 7.17 的 SQL 到底能查到什么?一次踩坑记录
后端·sql·elasticsearch·查询
Elastic 中国社区官方博客2 天前
更少的位数,相同的召回率:DiskBBQ 更保守的自动校准扫描
大数据·运维·开发语言·人工智能·elasticsearch·搜索引擎
Elasticsearch2 天前
Kibana 中的人工智能连接器:你的 agent 可调用的 90 多个数据源
elasticsearch
Elasticsearch3 天前
更少的位数,相同的召回率:DiskBBQ 更保守的自动校准扫描
elasticsearch
瑞克-桑切斯4 天前
docker Harbor 单机部署手册
大数据·运维·elasticsearch·docker·容器
Elasticsearch6 天前
对 OpenTelemetry Kafka 接收器的两项改动,避免一个缓慢的租户拖住其他租户
elasticsearch
全栈陈序员7 天前
Git】从入门到精通(八)—— git log:查看提交历史
大数据·git·elasticsearch
Percep_gan7 天前
Linux中安装gitea,很详细
linux·elasticsearch·gitea