Elasticsearch:语义搜索即服务处于卓越搜索的中心

作者:来自 Elastic Sherry Ger, Stephen Brown

对于许多企业来说,搜索卓越中心(center of excellence - COE)向其用户提供搜索服务,从不同的数据源中整理知识,并将搜索功能集成到其内部和外部应用程序中。Elasticsearch,这个 “支撑着互联网上大约 90% 的搜索栏” 的分布式搜索平台,通常是企业搜索 COE 的首选工具。随着 ChatGPT 的广泛流行,用户发现 LLM(大型语言模型)具有抓住含义的神奇能力。这引发了对企业搜索 COE 提供增强型搜索体验的迫切需求:一种直观、自然、上下文驱动且能轻松识别用户意图的搜索体验。Elasticsearch,最受欢迎的向量数据库,支持规模化的全向量搜索,并与基于转换器的 LLM 原生集成;Elasticsearch 相关性引擎(ESRE)使搜索 COE 能够支持安全、可扩展且高性能的企业级语义搜索。

在这个两部分的博客中,我们将探讨如何使用 Elastic Learned Sparse EncodeR(ELSER)来实现并扩展搜索 COE 的语义搜索服务,ELSER 是 Elastic 训练的一个后交互模型,能够提供开箱即用的语义搜索能力,无需任务特定的微调。我们将在博客的第一部分中探讨在为开发人员提供内部 wiki 文章的语义搜索的用例,实施此过程以及从中获得的经验教训,重点关注以下领域:

  • 模型选择 - model selection
  • 模式设计 - schem design
  • 数据摄入 - data ingestion
  • 访问控制 - access control
  • 搜索技术 - search techniques

备注:此博客的所有代码和内容都可以在这里找到。

在博客的下一部分中,我们将调查使用 Elastic Search 应用程序向开发人员扩展搜索服务的情况。

模型选择

实现语义搜索的第一个任务是选择一个嵌入模型,该模型应具备以下特点:

  • 将文本及其含义转换为数值向量表示
  • 适用于你的用例

有许多可选项,包括商业模型如 OpenAI、Cohere 和 Anthropic,以及 HuggingFace 上托管的开源模型,例如 Mistral 7B 或 Llama 2。此外,许多企业拥有自己的数据科学团队,他们已经使用内部数据微调了自己的 LLM 模型。

选择现有的 LLM 用于搜索 COE 的挑战在于该模型可能已经在特定领域的数据集上进行了训练。通常情况下,搜索 COE 必须满足各种各样的用例,并且可能没有数据科学资源来对基础模型进行领域适应。

Elastic Learned Sparse EncodeR(ELSER)是一种检索模型,专为开箱即用用例设计,因此对于优先考虑灵活性、速度和简化实施的搜索 COE 来说,选择它是一个很容易的选择。对于本博客,我们将使用 ELSER 来处理我们的用例,因为我们只处理英文文档,并且可以通过单击在 Elasticsearch 中部署该模型。对于多语言向量搜索,Elasticsearch 提供了类似的一键支持,支持 E5 嵌入模型。

下图描述了向量搜索的基础知识。语义搜索是向量搜索的一个子集,因为我们只关注文本。

模式设计

对于我们的用例来说,一个 “必须具备” 的功能是根据用户查询返回文章中最相关的段落,以及元数据、原始文档的 URL、发布和更新日期以及 wiki 的来源。文档的长度不一,往往超过 ELSER 模型的最大输入令牌限制(512),需要将文本 “分块” 以避免截断。此外,我们可以将文章的元数据与向量嵌入一起存储在 Elasticsearch 中。

与纯向量数据库不同,Elasticsearch 既可以对文本执行传统的 BM25 搜索,也可以原生地过滤和聚合元数据(时间性、数值型、空间性、布尔等)。

这意味着 Elasticsearch 可以在同一个数据存储中以及在单个搜索请求中执行所有这些技术以及执行向量搜索。无需预处理/后处理文本或向量,也无需在应用层或另一个数据存储中关联向量搜索结果。这大大降低了应用复杂性和所需工具的数量。

有了明确的用例需求,我们就可以创建我们的映射了。

    PUT dev_wiki_elser
    {
      "mappings": {
        "properties": {
          "@timestamp": {
            "type": "date"
          },
          "access": {
            "type": "keyword"
          },
          "created_at": {
            "type": "date",
            "format": "iso8601"
          },
          "key_phrases": {
            "type": "text"
          },
          "links": {
            "type": "text"
          },
          "passages": {
            "type": "nested",
            "properties": {
              "is_truncated": {
                "type": "boolean"
              },
              "model_id": {
                "type": "text",
                "fields": {
                  "keyword": {
                    "type": "keyword",
                    "ignore_above": 256
                  }
                }
              },
              "passage_tokens": {
                "type": "sparse_vector"
              },
              "text": {
                "type": "text"
              }
            }
          },
          "source": {
            "type": "keyword"
          },
          "summary": {
            "type": "text"
          },
          "updated_at": {
            "type": "date",
            "format": "iso8601"
          }
        }
      }
    }

我们将嵌套字段类型用于原始文本块及其使用 ELSER 创建的相应稀疏向量嵌入。 嵌套字段类型是一种特殊类型,其中每个内部文档都作为其自己的文档进行索引,并且其引用与包含文档或父文档一起存储。 使用嵌套字段类型,我们不会为每个文本块复制元数据。 此外,我们不会索引原始文档,因为文档的各个部分在 passage 字段中可用。 另一个细节是 summary 字段包含文章的标题。

使用 Elastic Ingest Pipeline 进行数据摄入

Elasticsearch 的推断处理器允许我们在摄入文档时创建稀疏向量嵌入。脚本处理器将 article_content 分区为少于 512 个项的段落,将文本转换为向量嵌入,并将文本和嵌入都索引到嵌套字段 passages 中。摄入管道是从博客 “通过摄入管道将大型文档分块加上嵌套向量等于简单的段落搜索” 中调整而来,该博客演示了使用摄入推断处理器将文本分块并转换为 LLM 模型中导入 Elasticsearch 的密集向量的过程。在这里,我们使用相同的分块技术通过分隔符来调用 ELSER 创建稀疏向量嵌入。

    PUT _ingest/pipeline/elser-v2-dev-wiki2
    {
      "processors": [
        {
          "script": {
            "description": "Chunk body into sentences by looking for . followed by a space",
            "lang": "painless",
            "source": """
              String[] envSplit = /((?<!M(r|s|rs)\.)(?<=\.) |(?<=\!) |(?<=\?) )/.split(ctx['article_content']);
              ctx['passages'] = new ArrayList();
              int i = 0;
              boolean remaining = true;
              if (envSplit.length == 0) {
                return
              } else if (envSplit.length == 1) {
                Map passage = ['text': envSplit[0]];ctx['passages'].add(passage)
              } else {
                while (remaining) {
                  Map passage = ['text': envSplit[i++]];
                  while (i < envSplit.length && passage.text.length() + envSplit[i].length() < params.model_limit) {passage.text = passage.text + ' ' + envSplit[i++]}
                  if (i == envSplit.length) {remaining = false}
                  ctx['passages'].add(passage)
                }
              }
              """,
            "params": {
              "model_limit": 400
            }
          }
        },
        {
          "foreach": {
            "field": "passages",
            "processor": {
              "inference": {
                "model_id": ".elser_model_2_linux-x86_64",
                "input_output": [
                  {
                    "input_field": "_ingest._value.text",
                    "output_field": "_ingest._value.passage_tokens"
                  }
                ],
                "on_failure": [
                  {
                    "append": {
                      "field": "_source._ingest.inference_errors",
                      "value": [
                        {
                          "message": "Processor 'inference' in pipeline 'elser-v2-dev-wiki' failed with message '{{ _ingest.on_failure_message }}'",
                          "pipeline": "elser-v2-dev-wiki",
                          "timestamp": "{{{ _ingest.timestamp }}}"
                        }
                      ]
                    }
                  }
                ]
              }
            }
          }
        },
        {
          "remove": {
            "field": [
              "article_content"
            ]
          }
        }
      ]
    }

作为管道的一部分,我们从索引中删除了article_content,因为内容在 passages 字段的分块中已经可用。

这里使用的分块技术,通过句尾标点创建 passages,是一种基本技术。有关使用各种方法进行分块的详细信息和代码,请参阅用于语义搜索的 token 计算。此外,Elasticsearch 中的原生分块功能即将推出。

对于这篇博客,我们将使用管道摄入 4 个公开的样本文档。这些文档是关于配置流量过滤的 Elastic Cloud 指南。其中一个文档具有 "access": "private"。

    POST dev_wiki_elser/_doc?pipeline=elser-v2-dev-wiki
    {
      "summary": "IP traffic filters",
      "access": "private",
      "@timestamp": "2023-08-07T08:15:12.590363000Z",
      "key_phrases": """- Traffic filtering\\n- IP address \\n- CIDR block \\n- Egress IP filters \\n- Ingress IP filters\\n- Inbound IP filters\\n- Outbound IP filters\\n- IPv4 \\n- VPC Endpoint Gateway \\n- VPC Endpoint Interface \""",
      "updated_at": "2023-08-07T08:15:14.756374+00:00",
      "created_at": "2023-08-03T19:54:31.260012+00:00",
      "links": [
    "https://www.elastic.co/guide/en/cloud/current/ec-traffic-filtering-ip.html"
        ],
        "source": "CLOUD_INFRASTRACTURE_DOCUMENT",
        "article_content": """Traffic filtering, by IP address or CIDR block, is one of the security layers available in Elasticsearch Service. It allows you to limit how your deployments can be
    …
        Select the Delete icon. The icon is inactive if there are deployments assigned to the rule set.
        """
    }

其他三个具有 “access”: “public” 属性。 以下是有关配置 AWS Privatelink 流量过滤器的文章。

    POST dev_wiki_elser/_doc?pipeline=elser-v2-dev-wiki
    {
      "summary": "AWS PrivateLink traffic filter",
      "access": "public",
      "@timestamp": "2023-08-07T08:15:12.590363000Z",
      "key_phrases": "- AWS\\\\n- PrivateLink \\\\n- VPC \\\\n- VPC Endpoint \\\\n- VPC Endpoint Service \\\\n- VPC Endpoint Policy \\\\n- VPC Endpoint Connection \\\\n- VPC Endpoint Interface \\\\n- VPC Endpoint Gateway \\\\n- VPC Endpoint Interface \\",
      "updated_at": "2023-08-07T08:15:14.756374+00:00",
      "created_at": "2023-08-03T19:54:31.260012+00:00",
      "links": [
        "https://www.elastic.co/guide/en/cloud/current/ec-traffic-filtering-vpc.html"
        ],
        "source": "CLOUD_INFRASTRACTURE_DOCUMENT",
        "article_content": """Traffic filtering, to only AWS PrivateLink
    …
        On the Security page, under Traffic filters select Remove."""
    }

另外两个文档非常相似,一个是关于 Azure Private Link 流量过滤器的,另一个是关于 GCP Private Service Connect 流量过滤器的。

访问控制

Elasticsearch 支持基于角色的访问控制,包括原生支持字段和文档级别的访问控制;这大大减少了保护应用程序所需的操作和维护复杂性。在我们的开发者 wiki 用例中,我们可以根据 access 字段值限制对文档的访问。例如,标记为 private 的文档不应对属于public_documents 用户角色的用户可访问,即具有属性access: private 的文档对于拥有 public_documents 角色的用户而言是不存在的。除了限制拥有 public_documents 用户角色的用户对文档的访问外,我们还可以移除对 access 字段的可见性。

注意:通过 REST API PUT 角色的代码包含在 gist 中。

用户 sherry 具有 public_documents 角色。 对于该用户,对索引进行简单计数将仅返回 3 个具有 "access": "public" 属性的文档。

 curl -u sherry:my_password -XGET https://my-cluster.aws.elastic-cloud.com/dev_wiki_elser/_count/?pretty

响应:

    {
      "count" : 3,
      "_shards" : {
        "total" : 1,
        "successful" : 1,
        "skipped" : 0,
        "failed" : 0
      }
    }

此外,查看索引映射的调用将仅返回用户被授权的字段。

    curl -u sherry:my_password -XGET https://my-cluster.aws.elastic-cloud.com/dev_wiki_elser/_mapping/?pretty
    {
      "dev_wiki_elser" : {
        "mappings" : {
          "properties" : {
            "@timestamp" : {
              "type" : "date"
            },
            "created_at" : {
              "type" : "date",
              "format" : "iso8601"
            },
            "key_phrases" : {
              "type" : "text"
            },
            "links" : {
              "type" : "text"
            },
            "passages" : {
              "type" : "nested",
              "properties" : {
                "passage_tokens" : {
                  "type" : "sparse_vector"
                },
                "text" : {
                  "type" : "text"
                }
              }
            },
            "source" : {
              "type" : "keyword"
            },
            "summary" : {
              "type" : "text"
            },
            "updated_at" : {
              "type" : "date",
              "format" : "iso8601"
            }
          }
        }
      }
    }

有了这种基于角色的访问控制(role-based control access - RBAC),拥有 public_documents 角色的用户将只能搜索和访问他们有权限的文档和字段。这是一个简单但强大的例子,展示了如何在 Elasticsearch 中本地轻松地保护数据和内容。此外,Elasticsearch 完全支持其他企业级认证/授权框架,如 SAML、LDAP、Active Directory 等,因此利用这些框架来控制对数据的访问只是简单的配置问题。

搜索技术

现在,我们准备转向语义搜索。请注意,搜索相关性调优是一个迭代过程,可能需要我们回头使用不同于我们已采用的模型和/或修改索引模式。

此外,向我们的语义搜索查询中添加元数据过滤可以提高相关性。同时,结合使用不同的搜索算法也是优化结果的另一个选项,比如将 BM25 与 ELSER 一起使用,使用倒数排名融合(RRF)进行混合搜索,使用密集向量与 ELSER 以及它们的某些组合。Elasticsearch 原生支持所有这些功能。

我们用例的语料库,开发者 wiki 文档,倾向于包含非常相似的主题和术语。以下查询仅使用 ELSER 向量嵌入检索关于配置过滤规则集,以连接 Google Private Service Connect 到 Elastic Cloud 部署的最相关段落。我们已将 "_source" 设置为 "false",因为我们只需要输出 summary 或 title、URL 和文章的相关部分。为了清晰起见,我们跳过了日期。

    GET dev_wiki_elser/_search
    {
      "_source": "false",
      "fields": [
        "summary",
        "links"
      ],
      "query": {
        "nested": {
          "path": "passages",
          "score_mode": "max",
          "query": {
            "text_expansion": {
              "passages.passage_tokens": {
                "model_id": ".elser_model_2_linux-x86_64",
                "model_text": "How to configure traffic filter rule set private link google"
              }
            }
          },
          "inner_hits": {
            "size": 1,
            "_source": false,
            "fields": [
              "passages.text"
            ]
          }
        }
      }
    }

不幸的是,返回的第一篇文章是关于如何为 AWS 配置流量过滤器集,而不是 Google Cloud 的文章。这并不令人惊讶,因为 “private link” 是一个描述 VPCs 之间安全链接的常用词汇,最初由亚马逊网络服务(AWS)使用,就像 Kleenex 之于面巾纸一样;尽管其在 Google Cloud Platform 中的等效物被称为私有连接服务,但它被用户广泛采用。

    {
      "took": 19,
      "timed_out": false,
      "_shards": {
       …
      },
      "hits": {
        "total": {
          "value": 4,
          "relation": "eq"
        },
        "max_score": 20.017376,
        "hits": [
          {
            "_index": "dev_wiki_elser",
            "_id": "UGxiOY0Bds674Ci9z6yW",
            "_score": 20.017376,
            "_source": {},
            "fields": {
              "summary": [
                "AWS PrivateLink traffic filter"
              ],,
              "links": ["https://www.elastic.co/guide/en/cloud/current/ec-traffic-filtering-vpc.html"]
            },
            "inner_hits": {
              "passages": {
                "hits": {
                  "total": {
                    "value": 24,
                    "relation": "eq"
                  },
                  "max_score": 20.017376,
                  "hits": [
                    {
                      "_index": "dev_wiki_elser",
                      "_id": "UGxiOY0Bds674Ci9z6yW",
                      "_nested": {
                        "field": "passages",
                        "offset": 17
                      },
                      "_score": 20.017376,
                      "fields": {
                        "passages": [
                          {
                            "text": [
                              """Or, select Dedicated deployments to go to the deployments page to view all of your deployments.
        Under the Features tab, open the Traffic filters page.
        Select Create filter.
        Select Private link endpoint.
    ...

这就是我们映射中的 key_phrases 字段发挥作用的地方。在我们的用例中,文章附有关键词和短语,这为将语义搜索与传统的 BM25 搜索相结合提供了一个绝佳的方式。

通常,内容并没有关键词/短语,但这可以通过使用 LLM 来执行关键词提取轻松解决,这样可以提炼出文章的精华。这可以通过使用公共的 LLM,如 OpenAI 或 Gemini,或者使用本地托管的 LLM,如 Mistral 7 或 llama2 来实现。请在下一篇博客中留意这一点。

将我们原始的文本扩展搜索和对 key_phrases 字段的 match 查询包裹在一个 bool 查询中,确保如预期返回正确的文档。

    GET dev_wiki_elser/_search
    {
      "_source": "false",
      "fields": [
        "summary",
        "links"
      ],
      "query": {
        "bool": {
          "should": [
            {
              "nested": {
                "path": "passages",
                "score_mode": "max",
                "query": {
                  "text_expansion": {
                    "passages.passage_tokens": {
                      "model_id": ".elser_model_2_linux-x86_64",
                      "model_text": "How to configure traffic filter rule set private link google"
                    }
                  }
                },
                "inner_hits": {
                  "size": 1,
                  "_source": false,
                  "fields": [
                    "passages.text"
                  ]
                }
              }
            },
            {
              "match": {
                "key_phrases": "How to configure traffic filter rule set private link google"
              }
            }
          ]
        }
      }
    }

查询的响应正确标识了相关文章。

    {
      "took": 22,
      "timed_out": false,
      "_shards": {
        "total": 1,
        "successful": 1,
        "skipped": 0,
        "failed": 0
      },
      "hits": {
        "total": {
          "value": 4,
          "relation": "eq"
        },
        "max_score": 22.327188,
        "hits": [
          {
            "_index": "dev_wiki_elser",
            "_id": "UmxjOY0Bds674Ci9Dqzy",
            "_score": 22.327188,
            "_source": {},
            "fields": {
              "summary": [
                "Google Private Service Connect"
              ],
              "links": [
                "https://www.elastic.co/guide/en/cloud/current/ec-traffic-filtering-psc.html"
              ]
            },
            "inner_hits": {
              "passages": {
                "hits": {
                  "total": {
                    "value": 22,
                    "relation": "eq"
                  },
                  "max_score": 19.884687,
                  "hits": [
                    {
                      "_index": "dev_wiki_elser",
                      "_id": "UmxjOY0Bds674Ci9Dqzy",
                      "_nested": {
                        "field": "passages",
                        "offset": 16
                      },
                      "_score": 19.884687,
                      "fields": {
                        "passages": [
                          {
                            "text": [
                              """Add the Private Service Connect rules to your deployments
                              …

我们针对该用例尝试的另一种技术是具有倒数排名融合的混合搜索。 对于我们的用例,该方法不如带有文本扩展和 BM25 的简单布尔查询有效。 此外,由于我们使用的分块技术,尽管相关性很好,但响应段落通常从段落的中间开始。 我们能够美化应用层的响应。

总结

在这篇博客中,我们探索了在企业卓越中心实施语义搜索的过程。

  • 模型选择:ELSER 是一个为开箱即用用例设计的检索模型,这使得它成为寻求灵活性、速度和流线型实施的搜索中心的简单选择。
  • 模式设计:与纯向量数据库不同,Elasticsearch 同样可以执行传统的 BM25 搜索,并且能够在同一上下文数据库和查询中原生地过滤和聚合元数据以及向量搜索。其结果是能够显著简化应用复杂性和相比于纯向量数据库所需的工具数量。使用嵌套字段类型来存储原始文本的块及其对应的由 ELSER 创建的稀疏向量嵌入,是一种存储和搜索数据的高效方式。
  • 数据摄入:Elasticsearch 推理处理器允许我们在摄入文档时 “分块” 并创建稀疏向量嵌入。这一切都可以在 Elasticsearch 内完成,无需额外的工具和预处理。Elasticsearch 即将推出原生分块功能。
  • 访问控制:Elasticsearch 拥有强大的原生 RBAC 控制,以限制/控制访问,包括字段和文档级别的访问控制,这大大减少了保护数据和应用所需的操作和维护复杂性。
  • 搜索技术:语义搜索是一个迭代过程,可能需要调整或结合多种搜索技术来产生最相关的结果。在这个案例中,我们发现纯粹的语义文本扩展搜索没有提供最佳的相关性。因此,我们结合了语义搜索和传统的 BM25 搜索对关键短语进行过滤,以提供最佳结果。还有其他技术,如倒数排序融合可以使用,尽管在这个用例中它们没有提供更好的结果。

提醒一下,这篇博客的所有代码和内容都可以在这里找到。

其他注意事项

我们忽略的一件事是如何以可扩展和系统的方式评估搜索相关性。 对于我们的用例,我们有一个测试数据集、查询和预期结果来定量测量 “什么是好的”。 我们强烈建议你查看通过数据驱动的查询优化提高搜索相关性,以获得可靠的方法。

此外,调整我们的用例的语义搜索相关性是一个迭代过程。 对于许多搜索 COE 来说,快速启动、调整路线并在需要时采用不同的技术是有意义的。 LLMs 是我们工具集中一个极其灵活的工具,可以为我们的用户提供更高级别的搜索体验。

下一个博客

在本博客的下一部分中,我们将了解如何以优化且简单的方式向开发人员公开我们的 Elasticsearch 查询,使他们能够快速将搜索功能合并到应用程序中。 作为其中的一部分,我们将提供关键字提取的示例,这可以提高搜索性能。

原文:https://www.elastic.co/search-labs/blog/semantic-search-as-service-at-a-search-center-of-excellence

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Tensorflow2.0笔记 - metrics做损失和准确度信息度量

本笔记主要记录metrics相关的内容&#xff0c;详细内容请参考代码注释&#xff0c;代码本身只使用了Accuracy和Mean。本节的代码基于上篇笔记FashionMnist的代码经过简单修改而来&#xff0c;上篇笔记链接如下&#xff1a; Tensorflow2.0笔记 - FashionMnist数据集训练-CSDN博…

AI 异构计算机设计方案:902-基于6U VPX 高带宽PCIe的GPU AI 异构计算机

基于6U VPX 高带宽PCIe的GPU AI 异构计算机 一、产品概述 基于6U 6槽 VPX 高带宽PCIe的GPU AI 异构计算机以PCIe总线为架构&#xff0c;通过高带宽的PCIe互联&#xff0c;实现主控计算板、GPU AI板卡&#xff0c;FPGA接口板&#xff0c;存储板的PCIe高带宽互联访问&…

揭秘百度百科审核内幕,百科词条审核究竟需要多久?

百度百科作为国内最大的网络百科全书平台之一&#xff0c;致力于提供全面、准确的知识服务&#xff0c;同时也承担着审核百科词条的工作。在互联网时代&#xff0c;人们对信息的需求日益增长&#xff0c;因此百度百科的审核工作显得尤为重要。那么&#xff0c;百度百科词条审核…

152 Linux C++ 通讯架构实战7 ,makefile编写改成for cpp,读配置文件,内存泄漏查找,设置标题实战

读写配置文件代码实战。nginx.conf 一个项目要启动&#xff0c;需要配置很多信息&#xff0c;第一项就是学习如何配置一个项目 nginx.conf的内容 #是注释行&#xff0c; #每个有效配置项用 等号 处理&#xff0c;等号前不超过40个字符&#xff0c;等号后不超过400个字符&#…

虚幻引擎资源加密方案解析

前段时间&#xff0c;全球游戏开发者大会(Game Developers Conference&#xff0c;简称GDC)在旧金山圆满落幕&#xff0c;会议提供了多份值得参考的数据报告。根据 GDC 调研数据&#xff0c;当下游戏市场中&#xff0c;Unreal Engine (下文简称虚幻)和 Unity 是使用最多的游戏引…

Qlib-Server:量化库数据服务器

Qlib-Server:量化库数据服务器 介绍 Qlib-Server 是 Qlib 的配套服务器系统,它利用 Qlib 进行基本计算,并提供广泛的服务器系统和缓存机制。通过 Qlib-Server,可以以集中的方式管理 Qlib 提供的数据。 框架 Qlib 的客户端/服务器框架基于 WebSocket 构建,这是因为 WebS…

js动态设置页面高度

准备一个div <div class"card-edit"><!-- 业务需求 --> </div>开始操作 // 获取页面的中需要设置高度的元素 如&#xff1a;card-editconst autoStyle document.getElementsByClassName(card-edit)[0]// 根据业务需求做判断// 此处设定&#…

DC电源模块的设计与制造流程

BOSHIDA DC电源模块的设计与制造流程 DC电源模块是一种用于将交流电转换为直流电的设备。它广泛应用于各种电子设备中&#xff0c;如电子产品、工业仪器、电视等。下面是DC电源模块的设计与制造流程的简要描述&#xff1a; 1. 需求分析&#xff1a;在设计DC电源模块之前&#…

sql——对于行列转换相关的操作

目录 一、lead、lag 函数 二、wm_concat 函数 三、pivot 函数 四、判断函数 遇到需要进行行列转换的数据处理需求&#xff0c;以 oracle 自带的表作为例子复习一下&#xff1a; 一、lead、lag 函数 需要行列转换的表&#xff1a; select deptno,count(empno) emp_num from…

R语言赋值符号<-、=、->、<<-、->>的使用与区别

R语言的赋值符号有&#xff1c;-、、-&#xff1e;、&#xff1c;&#xff1c;-、-&#xff1e;&#xff1e;六种&#xff0c;它们的使用与区别如下: <-’&#xff1a;最常用的赋值符号。它将右侧表达式的值赋给左侧的变量&#xff0c;像一个向左的箭头。例如&#xff0c;x …

Python-VBA编程500例-024(入门级)

字符串写入的行数(Line Count For String Writing)在实际应用中有着广泛的应用场景。常见的应用场景有&#xff1a; 1、文本编辑及处理&#xff1a;在编写或编辑文本文件时&#xff0c;如使用文本编辑器或文本处理器&#xff0c;经常需要处理字符串并确定其在文件中的行数。这…

【数据结构 | 图论】如何用链式前向星存图(保姆级教程,详细图解+完整代码)

一、概述 链式前向星是一种用于存储图的数据结构&#xff0c;特别适合于存储稀疏图&#xff0c;它可以有效地存储图的边和节点信息&#xff0c;以及边的权重。 它的主要思想是将每个节点的所有出边存储在一起&#xff0c;通过数组的方式连接&#xff08;类似静态数组实现链表…

基于Springboot+Vue的酒店管理系统!新鲜出炉,可商用,带源码

新年了给大家分享一套基于SpringbootVue的酒店管理系统源码&#xff0c;在实际项目中可以直接复用。(免费提供&#xff0c;文末自取) 一、系统运行图&#xff08;管理端和用户端&#xff09; 1、管理登陆 2、房间管理 3、订单管理 4、用户登陆 5、房间预定 二、系统搭建视频教…

JavaEE—— HTTP协议和与Tomcat (末篇)

本篇文章&#xff0c;承接前面两篇文章&#xff1a; 在前面的两篇文章中&#xff0c;简单介绍了 什么是 HTTP 协议&#xff0c;介绍了抓包工具&#xff0c;如何构造 HTTP 请求&#xff0c;以及&#xff0c;如何使用第三方工具来简化构造请求的过程。 如果需要了解前面的知识可…

算法---动态规划练习-6(地下城游戏)

地下城游戏 1. 题目解析2. 讲解算法原理3. 编写代码 1. 题目解析 题目地址&#xff1a;点这里 2. 讲解算法原理 首先&#xff0c;定义一个二维数组 dp&#xff0c;其中 dp[i][j] 表示从位置 (i, j) 开始到达终点时的最低健康点数。 初始化数组 dp 的边界条件&#xff1a; 对…

AI赋能微服务:Spring Boot与机器学习驱动的未来应用开发

&#x1f9d1; 作者简介&#xff1a;阿里巴巴嵌入式技术专家&#xff0c;深耕嵌入式人工智能领域&#xff0c;具备多年的嵌入式硬件产品研发管理经验。 &#x1f4d2; 博客介绍&#xff1a;分享嵌入式开发领域的相关知识、经验、思考和感悟。提供嵌入式方向的学习指导、简历面…

实践笔记-harbor搭建(版本:2.9.0)

harbor搭建 1.下载安装包&#xff08;版本&#xff1a;2.9.0&#xff09;2.修改配置文件3.安装4.访问harbor5.可能用得上的命令: 环境&#xff1a;centos7 1.下载安装包&#xff08;版本&#xff1a;2.9.0&#xff09; 网盘资源&#xff1a;https://pan.baidu.com/s/1fcoJIa4x…

Vue中的一些指令与计算方法

语法 插值语法 HTML的双标签内容中使用&#xff0c;在{{}}之内书写JS代码 属性语法 1.v-bind或: 2.:属性名"值"或v-bind"值" 事件语法 v-on或 v-on:事件名"方法名"或事件名"方法名" 选项 选项&#xff1a;可选的配置项——官方…

vue3封装Element动态表单组件

1. 封装组件DymanicForm.vue 使用component实现动态组件组件不能直接使用字符串传入&#xff0c;所以根据传入的组件名称找到对应的组件校验规则&#xff0c;可使用rule传入自定义规则&#xff0c;也可以使用封装好的基本规则 示例中使用了checkRequired暴露重置方法和校验方法…

奥比中光Astra SDK相机SDK openni相机成像原理

目录 1.1 成像原理简介 1.1.1 结构光 1.1.2 双目视觉 1.1.3 光飞行时间TOF​ 2.使用手册 参考网址 2.1 产品集成设计 2.2 SDK介绍与使用 2.3 常用API介绍 OPENNI API 2 OpenNI类&#xff08;OpenNI.h&#xff09; 1.1 成像原理简介 1.1.1 结构光 结构光&#xff0…