如何将 Elasticsearch 与流行的 Ruby 工具结合使用

作者:来自 Elastic  Fernando Briano

了解如何将 Elasticsearch 与一些流行的 Ruby 库一起使用。

在这篇博文中,我们将介绍如何将 Elasticsearch 与一些流行的 Ruby 工具结合使用。我们将实现 Ruby 客户端 “入门”指南 中介绍的常用 API。如果你点击该链接,你将看到如何使用官方 Elasticsearch 客户端:elasticsearch-ruby 运行这些相同的操作。

我们对客户端进行了广泛的测试,以确保 Elasticsearch 中的所有 API 都支持每个版本,包括当前正在开发的版本。这涵盖了近 500 个 API。

但是,在某些情况下,你可能不想使用客户端,而想在 Ruby 代码中自己实现一些功能。你的代码可能严重依赖于某个特定的库,并且你希望将其重用于 Elasticsearch。你可能在只需要几个 API 的设置中工作,并且不想引入新的依赖项。或者你的资源有限,并且你不想使用可以在 Elasticsearch 中完成所有操作的成熟客户端。

无论出于何种原因,Elasticsearch 都通过公开可直接调用的 REST API 简化了操作,因此你可以通过发出 HTTP 请求来访问其功能,而无需客户端。使用 API 时,建议查看 API 约定和常用选项。

简介

这些示例中使用的库是 Net::HTTP、HTTParty、exon、HTTP(又名 http.rb)、Faraday 和 elastic-transport。除了了解如何从 Ruby 与 Elasticsearch 交互之外,本文还将简要介绍每个库,让我们了解它们以及如何使用它们。本文不会深入介绍任何库,但会让你了解每个库的使用方式。

代码是在 Ruby 3.3.5 中编写和测试的。每个工具的版本将在各自的部分中提及。示例使用 require 'bundler/inline' 以方便在编写代码的同一文件中安装必要的 gem,但你也可以使用 Gemfile。

设置

在处理这些示例时,我使用 start-local,这是一个简单的 shell 脚本,可在几秒钟内设置 Elasticsearch 和 Kibana 以进行本地开发。在我编写此代码的目录中,我运行:

curl -fsSL https://elastic.co/start-local | sh

这将创建一个名为 elastic-start-local 的子目录,其中包含一个 .env 文件,其中包含我们连接和验证 Elasticsearch 所需的信息。我们可以在运行 Ruby 代码之前运行 source elastic-start-local/.env,也可以使用 dotenv gem:

require 'dotenv'
Dotenv.load('./elastic-start-local/.env')

以下代码示例假设此文件中的 ENV 变量已加载。

我们可以使用基本身份验证或 API 密钥身份验证对 Elasticsearch 进行身份验证。要使用基本身份验证,我们必须使用用户名 “elastic” 和存储在 ES_LOCAL_PASSWORD 中的值作为密码。要使用 API 密钥身份验证,我们需要此 .env 文件中存储在 ES_LOCAL_API_KEY 中的值。可以使用 Kibana 管理 Elasticsearch,它将使用 start-local 在 http://localhost:5601 运行,你也可以在 Kibana 中手动创建 API 密钥。

默认情况下,Elasticsearch 将在 http://localhost:9200 上运行,但示例从 ES_LOCAL_URL 环境变量加载主机。

你还可以使用任何其他 Elasticsearch 集群来运行这些集群,并相应地调整主机和凭据。如果你使用的是 start-local,你可以使用命令 docker compose stop 停止正在运行的 Elasticsearch 实例,然后从 elastic-start-local 目录使用 docker compose up 重新启动它。

Net::HTTP

Net::HTTP 提供了一个丰富的库,它使用 HTTP 请求-响应协议在客户端-服务器模型中实现客户端。我们可以在代码中使用 require 'net-http' 来要求这个库,然后开始使用它,而无需安装任何额外的依赖项。它不是最用户友好的,但它在 Ruby 中是原生可用的。这些示例中使用的版本是 0.4.1。

require 'json'
require 'net/http'

host = URI(ENV['ES_LOCAL_URL'])
headers = {
  'Authorization' => "ApiKey #{ENV['ES_LOCAL_API_KEY']}",
  'Content-Type' => 'application/json'
}

这为我们提供了执行对 Elasticsearch 的请求的设置。我们可以通过对服务器根路径的初始请求来测试这一点:

response = JSON.parse(Net::HTTP.get(host, headers))
puts response
# {"name"=>"b3349dfab89f", "cluster_name"=>"docker-cluster", ..., "tagline"=>"You Know, for Search"}

我们可以检查响应以获取更多信息:

response = Net::HTTP.get_response(host, headers)
puts "Content-Type: #{response['Content-type']}"
puts "Response status: #{response.code}"
puts "Body: #{JSON.parse(response.body)}"
# Content-Type: application/json
# Response status: 200
# Body: {"name"=>"b3349dfab89f", ...

我们现在可以尝试创建一个索引:

index = 'nethttp_docs'
http = Net::HTTP.new(host.hostname, host.port)

# Create an index
response = http.put("/#{index}", '', headers)
puts response
# {"acknowledged":true,"shards_acknowledged":true,"index":"nethttp_index"}

有了索引,我们现在就可以开始处理文档了。

# Index a document
document = { name: 'elasticsearch-ruby', description: 'Official Elasticsearch Ruby client' }.to_json
response = http.post("/#{index}/_doc", document, headers)
puts response
# {"_index":"nethttp_docs","_id":"...

# Save the id for following requests:
id = JSON.parse(response.body)["_id"]

请注意,我们需要将文档转换为 JSON 才能在请求中使用它。有了索引文档,我们可以测试一个非常简单的 search 请求:

# Search
search_body = { query: { match_all: {} } }.to_json
response = http.post("#{index}/_search", search_body, headers)
JSON.parse(response.body)['hits']['hits']
# => [{"_index"=>"nethttp_docs", "_id"=>...

并对索引数据进行更多工作:

# Get a document
response = http.get("#{index}/_doc/#{id}", headers)
JSON.parse(response.body)
# => {"_index"=>"nethttp_docs", ..., "_source"=>{"name"=>"elasticsearch-ruby", "description"=>"Official Ruby client"}}

# Update a document
document = { doc: { name: 'net-http-ruby', description: 'NetHTTP Ruby client' } }.to_json
response = http.post("#{index}/_update/#{id}", document, headers)
# => <Net::HTTPOK 200 OK readbody=true>

# Deleting documents
response = http.delete("#{index}/_doc/#{id}", headers)
# => <Net::HTTPOK 200 OK readbody=true>

最后,我们将删除索引来清理集群:

# Deleting an index
response = http.delete(index, headers)
# => <Net::HTTPOK 200 OK readbody=true>

HTTParty

HTTParty 是一款 “旨在让 HTTP 变得有趣” 的瑰宝。它提供了一些有用的抽象来发出请求和处理响应。这些示例使用了该库的 0.22.0 版本。

require 'bundler/inline'
require 'json'

gemfile do
  source 'https://rubygems.org'
  gem 'httparty'
end

host = URI(ENV['ES_LOCAL_URL'])
headers = {
  'Authorization' => "ApiKey #{ENV['ES_LOCAL_API_KEY']}",
  'Content-Type' => 'application/json'
}

向服务器发出的初始请求:

response = HTTParty.get(host, headers: headers)
# => {"name"=>"b3349dfab89f",
...

# And we can see more info:
response.headers['content-type']
# => "application/json"
response.code
# => 200
JSON.parse(response.body)
# => {"name"=>"b3349dfab89f", ...

如果响应内容类型为 application/json,HTTParty 将解析响应并返回 Ruby 对象(例如哈希或数组)。解析 JSON 的默认行为将以字符串形式返回键。我们可以按如下方式使用响应:

response
# =>
# {"name"=>"b3349dfab89f",
#  "cluster_name"=>"docker-cluster",
#  ...
#  "tagline"=>"You Know, for Search"}

JSON.parse(response.body, symbolize_names: true)
#  =>
# {:name=>"b3349dfab89f",
#  :cluster_name=>"docker-cluster",
#  ...
#  :tagline=>"You Know, for Search"}

# We can also access the response keys directly, like the Elasticsearch::API:Response object returned by the Elasticsearch Ruby client:
response['name']
# => "b3349dfab89f"

README 展示了如何使用类方法快速发出请求以及创建自定义类的选项。实现 Elasticsearch Client 类并添加我们想要使用的不同 API 方法会更方便。例如:

class ESClient
  include HTTParty
  base_uri ENV['ES_LOCAL_URL']

  def initialize
    @headers = {
      'Authorization' => "ApiKey #{ENV['ES_LOCAL_API_KEY']}",
      'Content-Type' => 'application/json'
    }
  end

  def info
    self.class.get('/', headers: @headers)
  end
end

client = ESClient.new
puts client.info

我们不想在这篇博文中使用 HTTParty 重新实现 Elasticsearch Ruby,但当仅使用一些 API 时,这可能是一种替代方案。我们将了解如何构建其余请求:

index = 'httparty-test'
# Create an index
response = HTTParty.put("#{host}/#{index}", headers: headers)
puts response
# {"acknowledged"=>true, "shards_acknowledged"=>true, "index"=>"httparty-test"}

# Index a Document
document = { name: 'elasticsearch-ruby', description: 'Official Elasticsearch Ruby client' }.to_json
response = HTTParty.post("#{host}/#{index}/_doc", body: document, headers: headers)
# => {"_index"=>"httparty-test", "_id": ... }

# Save the id for following requests:
id = response["_id"]

# Get a document:
response = HTTParty.get("#{host}/#{index}/_doc/#{id}", headers: headers)
# => {"_index"=>"httparty-test", ..., "_source"=>{"name"=>"elasticsearch-ruby", "description"=>"Official Elasticsearch Ruby client"}}

# Search
search_body = { query: { match_all: {} } }.to_json
response = HTTParty.post("#{host}/#{index}/_search", body: search_body, headers: headers)
response['hits']['hits']
# => [{"_index"=>"httparty-test", ... ,"_source"=>{"name"=>"elasticsearch-ruby", "description"=>"Official Elasticsearch Ruby client"}}]

# Update a document
document = { doc: { name: 'httparty-ruby', description: 'HTTParty Elasticsearch client' } }.to_json
response = HTTParty.post("#{host}/#{index}/_update/#{id}", body: document, headers: headers)
# => {"_index"=>"httparty-test", "_id" ... }
response.code
# => 200

# Deleting documents
response = HTTParty.delete("#{host}/#{index}/_doc/#{id}", headers: headers)
# => {"_index"=>"httparty-test", "_id" ... }
response.code
# => 200

# Deleting an index
response = HTTParty.delete("#{host}/#{index}", headers: headers)
# => {"acknowledged":true}

excon

Excon 的设计目标是简单、快速和高性能。它特别适合在 API 客户端中使用,因此非常适合与 Elasticsearch 交互。此代码使用 Excon 版本 0.111.0。

require 'bundler/inline'
require 'json'
gemfile do
  source 'https://rubygems.org'
  gem 'excon'
end

host = URI(ENV['ES_LOCAL_URL'])
headers = {
  'Authorization' => "ApiKey #{ENV['ES_LOCAL_API_KEY']}",
  'Content-Type' => 'application/json'
}

response = Excon.get(host, headers: headers)
puts "Content-Type: #{response.headers['content-type']}"
puts "Response status: #{response.status}"
puts "Body: #{JSON.parse(response.body)}"
# Content-Type: application/json
# Response status: 200
# Body: {"name"=>"b3349dfab89f", "cluster_name"=>"docker-cluster", ..., "tagline"=>"You Know, for Search"}

Excon 请求返回一个 Excon::Response 对象,该对象具有 body、headers、remote_ip 和 status 属性。我们还可以使用键作为符号直接访问数据,类似于 Elasticsearch::API::Response 的工作方式:

response[:headers]
# => {"X-elastic-product"=>"Elasticsearch", "content-type"=>"application/json", "content-length"=>"541"}

我们可以在多个请求之间重复使用一个连接,以共享选项并提高性能。我们还可以使用持久连接与初始请求建立套接字连接,并在运行以下示例时保持套接字打开:

connection = Excon.new(host, persistent: true, headers: headers)
index = 'excon-test'

# Create an index
response = connection.put(path: index)
puts response.body
# {"acknowledged":true,"shards_acknowledged":true,"index":"excon-test"}

# Index a Document
document = { name: 'elasticsearch-ruby', description: 'Official Elasticsearch Ruby client' }.to_json
response = connection.post(path: "#{index}/_doc", body: document)
puts response.body
# {"_index":"excon-test","_id" ... }

# Save the id for following requests:
id = JSON.parse(response.body)["_id"]

# Get a document:
response = connection.get(path: "#{index}/_doc/#{id}")
JSON.parse(response.body)
# => {"_index"=>"excon-test", ...,"_source"=>{"name"=>"elasticsearch-ruby", "description"=>"Official Elasticsearch Ruby client"}}

# Search
search_body = { query: { match_all: {} } }.to_json
response = connection.post(path: "#{index}/_search", body: search_body)
JSON.parse(response.body)['hits']['hits']
# => [{"_index"=>"excon-test",..., "_source"=>{"name"=>"elasticsearch-ruby", "description"=>"Official Elasticsearch Ruby client"}}]

# Update a document
document = { doc: { name: 'excon-ruby', description: 'Excon Elasticsearch client' } }.to_json
response = connection.post(path: "#{index}/_update/#{id}", body: document)
# => <Excon::Response:0x0000...
response.status
# => 200

# Deleting documents
response = connection.delete(path: "#{index}/_doc/#{id}")
# => <Excon::Response:0x0000...
response.status
# => 200

# Deleting an index
response = connection.delete(path: index)
puts response.body
# {"acknowledged":true}

# Close connection
connection.reset

HTTP (http.rb)

HTTP 是一个 HTTP 客户端,它使用类似于 Python 的 Requests 的可链接 API。它用 Ruby 实现 HTTP 协议,并将解析外包给本机扩展。此代码中使用的版本是 5.2.0。

host = URI(ENV['ES_LOCAL_URL'])

headers = {
  'Authorization' => "ApiKey #{ENV['ES_LOCAL_API_KEY']}",
  'Content-Type' => 'application/json'
}

HTTP.get(host, headers: headers)
response = HTTP.get(host, headers: headers)
# => <HTTP::Response/1.1 200 OK {"X-elastic-product"=>"Elasticsearch", "content-type"=>"application/json", "content-length"=>"541"}>
puts "Content-Type: #{response.headers['content-type']}"
puts "Response status: #{response.code}"
puts "Body: #{JSON.parse(response.body)}"
# Content-Type: application/json
# Response status: 200
# Body: {"name"=>"b3349dfab89f", ..., "tagline"=>"You Know, for Search"}

我们还可以使用 auth 方法来利用可链接 API:

HTTP.auth(headers["Authorization"]).get(host)

或者因为我们还关心内容类型标头、链 headers:

HTTP.headers(headers).get(host)

因此,一旦我们创建了持久客户端,构建请求就会变得更短:

# Create an index
index = 'http-test'
response = http.put("#{host}/#{index}")
response.parse
# => {"acknowledged"=>true, "shards_acknowledged"=>true, "index"=>"http-test"}

# Index a Document
document = { name: 'elasticsearch-ruby', description: 'Official Elasticsearch Ruby client' }.to_json
response = http.post("#{host}/#{index}/_doc", body: document)
# => <HTTP::Response/1.1 201 Created {"Location"=>"/http-test/_doc/GCA1KZIBr7n-DzjRAVLZ", "X-elastic-product"=>"Elasticsearch", "content-type"=>"application/json", "content-length"=>"161"}>
response.parse
# => {"_index"=>"http-test", "_id" ...}

# Save the id for following requests:
id = response.parse['_id']

# Get a document:
response = http.get("#{host}/#{index}/_doc/#{id}")
# => <HTTP::Response/1.1 200 OK {"X-elastic-product"=>"Elasticsearch", "content-type"=>"application/json", "content-length"=>"198"}>
response.parse
# => {"_index"=>"http-test", "_id", ..., "_source"=>{"name"=>"elasticsearch-ruby", "description"=>"Official Elasticsearch Ruby client"}}

# Search
search_body = { query: { match_all: {} } }.to_json
response = http.post("#{host}/#{index}/_search", body: search_body)
# => <HTTP::Response/1.1 200 OK ...
response.parse['hits']['hits']
# => [{"_index"=>"http-test", "_id",..., "_source"=>{"name"=>"elasticsearch-ruby", "description"=>"Official Elasticsearch Ruby client"}}]

# Update a document
document = { doc: { name: 'http-ruby', description: 'HTTP Elasticsearch client' } }.to_json
response = http.post("#{host}/#{index}/_update/#{id}", body: document)
# => <HTTP::Response/1.1 200 OK ...
response.code
# => 200
response.flush

# Deleting documents
response = http.delete("#{host}/#{index}/_doc/#{id}")
# => <HTTP::Response/1.1 200 OK ...
response.code
# => 200
response.flush

# Deleting an index
response = http.delete("#{host}/#{index}")
# => <HTTP::Response/1.1 200 OK ...
response.parse
# => {"acknowledged"=>true}

文档警告我们,在持久连接中发送下一个请求之前,必须使用响应。这意味着在响应对象上调用 to_s、parse 或 flush。

Faraday

Faraday 是 Elasticsearch 客户端默认使用的 HTTP 客户端库。它提供了多个适配器的通用接口,你可以在实例化客户端时选择这些适配器(Net::HTTP、Typhoeus、Patron、Excon 等)。此代码中使用的 Faraday 版本为 2.12.0。

get 的签名为 (url, params = nil, headers = nil),因此我们在此初始测试请求中传递 nil 作为参数:

require 'bundler/inline'
require 'json'
gemfile do
  source 'https://rubygems.org'
  gem 'faraday'
end

response = Faraday.get(host, nil, headers)
# => <Faraday::Response:0x0000...

响应是一个 Faraday::Response 对象,其中包含响应状态、标头和正文,我们还可以访问 Faraday Env 对象中的许多属性。正如我们在其他库中看到的那样,在我们的用例中使用 Faraday 的推荐方法是创建一个 Faraday::Connection 对象:

conn = Faraday.new(
  url: host,
  headers: headers
)

response = conn.get('/')
puts "Content-Type: #{response.headers['content-type']}"
puts "Response status: #{response.code}"
puts "Body: #{JSON.parse(response.body)}"
# Content-Type: application/json
# Response status: 200
# Body: {"name"=>"b3349dfab89f", ..., "tagline"=>"You Know, for Search"}

现在重新使用该连接,我们可以看到 Faraday 的其余请求是什么样的:

index = 'faraday-test'
# Create an index
response = conn.put(index)
puts response.body
# {"acknowledged":true,"shards_acknowledged":true,"index":"faraday-test"}'

# Index a Document
document = { name: 'elasticsearch-ruby', description: 'Official Elasticsearch Ruby client' }.to_json
# The signature for post is (url, body = nil, headers = nil), unlike the get signature:
response = conn.post("#{index}/_doc", document)
puts response.body
# {"_index":"faraday-test","_id" ... }

# Save the id for following requests:
id = JSON.parse(response.body)["_id"]

# Get a document:
response = conn.get("#{index}/_doc/#{id}")
JSON.parse(response.body)
# => {"_index"=>"faraday-test", ...,"_source"=>{"name"=>"elasticsearch-ruby", "description"=>"Official Elasticsearch Ruby client"}}

# Search
search_body = { query: { match_all: {} } }.to_json
response = conn.post("#{index}/_search", search_body)
JSON.parse(response.body)['hits']['hits']
# => [{"_index"=>"faraday-test", ..., "_source"=>{"name"=>"elasticsearch-ruby", "description"=>"Official Elasticsearch Ruby client"}}]

# Update a document
document = { doc: { name: 'faraday-ruby', description: 'Faraday client' } }.to_json
response = conn.post("#{index}/_update/#{id}", document)
# => <Faraday::Response:0x0000...
response.status
# => 200

# Deleting documents
response = conn.delete("#{index}/_doc/#{id}")
# => <Excon::Response:0x0000...
response.status
# => 200

# Deleting an index
response = conn.delete(index)
puts response.body
# {"acknowledged":true}
 

Elastic Transport

elastic-transport 库是 Ruby 中的精华,用于在官方 Elastic Ruby 客户端中执行 HTTP 请求、编码、压缩等。多年来,这个库已经针对每个官方版本的 Elasticsearch 进行了实战测试。它曾被称为 elasticsearch-transport,因为它是官方 Elasticsearch 客户端的基础。然而,在客户端的 8.0.0 版本中,我们将传输库迁移到了 elastic-transport,因为它还支持官方企业搜索客户端和最近的 Elasticsearch 无服务器(severless)客户端。

它默认使用 Faraday 实现,支持我们之前看到的几种不同的适配器。你还可以使用库中包含的 Manticore 和 Curb(libcurl 的 Ruby 绑定)实现。你甚至可以编写自己的实现,或者使用我们在这里介绍的一些库编写实现。但这将是另一篇博客文章的主题!

Elastic Transport 还可以用作与 Elasticsearch 交互的 HTTP 库。它将处理你需要的一切,并且具有许多与 Elastic 使用相关的设置和不同配置。这里使用的版本是最新的8.3.5。一个简单的例子:

require 'bundler/inline'

gemfile do
  source 'https://rubygems.org'
  gem 'elastic-transport'
end

host = URI(ENV['ES_LOCAL_URL'])
headers = { 'Authorization' => "ApiKey #{ENV['ES_LOCAL_API_KEY']}" }

# Instantiate a new Transport client
transport = Elastic::Transport::Client.new(hosts: host)

# Make a request to the root path ('info') to make sure we can connect:
response = transport.perform_request('GET', '/', {}, nil, headers)

# Create an index
index = 'elastic-transport_docs'
response = transport.perform_request('PUT', "/#{index}", {}, nil, headers)
response.body
# => {"acknowledged"=>true, "shards_acknowledged"=>true, "index"=>"elastic-transport_docs"}

# Index a document
document = { name: 'elastic-transport', description: 'Official Elastic Ruby HTTP transport layer' }.to_json
response = transport.perform_request('POST', "/#{index}/_doc", {}, document, headers)
response.body
# => {"_index"=>"elastic-transport_docs", "_id"=> ... }

# Get the document we just indexed
id = response.body['_id']
response = transport.perform_request('GET', "/#{index}/_doc/#{id}", {}, nil, headers)
response.body['_source']
# => {"name"=>"elastic-transport", "description"=>"Official Elastic Ruby HTTP transport layer"}

# Search for a document
search_body = { query: { match_all: {} } }
response = transport.perform_request('POST', "/#{index}/_search", {}, search_body, headers)
response.body.dig('hits', 'hits').first
# => {"_index"=>"elastic-transport_docs", ..., "_source"=>{"name"=>"elastic-transport", "description"=>"Official Elastic Ruby HTTP transport layer"}}

# Update the document
body = { doc: { name: 'elastic-transport', description: 'Official Elastic Ruby HTTP transport layer.' } }.to_json
response = transport.perform_request('POST', "/#{index}/_update/#{id}", {}, body, headers)
response.body
# => {"_index"=>"elastic-transport_docs", ... }

# Delete a document
response = transport.perform_request('DELETE', "/#{index}/_doc/#{id}", {}, nil, headers)
response.body
# => {"_index"=>"elastic-transport_docs", ... }

结论

如你所见,Elasticsearch Ruby 客户端做了很多工作,让你可以轻松地在 Ruby 代码中与 Elasticsearch 交互。在这篇博文中,我们甚至没有深入讨论如何处理更复杂的请求或处理错误。但 Elasticsearch 的 REST API 使其可以与任何支持 HTTP 请求的库一起使用,无论是 Ruby 还是其他任何语言。Elasticsearch REST API 指南是了解可用 API 及其使用方法的绝佳参考。

准备好自己尝试一下了吗?开始免费试用。

想要获得 Elastic 认证?了解下一期 Elasticsearch 工程师培训何时举行!

原文:How to use Elasticsearch with popular Ruby tools - Search Labs

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

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

相关文章

【从零开发Mybatis】引入XNode和XPathParser

引言 在上文&#xff0c;我们发现直接使用 DOM库去解析XML 配置文件&#xff0c;非常复杂&#xff0c;也很不方便&#xff0c;需要编写大量的重复代码来处理 XML 文件的读取和解析&#xff0c;代码可读性以及可维护性相当差&#xff0c;使用起来非常不灵活。 因此&#xff0c…

深度学习:对评论信息的情感分析,建立模型,自动识别评论信息的情绪状态完整代码实现

评论 思考&#xff1a;向模型中传递数据时&#xff0c;需要提前处理好数据 1、目标&#xff1a;将评论内容转换为词向量。 2、每个词/字转换为词向量长度(维度)200 3、每一次传入的词/字的个数是否就是评论的长度? 应该是固定长度&#xff0c;每次传入数据与图像相似…

DIY我的世界磁力方块

引子 小朋友喜欢我的世界&#xff0c;就像当年我那代对俄罗斯方块的执着&#xff0c;考虑电子游戏伤眼睛&#xff0c;所以最近开始给小朋友买磁力方块。 一个将近1元多的价格&#xff0c;催生我DIY的念头。 正文 Freecad图&#xff0c;A,B,C,D处 放磁铁 5.14g 材料费 最后的成…

Axure中继器单选、多选和重置

亲爱的小伙伴&#xff0c;在您浏览之前&#xff0c;烦请关注一下&#xff0c;在此深表感谢&#xff01; 课程主题&#xff1a;Axure中继器单选、多选和重置 主要内容&#xff1a;根据查询条件&#xff0c;通过单选、多选和重置&#xff0c;从中继器中得到数据 应用场景&…

DockerCompose快速部署Java项目、nginx前端和mysql数据库到centos虚拟机

简介&#xff1a;整理自&#xff1a;SpringCloud微服务开发与实战&#xff0c;java黑马商城项目微服务实战开发&#xff08;涵盖MybatisPlus、Docker、MQ、ES、Redis高级等&#xff09;课程的飞书文档。 DockerCompose介绍 大家可以看到&#xff0c;我们部署一个简单的java项…

stm32实现esp8266连接到TCP服务器(二)未完

1.2 连接到TCP Server 1.2.1 使用网络助手&#xff0c;设立TCP服务器 ​ 编辑 1.2.2 连接服务器 ATCIPSTART"TCP","192.168.1.18",8080 //指令&#xff0c;注意双引号逗号都要半角(英文)输入 CONNECT //结果&#xff1a;成功 OK //结果&#xff1a;成功 …

[C++]ecplise C++新建项目跑hello world

测试通过版本&#xff1a; ecplise-cpp 2024-09 ecplise-cpp 2020-09 【前提】 安装好MinGW环境&#xff0c;实际测试不需要下载什么CDT插件就可以运行了。 步骤&#xff1a; &#xff08;1&#xff09;打开ecplise,选择launch 选择File->New->C/C Project 选择C M…

Java_数组的使用

一、数组的介绍 数组可以存放多个同一类型的数据。数组也是一种数据类型&#xff0c;是引用类型。 即&#xff1a;数&#xff08;数据&#xff09;组&#xff08;一组&#xff09;就是一组数据 二、代码演示 public class Array01 {public static void main(String[] args) …

DMAIC赋能智能家居:解锁未来生活新篇章!

从清晨自动拉开的窗帘&#xff0c;到夜晚自动调暗的灯光&#xff0c;每一处细节都透露着科技的温度与智慧的光芒。而在这场智能革命的浪潮中&#xff0c;DMAIC&#xff08;定义Define、测量Measure、分析Analyze、改进Improve、控制Control&#xff09;作为六西格玛管理的核心方…

React之组件渲染性能优化

关键词&#xff1a; shouldComponentUpdate、PureComnent、React.memo、useMemo、useCallback shouldComponentUpdate 与 PureComnent shouldComponentUpdate 与 PureComnent 用于类组件。虽然官方推荐使用函数组件&#xff0c;但我们依然需要对类组件的渲染优化策略有所了解…

10 排序算法:冒泡排序与快速排序(算法原理、算法实现、时间和空间复杂度分析)

目录 1 十大常见的排序算法 1.1 算法的稳定性 2 冒泡排序 2.1 算法原理 2.2 算法实现 2.3 时间空间复杂度分析 2.3.1 时间复杂度分析 2.3.2 空间复杂度分析 3 快速排序 3.1 算法原理 3.1.1 排序思想 3.1.2 递归过程 3.2 示例 3.2.1 示例 1 3.2.2 示例 2 3.2.3 …

RHCE--网络服务

第一章 例行性工作 1、单一执行的例行性工作&#xff08;at&#xff09; 1.1 查看at命令 at的黑名单&#xff08;deny&#xff09;、白名单&#xff08;allow&#xff09;&#xff1b;两个文件若都不存在则只有root用户能使用 at工作调度对应的系统服务 atd&#xff1a;at的…

N9305高品质mp3音频语音芯片ic在早教故事机的应用方案

随着人们对教育的重视程度不断提高&#xff0c;儿童早教机已经成为了很多家庭的教育必备品。N9305音乐芯片在早教故事机中的应用&#xff0c;不仅为孩子们带来了丰富多彩的故事世界&#xff0c;还以其卓越的音质表现和功能&#xff0c;进一步提升了早教体验。 九芯电子N9305高品…

单片机——ADC采样

1、什么是ADC采样&#xff1f; ADC是指将模拟信号转换成数字信号的过程。通俗理解ADC采样就是采集电路中的电压&#xff0c;通过数值的方式表现出来。以STM32F103系列为例&#xff0c;它可以反应0~4095&#xff0c;换句话说&#xff0c;它采集的电压数值上表现为0~4095&#xf…

前端文件流导出

1、前端代码 ​ /** 导出 */ const handleExport async () > {let config {responseType: blob,headers: {Content-Type: application/json,},};const res await getTargetExport(config);const blob new Blob([res]);const fileName PK目标跟进导出列表.xls;const li…

WEB前端作业1

<!DOCTYPE html> <html><head><meta charset"utf-8"><title>用户注册页面</title></head><style type"text/css">#center{text-align: center;background-color: #e9e9e9;}tr td,th{border:1px solid whi…

linux线程 | 同步与互斥 | 互斥(下)

前言&#xff1a;本篇文章主要讲述linux线程的互斥的知识。 讲解流程为先讲解锁的工作原理&#xff0c; 再自己封装一下锁并且使用一下。 做完这些就要输出一堆理论性的东西&#xff0c; 但博主会总结两条结论&#xff01;&#xff01;最后就是讲一下死锁。 那么&#xff0c; 废…

Java-多线程2

什么是线程&#xff1f; 线程是 cpu调度和执行的单位。 多个线程共享进程的堆和方法区资源&#xff0c;但每个线程有自己的程序计数器、虚拟机栈和本地方法栈。 如何实现线程 继承Thread类 实现步骤&#xff1a; 创建自定义类&#xff0c;继承Thread类 重写run方法 创建自定…

深度学习面试笔试之循环神经网络(RNN)、门控循环单元(GRU)、长短期记忆(LSTM)

深度学习面试笔试之循环神经网络RNN、门控循环单元GRU、长短期记忆LSTM 循环神经网络(RNN)1. 什么是RNN1.1 RNN的应用1.2 为什么有了CNN&#xff0c;还要RNN?1.3 RNN的网络结构1.4 双向RNN1.5 BPTT算法 2. 其它类型的RNN3. CNN与RNN的区别4. 为什么RNN 训练的时候Loss波动很大…

aws(学习笔记第七课) 私有子网使用NAT服务器

aws(学习笔记第七课) AWS的私有子网使用NAT服务器 学习内容&#xff1a; AWS的私有子网使用NAT服务器 1. AWS的私有子网使用NAT服务器 在上面的例子的网络构成图中&#xff0c;可能会发现一个问题。就是Private Subnet的Apache server无法访问互联网。比如&#xff0c;当需要…