当前位置: 首页 > news >正文

Elasticsearch:智能 RAG,获取周围分块(二)

在之前的文章 “Elasticsearch:智能 RAG,获取周围分块(一) ” 里,它介绍了如何实现智能 RAG,获取周围分块。在那个文章里有一个 notebook。为了方便在本地部署的开发者能够顺利的运行那里的 notebook。在本篇文章里,我来详述如何进行配置。

安装

Elastisearch 及 Kibana

 如果你还没有安装好自己的 Elasticsearch 及 Kibana,请参考如下的链接来进行安装:

  • 如何在 Linux,MacOS 及 Windows 上进行安装 Elasticsearch
  • Kibana:如何在 Linux,MacOS 及 Windows上安装 Elastic 栈中的 Kibana

在安装的时候,我们选择 Elastic Stack 8.x 来进行安装。特别值得指出的是:ES|QL 只在 Elastic Stack 8.11 及以后得版本中才有。你需要下载 Elastic Stack 8.11 及以后得版本来进行安装。

在首次启动 Elasticsearch 的时候,我们可以看到如下的输出:

 我们需要记下 Elasticsearch 超级用户 elastic 的密码。

我们还可以在安装 Elasticsearch 目录中找到 Elasticsearch 的访问证书:

$ pwd
/Users/liuxg/elastic/elasticsearch-8.14.0/config/certs
$ ls
http.p12      http_ca.crt   transport.p12

在上面,http_ca.crt 是我们需要用来访问 Elasticsearch 的证书。

我们首先克隆已经写好的代码:

git clone https://github.com/liu-xiao-guo/elasticsearch-labs

我们然后进入到该项目的根目录下:

$ pwd
/Users/liuxg/python/elasticsearch-labs/supporting-blog-content/fetch-surrounding-chunks
$ cp ~/elastic/elasticsearch-8.14.0/config/certs/http_ca.crt .
$ ls
README.md      fetch-surrounding-chunks.ipynb 
http_ca.crt

在上面,我们把 Elasticsearch 的证书拷贝到当前的目录下。上面的 09-geospatial-search.ipynb 就是我们下面要展示的 notebook。

启动白金试用

在下面,我们需要使用 ELSER。这是一个白金试用的功能。我们按照如下的步骤来启动白金试用:

这样我们就完成了白金试用功能。

获取 Elasticsearch API key

我们在 Kibana 中,进行如下的步骤:

点击上面的拷贝按钮,我们就可以得到所需要的 Elastic API key。

 创建环境变量

为了能够使得下面的应用顺利执行,在项目当前的目录下运行如下的命令:

export ES_ENDPOINT="localhost"
export ES_USER="elastic"
export ES_PASSWORD="Xw4_Nohry-LgaOum6oh-"
export ELASTIC_API_KEY="WXhDakhwQUJFQklhemFRdVRQTkw6V3A0TFFieFZTRjJDdzFZbkF5dGVyUQ=="

在上面,我们需要根据自己的 Elasticsearch 配置来进行设置。

下载文档

在我们的例程中,它讲使用哈利波特的文字来进行练习。这个文字,我们可以在地址进行获得。我们可以通过如下的方式来进行下载:

curl -o harry_potter.txt https://raw.githubusercontent.com/amephraim/nlp/master/texts/J.%20K.%20Rowling%20-%20Harry%20Potter%201%20-%20Sorcerer\'s%20Stone.txt
$ pwd
/Users/liuxg/python/elasticsearch-labs/supporting-blog-content/fetch-surrounding-chunks
$ ls
README.md                      fetch-surrounding-chunks.ipynb http_ca.crt
$ curl -o harry_potter.txt https://raw.githubusercontent.com/amephraim/nlp/master/texts/J.%20K.%20Rowling%20-%20Harry%20Potter%201%20-%20Sorcerer\'s%20Stone.txt% Total    % Received % Xferd  Average Speed   Time    Time     Time  CurrentDload  Upload   Total   Spent    Left  Speed
100  429k  100  429k    0     0   274k      0  0:00:01  0:00:01 --:--:--  274k

这样我们可以在当前目录下看到一个叫做 harry_potter.txt 的文件:

$ ls
README.md                      harry_potter.txt
fetch-surrounding-chunks.ipynb http_ca.crt

安装 Python 响应的包

pip3 install python-dotenv elasticsearch==8.14.0 pandas eland

好了,我们的一切准备工作就完成了。我们在下面,就可以打开 notebook 来进行练习了。

代码展示

我们可以使用如下的命令来启动 notebook:

jupyter notebook fetch-surrounding-chunks.ipynb
$ pwd
/Users/liuxg/python/elasticsearch-labs/supporting-blog-content/fetch-surrounding-chunks
$ jupyter notebook fetch-surrounding-chunks.ipynb 

安装及导入包

!pip install elasticsearch==8.14.0
!pip install pandas
!python -m pip install elandimport json
import time
import urllib.request
import re
import pandas as pd
from transformers import AutoTokenizer, BertTokenizer
from elasticsearch import Elasticsearch, helpers, exceptions
import textwrap

如果在上面已经安装了所需要的包,那么我们可以省去上面的安装命令。

读入变量并连接到 Elasticsearch

from elasticsearch import Elasticsearch
from dotenv import load_dotenv
import os
from transformers import BertTokenizer, BertForMaskedLMload_dotenv()raw_source_index = "harry_potter_dataset-raw"
index_name = "harry_potter_dataset_enriched"dense_embedding_model_id = "sentence-transformers__all-minilm-l6-v2"
dense_huggingface_model_id = "sentence-transformers/all-MiniLM-L6-v2"
dense_model_number_of_allocators = 2elser_model_id = ".elser_model_2"
elser_model_number_of_allocators = 2bert_tokenizer = BertTokenizer.from_pretrained("bert-base-uncased")SEMANTIC_SEARCH_TOKEN_LIMIT = 500
ELSER_TOKEN_OVERLAP = 0.0# Create the client instance
load_dotenv()ES_USER = os.getenv("ES_USER")
ES_PASSWORD = os.getenv("ES_PASSWORD")
ES_ENDPOINT = os.getenv("ES_ENDPOINT")
ELASTIC_API_KEY = os.getenv("ELASTIC_API_KEY")url = f"https://{ES_USER}:{ES_PASSWORD}@{ES_ENDPOINT}:9200"
print(url)esclient = Elasticsearch(url, ca_certs = "./http_ca.crt", verify_certs = True)
print(esclient.info())

如果你运行顺利的话,那么你可以看到如下的输出结果:

它表明我们的 Elasticsearch 客户端连接是成功的。

导入模型

在这里,我们用到脚本来上传所需要的模型。使用 eland_import_hub_model 脚本,下载并安装 all-MiniLM-L6-v2 转换器模型。将 NLP --task-type 设置为 text_embedding。

要验证你的请求,请使用 Elastic API API 密钥。 

CA_CERT = "./http_ca.crt"
print(url)
!eland_import_hub_model --url $url --es-model-id {dense_embedding_model_id} --hub-model-id {dense_huggingface_model_id} --task-type text_embedding --es-api-key $ELASTIC_API_KEY --ca-cert $CA_CERT --start --clear-previous
resp = esclient.ml.update_trained_model_deployment(model_id=dense_embedding_model_id,body={"number_of_allocations": dense_model_number_of_allocators},
)
print(resp)
https://elastic:Xw4_Nohry-LgaOum6oh-@localhost:9200
2024-06-17 07:36:04,762 INFO : Establishing connection to Elasticsearch
2024-06-17 07:36:04,781 INFO : Connected to cluster named 'elasticsearch' (version: 8.14.0)
2024-06-17 07:36:04,781 INFO : Loading HuggingFace transformer tokenizer and model 'sentence-transformers/all-MiniLM-L6-v2'
STAGE:2024-06-17 07:36:09 54226:14164655 ActivityProfilerController.cpp:314] Completed Stage: Warm Up
STAGE:2024-06-17 07:36:09 54226:14164655 ActivityProfilerController.cpp:320] Completed Stage: Collection
STAGE:2024-06-17 07:36:09 54226:14164655 ActivityProfilerController.cpp:324] Completed Stage: Post Processing
2024-06-17 07:36:09,768 WARNING : `SentenceTransformer._target_device` has been removed, please use `SentenceTransformer.device` instead.
2024-06-17 07:36:09,768 WARNING : `SentenceTransformer._target_device` has been removed, please use `SentenceTransformer.device` instead.
2024-06-17 07:36:09,996 WARNING : `SentenceTransformer._target_device` has been removed, please use `SentenceTransformer.device` instead.
2024-06-17 07:36:09,996 WARNING : `SentenceTransformer._target_device` has been removed, please use `SentenceTransformer.device` instead.
2024-06-17 07:36:10,705 INFO : Stopping deployment for model with id 'sentence-transformers__all-minilm-l6-v2'
2024-06-17 07:36:10,806 INFO : Deleting model with id 'sentence-transformers__all-minilm-l6-v2'
2024-06-17 07:36:10,962 INFO : Creating model with id 'sentence-transformers__all-minilm-l6-v2'
2024-06-17 07:36:11,120 INFO : Uploading model definition
100%|███████████████████████████████████████| 87/87 [00:03<00:00, 25.11 parts/s]
2024-06-17 07:36:14,584 INFO : Uploading model vocabulary
2024-06-17 07:36:14,622 INFO : Starting model deployment
2024-06-17 07:36:16,031 INFO : Model successfully imported with id 'sentence-transformers__all-minilm-l6-v2'
{'assignment': {'task_parameters': {'model_id': 'sentence-transformers__all-minilm-l6-v2', 'deployment_id': 'sentence-transformers__all-minilm-l6-v2', 'model_bytes': 90303522, 'threads_per_allocation': 1, 'number_of_allocations': 2, 'queue_capacity': 1024, 'cache_size': '90303522b', 'priority': 'normal', 'per_deployment_memory_bytes': 90269696, 'per_allocation_memory_bytes': 291876956}, 'routing_table': {'PEyvsErNSXu8NbrlO_HPxA': {'current_allocations': 1, 'target_allocations': 2, 'routing_state': 'started', 'reason': ''}}, 'assignment_state': 'started', 'start_time': '2024-06-16T23:36:14.652847Z', 'max_assigned_allocations': 1}}

这个步骤,你可以参考之前的文章 “Elasticsearch:如何部署 NLP:文本嵌入和向量搜索” 来在命令行中进行部署。运行完上面的命令后,你需要在 Kibana 界面中进行选择:

下载及部署 ELSER 模型

对于一些开发者对 ELSER 还不是很熟的话,那么请阅我之前的文章 “Elasticsearch:部署 ELSER - Elastic Learned Sparse EncoderR”。

# delete model if already downloaded and deployed
try:esclient.ml.delete_trained_model(model_id=elser_model_id, force=True)print("Model deleted successfully, We will proceed with creating one")
except exceptions.NotFoundError:print("Model doesn't exist, but We will proceed with creating one")# Creates the ELSER model configuration. Automatically downloads the model if it doesn't exist.
esclient.ml.put_trained_model(model_id=elser_model_id, input={"field_names": ["text_field"]}
)

在上面,它删除已经部署好的 ELSER,并重新对它进行部署。

Model deleted successfully, We will proceed with creating one
ObjectApiResponse({'model_id': '.elser_model_2', 'model_type': 'pytorch', 'model_package': {'packaged_model_id': 'elser_model_2', 'model_repository': 'https://ml-models.elastic.co', 'minimum_version': '11.0.0', 'size': 438123914, 'sha256': '2e0450a1c598221a919917cbb05d8672aed6c613c028008fedcd696462c81af0', 'metadata': {}, 'tags': [], 'vocabulary_file': 'elser_model_2.vocab.json'}, 'created_by': 'api_user', 'version': '12.0.0', 'create_time': 1718580981790, 'model_size_bytes': 0, 'estimated_operations': 0, 'license_level': 'platinum', 'description': 'Elastic Learned Sparse EncodeR v2', 'tags': ['elastic'], 'metadata': {}, 'input': {'field_names': ['text_field']}, 'inference_config': {'text_expansion': {'vocabulary': {'index': '.ml-inference-native-000002'}, 'tokenization': {'bert': {'do_lower_case': True, 'with_special_tokens': True, 'max_sequence_length': 512, 'truncate': 'first', 'span': -1}}}}, 'location': {'index': {'name': '.ml-inference-native-000002'}}})

上述命令将下载 ELSER 模型。这将需要几分钟才能完成。使用以下命令检查模型下载的状态。

while True:status = esclient.ml.get_trained_models(model_id=elser_model_id, include="definition_status")if status["trained_model_configs"][0]["fully_defined"]:print("ELSER Model is downloaded and ready to be deployed.")breakelse:print("ELSER Model is downloaded but not ready to be deployed.")time.sleep(5)
ELSER Model is downloaded but not ready to be deployed.
ELSER Model is downloaded but not ready to be deployed.
ELSER Model is downloaded but not ready to be deployed.
ELSER Model is downloaded but not ready to be deployed.
ELSER Model is downloaded and ready to be deployed.

下载模型后,我们可以在 ML 节点中部署该模型。使用以下命令部署模型。这也需要几分钟才能完成。

# Start ELSER model deployment if not already deployed
esclient.ml.start_trained_model_deployment(model_id=elser_model_id,number_of_allocations=elser_model_number_of_allocators,wait_for="starting",
)while True:status = esclient.ml.get_trained_models_stats(model_id=elser_model_id,)if status["trained_model_stats"][0]["deployment_stats"]["state"] == "started":print("ELSER Model has been successfully deployed.")breakelse:print("ELSER Model is currently being deployed.")time.sleep(5)
ELSER Model is currently being deployed.
ELSER Model has been successfully deployed.

一旦部署完毕,我们可以在 Kibana 中进行查看:

写入数据

import codecs
f = codecs.open("harry_potter.txt", "r", "utf-8")
harry_potter_book_text = f.read()chapter_pattern = re.compile(r"CHAPTER [A-Z]+", re.IGNORECASE)
chapters = chapter_pattern.split(harry_potter_book_text)[1:]
chapter_titles = re.findall(chapter_pattern, harry_potter_book_text)
chapters_with_titles = list(zip(chapter_titles, chapters))print("Total chapters found:", len(chapters))
if chapters_with_titles:print("First chapter title:", chapters_with_titles[0][0])print("Text sample from first chapter:", chapters_with_titles[0][1][:500])# Structuring chapters into a DataFrame
df = pd.DataFrame(chapters_with_titles, columns=["chapter_title", "chapter_full_text"])
df["chapter"] = df.index + 1
df["book_title"] = "Harry Potter and the Sorcerer’s Stone"
df["passages"] = df["chapter_full_text"].apply(lambda text: chunk(text))
Total chapters found: 17
First chapter title: CHAPTER ONE
Text sample from first chapter: THE BOY WHO LIVEDMr. and Mrs. Dursley, of number four, Privet Drive, were proud to say
that they were perfectly normal, thank you very much. They were the last
people you'd expect to be involved in anything strange or mysterious,
because they just didn't hold with such nonsense.Mr. Dursley was the director of a firm called Grunnings, which made
drills. He was a big, beefy man with hardly any neck, although he did
have a very large mustache. Mrs. Dursley was thin and blonde and had
nearly t

上面的代码把文章按照每个 chapter 来进行拆分:

然后,我们通过如下的代码,把每个 chapter 写入到 Elasticsearch 中:

ndex_dataframe(esclient, raw_source_index, df)
Indexing documents to harry_potter_dataset-raw...
Successfully indexed 17 documents.
Failed to index 0 documents.

我们可以在 Kibana 中进行查看:

Elasticsearch 中的异步重新索引

此部分启动异步重新索引操作,将数据从原始源索引传输到 Elasticsearch 中的丰富索引。此过程在后台运行,允许其他操作继续进行而无需等待完成。

关键步骤

  1. 启动重新索引:从 raw_source_index 到 index_name 触发重新索引操作,将 wait_for_completion 设置为 False 以允许异步执行。
  2. 检索任务 ID:捕获并打印重新索引操作的任务 ID 以用于监控目的。
  3. 监控进度:check_task_status 函数持续检查重新索引任务的状态,每 10 秒提供一次更新,直到操作完成。
# Start the reindex operation asynchronously
response = esclient.reindex(body={"source": {"index": raw_source_index}, "dest": {"index": index_name}},wait_for_completion=False,
)
task_id = response["task"]
print("Task ID:", task_id)
check_task_status(esclient, task_id)

在上面 reindex 的过程中,它讲自动调用 index_name 所定义的 default_pipeline。这个在上面的代码中所定义:

index_settings = {"settings": {"number_of_shards": 2,"number_of_replicas": 0,"default_pipeline": "books_dataset_chunker",},"mappings": {"dynamic": "false","properties": {"book_title": {"type": "keyword"},"chapter": {"type": "keyword"},"chapter_full_text": {"type": "text", "index": False},"passages": {"type": "nested","properties": {"content_embedding": {"properties": {"is_truncated": {"type": "boolean"},"model_id": {"type": "text","fields": {"keyword": {"type": "keyword", "ignore_above": 256}},},"predicted_value": {"type": "sparse_vector"},}},

请注意上面的 default_pipeline。这个在 reindex 时,会自动调用。这个 pipeline 的定义是在 pipeline_body 中所定义的:

# Define the ingest pipeline configuration
pipeline_body = {"description": "Pipeline for processing book passages","processors": [{"foreach": {"field": "passages","processor": {"inference": {"field_map": {"_ingest._value.text": "text_field"},"model_id": dense_embedding_model_id,"target_field": "_ingest._value.vector","on_failure": [{"append": {"field": "_source._ingest.inference_errors","value": [{"message": "Processor 'inference' in pipeline 'ml-inference-title-vector' failed with message '{{ _ingest.on_failure_message }}'","pipeline": "ml-inference-title-vector","timestamp": "{{{ _ingest.timestamp }}}",}],}}],}},}},{"foreach": {"field": "passages","processor": {"inference": {"field_map": {"_ingest._value.text": "text_field"},"model_id": elser_model_id,"target_field": "_ingest._value.content_embedding","on_failure": [{"append": {"field": "_source._ingest.inference_errors","value": [{"message": "Processor 'inference' in pipeline 'ml-inference-title-vector' failed with message '{{ _ingest.on_failure_message }}'","pipeline": "ml-inference-title-vector","timestamp": "{{{ _ingest.timestamp }}}",}],}}],}},}},],
}

它分别针对 passages 中的每个段落进行 dene vector 的向量化(使用 sentence-transformers__all-minilm-l6-v2 模型),同时也针对它进行 sparse vectore 的向量化(使用 ELSER 模型):

整个 reindex 需要一定的时间来完成:

Task ID: PEyvsErNSXu8NbrlO_HPxA:122681
Indexing...
Indexing...
Indexing...
Indexing...
Indexing...
Indexing...
Indexing...
Indexing...
Indexing...
Reindexing complete.

等 reindex 完成后,我们可以在 Kibana 中进行查看:

也就是说,同样一个 passage,被同时密集向量化和稀疏向量化。我们可以看到每个 chunk 都是同样的。我们可以通过如下的方法来查看每个 chapter 最多的 chunk 数值:

GET harry_potter_dataset_enriched/_search
{"size": 0,"query": {"match": {"chapter": "1"}},"aggs": {"max_passage_number": {"nested": {"path": "passages"},"aggs": {"max_number": {"max": {"field": "passages.chunk_number"}}}}}
}

或者通过如下的方法来得到各个 chapter 的 passages 数值:

GET harry_potter_dataset_enriched/_search
{"size": 0,"aggs": {"chapter_chunks": {"terms": {"field": "chapter"},"aggs": {"max_passage_number": {"nested": {"path": "passages"},"aggs": {"max_number": {"max": {"field": "passages.chunk_number"}}}}}}}
}

自定义搜索查询的构建和执行

本节在 Elasticsearch 中构建和执行自定义搜索查询,利用结合向量和基于文本的搜索方法的混合方法来提高搜索准确性和相关性。使用的具体示例是关于“Nimbus 2000” 的用户查询。

关键步骤

  1. 定义用户查询:将用户查询指定为“what is a nimbus 2000”。
  2. 设置提升因子
    1.  knn_boost_factor:用于放大 vector-based 的搜索组件的重要性的值。
    2. text_expansion_boost:用于修改 text-based 的搜索组件的权重的值。 
  3. 构建查询:build_custom_query 函数构建搜索查询,结合密集向量和文本扩展组件。
  4. 执行搜索:针对指定的 Elasticsearch 索引执行查询。
  5. 识别相关段落
    1.  分析搜索结果以找到相关性得分最高的段落。
    2. 捕获并打印最佳匹配段落的 ID 和 chunk 编号。 
  6. 获取周围区块:构建并执行查询以检索与已识别段落相邻的区块,以获得更广泛的上下文。如果匹配的区块是第一个区块,则获取 n、n+1 和 n+2。如果该区块是章节中的最后一区块,则获取 n、n-1 和 n-2。对于其他区块,则获取 n-1、n 和 n+1。
  7. 显示结果:输出相关和相邻段落的文本。
# Custom Search Query Construction
user_query = "what is a nimbus 2000"knn_boost_factor = 20
text_expansion_boost = 1
query = build_custom_query(build_vector(user_query),user_query,knn_boost_factor,text_expansion_boost,debug=False,
)# Searching and identifying relevant passages
results = esclient.search(index=index_name, body=query, _source=False)hit_id = None
chunk_number = None
chapter_number = None
max_chunk_number = None
max_chapter_chunk_result = None
max_chunk_query = Noneif results and results.get("hits") and results["hits"].get("hits"):highest_score = -1best_hit = Nonehit_id = results["hits"]["hits"][0]["_id"]chapter_number = results["hits"]["hits"][0]["fields"]["chapter"][0]if "inner_hits" in results["hits"]["hits"][0]:for hit_type in ["text_hits", "dense_hit", "sparse_hits"]:if hit_type in results["hits"]["hits"][0]["inner_hits"]:inner_hit = results["hits"]["hits"][0]["inner_hits"][hit_type]["hits"]if inner_hit["hits"]:max_score = inner_hit["max_score"]if max_score and max_score > highest_score:highest_score = max_scorebest_hit = inner_hit["hits"][0]if best_hit:first_passage_text = best_hit["_source"]["text"]chunk_number = best_hit["_source"]["chunk_number"]# print(f"Matched Chunk ID: {hit_id}, Chunk Number: {chunk_number}, Text: {first_passage_text}")print(f"Matched Chunk ID: {hit_id}, Chunk Number: {chunk_number}, Text:\n{textwrap.fill(first_passage_text, width=200)}")print(f"\n")else:print(f"ID: {hit_id}, No relevant passages found.")
else:print("No results found.")# Fetch Surrounding Chunks if chapter_number is not None
if chapter_number is not None:print(f"Fetch Surrounding Chunks")print(f"------------------------")# max_chunk_query = get_max_chunk_number_query(chapter_number, debug=False)# max_chapter_chunk_result = esclient.search(index=index_name, body=max_chunk_query, _source=False)max_chapter_chunk_result = esclient.search(index=index_name,body=get_max_chunk_number_query(chapter_number, debug=False),_source=False,)max_chunk_number = max_chapter_chunk_result["aggregations"]["max_chunk_number"]["max_chunk"]["value"]adjacent_chunks_query = get_adjacent_chunks_query(hit_id, chunk_number, max_chunk_number, debug=False)results = esclient.search(index=index_name, body=adjacent_chunks_query, _source=False)print_text_from_results(results)
else:print("Skipping fetch of surrounding chunks due to no initial results.")

  

完整的代码可以在地址 elasticsearch-labs/supporting-blog-content/fetch-surrounding-chunks at main · liu-xiao-guo/elasticsearch-labs · GitHub 进行下载。

相关文章:

Elasticsearch:智能 RAG,获取周围分块(二)

在之前的文章 “Elasticsearch&#xff1a;智能 RAG&#xff0c;获取周围分块&#xff08;一&#xff09; ” 里&#xff0c;它介绍了如何实现智能 RAG&#xff0c;获取周围分块。在那个文章里有一个 notebook。为了方便在本地部署的开发者能够顺利的运行那里的 notebook。在本…...

华为---RIP路由协议的汇总

8.3 RIP路由协议的汇总 8.3.1 原理概述 当网络中路由器的路由条目非常多时&#xff0c;可以通过路由汇总(又称路由汇聚或路由聚合)来减少路由条目数&#xff0c;加快路由收敛时间和增强网络稳定性。路由汇总的原理是&#xff0c;同一个自然网段内的不同子网的路由在向外(其他…...

Python基础——字符串常见用法:切片、去空格、替换、拼接

文章目录 专栏导读1、拼接字符串2、获取字符串长度3、字符串切片4、字符串替换&#xff1a;5、字符串分割6、字符串查找7、字符串大小写转换8、字符串去除空白9、字符串格式化&#xff1a;10、字符串编码与解码&#xff1a;11、字符串判断12、字符串填充与对齐总结 专栏导读 &a…...

LeetCode.51N皇后详解

问题描述 按照国际象棋的规则&#xff0c;皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。 n 皇后问题 研究的是如何将 n 个皇后放置在 nn 的棋盘上&#xff0c;并且使皇后彼此之间不能相互攻击。 给你一个整数 n &#xff0c;返回所有不同的 n 皇后问题 的解决方案…...

计算机网络之奇偶校验码和CRC冗余校验码

今天我们来看看有关于计算机网络的知识——奇偶校验码和CRC冗余校验码&#xff0c;这两种检测编码的方式相信大家在计算机组成原理当中也有所耳闻&#xff0c;所以今天我就来跟大家分享有关他们的知识。 奇偶校验码 奇偶校验码是通过增加冗余位使得码字中1的个数恒为奇数或偶数…...

二叉树经典OJ练习

个人主页&#xff1a;C忠实粉丝 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 C忠实粉丝 原创 二叉树经典OJ练习 收录于专栏【数据结构初阶】 本专栏旨在分享学习数据结构学习的一点学习笔记&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; 目录 前置说…...

【OpenHarmony4.1 之 U-Boot 2024.07源码深度解析】008 - make distclean 命令解析

【OpenHarmony4.1 之 U-Boot 2024.07源码深度解析】008 - make distclean 命令解析 一、make V=1 distclean 命令解析系列文章汇总:《【OpenHarmony4.1 之 U-Boot 源码深度解析】000 - 文章链接汇总》 本文链接:《【OpenHarmony4.1 之 U-Boot 2024.07源码深度解析】008 - mak…...

QTreeView双击任意列展开

一.效果 二.原理 重点是如何通过其他列的QModelIndex(假设为index),获取第一列的QModelIndex(假设为firstColumnIndex)。代码如下所示: QModelIndex firstColumnIndex = model->index(index.row(), 0, index.parent()); 这里要注意index函数的第三个参数,第三个参…...

Linux入门攻坚——26、Web Service基础知识与httpd配置-2

http协议 URL&#xff1a;Uniform Resource Locator&#xff0c;统一资源定位符 URL方案&#xff1a;scheme&#xff0c;如http://&#xff0c;https:// 服务器地址&#xff1a;IP&#xff1a;port 资源路径&#xff1a; 示例&#xff1a;http://www.test.com:80/bbs/…...

相由心生与事出反常必有妖

从端午节之日生病起&#xff0c;已就医三次&#xff0c;快半个月了。医检的结论是老病复发—— 上呼吸道感染 。原本并无大碍&#xff0c;加之“水不在深&#xff0c;有龙则灵”的张龙医生处方得当&#xff0c;现已病情好转。只是“800727”趁人之危&#xff0c;兴灾乐祸地欲从…...

微信小程序---支付

一、判断是否登录 如果没有登录&#xff0c;走前端登录流程&#xff0c;不再赘述 二、获取订单编号 跟自己的后端商议入参&#xff0c;然后获取订单编号 三、通过订单编号获取wx.requestPayment()需要的参数 获取订单编号再次请求后端接口&#xff0c;拿到wx.requestPayme…...

Git学习2 -- VSCode中的Git

看了下&#xff0c;主要的插件有3个。自带的Source Control。第1个是Gitlens&#xff0c;第2个是Git Graph。第三个还有个git history。 首先是Source Control。界面大概是这样的。 还是挺直观的。在第一栏source control&#xff0c;可以进行基本的git操作。主要的git操作都是…...

VC++支持断点续下或续传的功能

VC使用多线程和Socket实现断点续下 一、断点续下的基本原理&#xff1a; 1.断点续传的理解可以分为两部分&#xff1a;一部分是断点&#xff0c;一部分是续传。断点的由来是在下载过程中&#xff0c;将一个下载文件分成了多个部分&#xff0c;同时进行多个部分一起的下载&…...

机器学习数学原理专题——线性分类模型:损失函数推导新视角——交叉熵

目录 二、从回归到线性分类模型&#xff1a;分类 3.分类模型损失函数推导——极大似然估计法 &#xff08;1&#xff09;二分类损失函数——极大似然估计 &#xff08;2&#xff09;多分类损失函数——极大似然估计 4.模型损失函数推导新视角——交叉熵 &#xff08;1&#x…...

windows和linux路径斜杆转换脚本,打开即用

前言&#xff1a; windows和linux的目录路径斜杆是相反的&#xff0c;在ssh或者其他什么工具在win和ubuntu传文件时候经常需要用到两边的路径&#xff0c;有这个工具就不用手动去修改斜杆反斜杠了。之前有个在线网站&#xff0c;后来挂了&#xff0c;就想着自己搞一个脚本来用。…...

在Android系统中,查看apk安装路径

在Android系统中&#xff0c;应用通常安装在内部存储的特定目录下。要找到已安装应用的路径&#xff0c;可以通过ADB&#xff08;Android Debug Bridge&#xff09;工具来查询。以下是一些步骤和命令&#xff0c;可以帮助你找到应用的安装路径&#xff1a; 使用pm list package…...

管理不到位,活该执行力差?狠抓这4点要素,强化执行力

管理不到位&#xff0c;活该执行力差&#xff1f;狠抓这4点要素&#xff0c;强化执行力 一&#xff1a;强化制度管理 1、权责分明&#xff0c;追责管理 要知道&#xff0c;规章制度其实就是一种“契约”。 在制定制度和规则的时候&#xff0c;民主一点&#xff0c;征求团队成员…...

应届毕业之本科简历制作

因为毕设以及编制岗位面试&#xff0c;最近好久没有更新了&#xff0c;刚好有同学问如何制作简历&#xff0c;我就准备将我自己制作简历的流程分享给各位&#xff0c;到此也算是一个小的结束&#xff0c;拿了工科学位证书毕业去做&#x1f402;&#x1f40e;了。 简历主要包含内…...

SparkOnHive_列转行、行转列生产操作(透视和逆透视)

前言 行专列&#xff0c;列转行是数开不可避免的一步&#xff0c;尤其是在最初接触Hive的时候&#xff0c;看到什么炸裂函数&#xff0c;各种udf&#xff0c;有点发憷&#xff0c;无从下手&#xff0c;时常产生这t怎么搞&#xff0c;我不会啊&#xff1f; 好吧&#xff…...

【人机交互 复习】第2章 Hadoop

一、概念 1.Hadoop 是一个能够对大量数据进行分布式处理的软件框架&#xff0c;并 且是以一种可靠、高效、可伸缩的方式进行处理的&#xff0c; 2.特点&#xff1a; 高可靠性&#xff0c;高效性&#xff0c;高可扩展性&#xff0c;高容错性 运行在Linux平台上&#xff0c;支持…...

国产自研编程语言“仓颉”来了!

在 6.21 召开的华为开发者大会&#xff08;HDC2024&#xff09;上,华为自研的国产编程语言“仓颉”终于对外正式发布了&#xff01; 随着万物互联以及智能时代的到来&#xff0c;软件的形态将发生巨大的变化。一方面&#xff0c;移动应用和移动互联网领域仍然强力驱动人机交互…...

Swarm 集群管理

Swarm 集群管理 简介 Docker Swarm 是 Docker 的集群管理工具。它将 Docker 主机池转变为单个虚拟 Docker 主机。 Docker Swarm 提供了标准的 Docker API&#xff0c;所有任何已经与 Docker 守护程序通信的工具都可以使用 Swarm 轻松地扩展到多个主机。 支持的工具包括但不限…...

从社交网络到元宇宙:Facebook的战略转型

随着科技的迅猛发展和数字化时代的深入&#xff0c;社交网络已不再局限于简单的信息交流和社交互动&#xff0c;而是逐步向更广阔、更深远的虚拟现实空间——元宇宙&#xff08;Metaverse&#xff09;转变。作为全球最大的社交网络平台之一&#xff0c;Facebook正在积极推动这一…...

程序猿大战Python——面向对象——继承进阶

方法重写 目标&#xff1a;掌握方法的重写。 当父类的同名方法达不到子类的要求&#xff0c;则可以在子类中对方法进行重写。语法&#xff1a; class 父类名(object):def 方法A(self):代码... class 子类名(父类名):def 方法A(self):代码... 例如&#xff0c;一起来完成&…...

【Linux基础】SSH登录

SSH简介 安全外壳协议&#xff08;Secure Shell Protocol&#xff0c;简称SSH&#xff09;是一种加密的网络传输协议&#xff0c;可在不安全的网络中为网络服务提供安全的传输环境。 SSH通过在网络中建立安全隧道来实现SSH客户端与服务器之间的连接。 SSH最常见的用途是远程登…...

经典机器学习方法(7)—— 卷积神经网络CNN

参考&#xff1a;《动手学深度学习》第六章 卷积神经网络&#xff08;convolutional neural network&#xff0c;CNN&#xff09;是一类针对图像数据设计的神经网络&#xff0c;它充分利用了图像数据的特点&#xff0c;具有适合图像特征提取的归纳偏置&#xff0c;因而在图像相…...

经典面试题【作用域、闭包、变量提升】,带你深入理解掌握!

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;我是前端菜鸟的自我修养&#xff01;今天给大家分享经典面试题【作用域、闭包、变量提升】&#xff0c;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;原创不易&#xff0c;如果能帮助到带大家&#xff0…...

Dockerfile实战

Dockerfile是用来快速创建自定义镜像的一种文本格式的配置文件&#xff0c;在持续集成和持续部署时&#xff0c;需要使用Dockerfile生成相关应用程序的镜像。 Dockerfile常用命令 FROM&#xff1a;继承基础镜像MAINTAINER&#xff1a;镜像制作作者的信息&#xff0c;已弃用&a…...

常用的开源数据集网站

Kaggle&#xff08;https://www.kaggle.com/datasets&#xff09;&#xff1a;Kaggle 是一个著名的数据科学竞赛平台&#xff0c;也提供了大量的开放数据集供用户下载和使用。UCI Machine Learning Repository&#xff08;https://archive.ics.uci.edu/datasets&#xff09;&am…...

html文本被木马病毒植入vbs脚本

我在公司服务器上写了一个静态html&#xff0c;方便导航&#xff0c;结果没过多久发现html文件被修改了&#xff0c;在</html>标签后加了这些代码。 注&#xff1a;WriteData 的内容很长&#xff0c;被我删掉了很多&#xff0c;不然没法提交这个提问 ​ <SCRIPT Lan…...

jsonl 文件介绍

jsonl文件介绍 什么是 jsonl 文件文件结构读取jsonl文件写入jsonl文件 什么是 jsonl 文件 jsonl&#xff08;json lines&#xff09;是一种文件格式&#xff0c;其中每一行都是一个单独的 json 对象。与常规的 json文件不同&#xff0c;jsonl文件在处理大量数据时具有优势&…...

反射机制详解

✅作者简介&#xff1a;大家好&#xff0c;我是Leo&#xff0c;热爱Java后端开发者&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;Leo的博客 &#x1f49e;当前专栏&#xff1a;Java从入门到精通 ✨特色专栏&#xff…...

【数据库】七、数据库安全与保护

七、数据库安全与保护 文章目录 七、数据库安全与保护安全性访问控制数据库安全性控制用户标识和鉴别存取控制自主存取控制(DAC)存取控制方法&#xff1a;授权与回收GRANT授权REVOKE回收 强制存取控制(MAC) MySQL的安全设置用户管理1.创建登录用户2.修改用户密码3.修改用户名4.…...

卡尔曼滤波-剔除异常值的影响

二郎在看论文的时候&#xff0c;发现了一个针对卡尔曼滤波过程中&#xff0c;测量向量出现误差导致滤波发散的处理方法。 该方法也可以扩展到其他问题中使用&#xff0c;所以二郎在这里写一下。 论文原文&#xff1a;https://www.mdpi.com/1424-8220/20/17/4710 论文翻译对应…...

Java程序之动物声音“模拟器”

题目&#xff1a; 设计一个“动物模拟器”&#xff0c;希望模拟器可以模拟许多动物的叫声和行为&#xff0c;要求如下&#xff1a; 编写接口Animal&#xff0c;该接口有两个抽象方法cry()和getAnimalName()&#xff0c;即要求实现该接口的各种具体的动物类给出自己的叫声和种类…...

jieba中文分词器的使用

Jieba 是一个中文分词的第三方库&#xff0c;主要用于对中文文本进行分词。分词是将文本分割成一个个词语的过程&#xff0c;这在中文文本处理中尤为重要&#xff0c;因为中文不像英文那样有明显的空格来分隔词语。Jieba 的分词算法可以实现精确分词、全模式分词和搜索引擎模式…...

【杂记-浅谈OSPF协议中的RouterDeadInterval】

OSPF协议中的RouterDeadInterval 一、RouterDeadInterval概述二、设置RouterDeadInterval三、RouterDeadInterval的重要性 一、RouterDeadInterval概述 RouterDeadInterval&#xff0c;即路由器死区间隔&#xff0c;它涉及到路由器如何在广播网络上发现和维护邻居关系。Router…...

Django 模版变量

1&#xff0c;模版变量作用 模板变量使用“{{ 变量名 }}” 来表示模板变量前后可以有空格&#xff0c;模板变量名称&#xff0c;可以由数字&#xff0c;字母&#xff0c;下划线组成&#xff0c;不能包含空格模板变量还支持列表&#xff0c;字典&#xff0c;对象 2&#xff0c;…...

【数据结构与算法】图的存储(邻接矩阵,邻接表)详解

图的邻接矩阵数据结构 typedef enum { NDG, DG, NDN, DN } GraphKind;using VRType int; using InfoType int;typedef struct ArcCell {VRType adj;InfoType *info; } Arc[N][N];struct MGraph {ElemType vexs[N];Arc arc;int vexnum, arcnum;GraphKind kind; };ArcCell 结构…...

【深度C++】之“类与结构体”

0. 抽象数据类型 类&#xff08;class&#xff09; 和结构体&#xff08;struct&#xff09; 都是C中的自定义数据类型&#xff0c;是使用C实现面向对象编程思想的起点。 类的基本思想是数据抽象&#xff08;data abstraction&#xff09; 和封装&#xff08;encapsulation&a…...

CTO的职责是什么?

看《架构思维》作者是这样讲的&#xff1a; CTO 到底是做什么的&#xff1f; 我当下的答案是&#xff1a;“CTO 就是一个从技术视角出发&#xff0c;为公司或者所在的部门做正确决策的 CEO。”怎么理解这句话呢&#xff1f;作为一个 CTO&#xff0c;其长期目标和决策优先级与…...

【GD32】从零开始学兆易创新32位微处理器——RTC实时时钟+日历例程

1 简介 RTC实时时钟顾名思义作用和墙上挂的时钟差不多&#xff0c;都是用于记录时间和日历&#xff0c;同时也有闹钟的功能。从硬件实现上来说&#xff0c;其实它就是一个特殊的计时器&#xff0c;它内部有一个32位的寄存器用于计时。RTC在低功耗应用中可以说相当重要&#xf…...

HTTP网络协议

1.HTTP &#xff08;1&#xff09;概念&#xff1a; Hyper Text Transfer Protocol&#xff0c;超文本传输协议规定了浏览器和服务器之间数据传输的规则。 &#xff08;2&#xff09;特点 基于TCP协议:面向连接&#xff0c;安全基于请求-响应模型的:一次请求对应一次响应HTTP协…...

Kubernetes相关生态

1、Prometheus、Metrics Server与Kubernetes监控体系 简介&#xff1a; Prometheus 项目与 Kubernetes 项目一样&#xff0c;也来自于 Google 的 Borg 体系&#xff0c;它的原型系统&#xff0c;叫作 BorgMon&#xff0c;是一个几乎与 Borg 同时诞生的内部监控系统 Pro…...

C语言入门4-函数和程序结构

函数举例 读取字符串&#xff0c;如果字符串中含有ould则输出该字符串&#xff0c;否则不输出。 #include <stdio.h>// 函数声明 int getLine(char s[], int lim); int strindex(char s[], char t[]);int main() {char t[] "ould"; // 要查找的目标子字符串…...

分行业二氧化碳排放数据

分行业二氧化碳排放量 资源名称&#xff1a;分行业二氧化碳排放量 数据来源&#xff1a;中国能源统计年鉴 时间范围&#xff1a;1995-2018年指标&#xff1a;八类能源和总量&#xff1a;煤炭、焦炭、原油、汽油、煤油、柴油、燃料油、天然气...

【OS基础】符合AUTOSAR标准的RTAOS-Alarms详解

目录 前言 正文 7.报警Alarms 7.1配置Alarms 7.1.1激活一个任务 7.1.2 设置一个事件 7.1.3报警回调Alarm Callback 7.1.4 增加计数器值 7.2设置Alarms 7.2.1 绝对Alarms 7.2.2 相对Alarm 7.3自启动Alarms 7.4 删除Alarms 7.5确认何时会发生Alarm 7.6非周期Alarm…...

基于Java的学生成绩管理系统

你好呀&#xff0c;我是计算机学姐码农小野&#xff01;如果有相关需求&#xff0c;可以私信联系我。 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;Java技术&#xff0c;B/S结构 工具&#xff1a;MyEclipse&#xff0c;MySQL 系统展示 首页 个人中…...

都2024年了,还有人不懂动态代理么?

文章目录 一、定义二、静态代理三、动态代理1. JDK代理1.1 JDK代理实现流程1.2 动态生成的类字节码 2. Cglib代理2.1 Cglib实现流程 四、总结 一、定义 静态代理和动态代理都反映了一个代理模式&#xff0c;代理模式是一种经典的设计模式&#xff0c;常用于为其他对象提供一种…...

ARM功耗管理框架之PPU

安全之安全(security)博客目录导读 思考&#xff1a;功耗管理框架&#xff1f;SCP&#xff1f;PPU&#xff1f;LPI&#xff1f;之间的关系&#xff1f;如何配合&#xff1f; 目录 一、功耗管理框架中的PPU 二、PPU的结构与连接关系 三、PPU操作模式和电源模式及其之间的转…...

Scala入门学习

Scala是一种现代化的多范式编程语言&#xff0c;它结合了面向对象编程和函数式编程的特点&#xff0c;运行在Java平台上。Scala的语法简洁&#xff0c;同时提供了强大的类型系统和丰富的库支持。下面是一些Scala入门的基础知识点&#xff1a; ### 1. 安装Scala - 下载并安装Sc…...

LeetCode:3115. 质数的最大距离(Java 筛质数)

目录 3115. 质数的最大距离 题目描述&#xff1a; 实现代码与解析&#xff1a; 筛质数 原理思路&#xff1a; 3115. 质数的最大距离 题目描述&#xff1a; 给你一个整数数组 nums。 返回两个&#xff08;不一定不同的&#xff09;质数在 nums 中 下标 的 最大距离。 示…...

机器学习/pytorch笔记:time2vec

1 概念部分 对于给定的标量时间概念 t&#xff0c;Time2Vec 的表示 t2v(t)是一个大小为 k1的向量&#xff0c;定义如下&#xff1a; 其中&#xff0c;t2v(t)[i]是 t2v(t)的第 i 个元素&#xff0c;F是一个周期性激活函数&#xff0c;ω和 ϕ是可学习的参数。 以下是个人理解&am…...

深入理解SLF4J与Logback以及Log4j的关系

在Java开发中&#xff0c;日志记录是一个不可或缺的部分&#xff0c;它帮助开发者监控应用程序的运行状态和调试问题。在众多日志框架中&#xff0c;SLF4J&#xff08;Simple Logging Facade for Java&#xff09;、Logback和Log4j是最为流行的几个。本文将简述它们之间的关系以…...

AI 开发平台(Coze)搭建《美食推荐官》

前言 本文讲解如何从零开始&#xff0c;使用扣子平台去搭建《美食推荐官》 bot直达&#xff1a;美食推荐官 - 扣子 AI Bot (coze.cn) 欢迎大家体验一下&#xff01;&#xff01; 效果 正文 prompt 美食推荐官的首要任务就是推荐美食&#xff0c;基于这个我们要给他一个基…...

Spring Security基本源码解析(超精细版)

一、基本源码解析 1.1 UsernamePasswordAuthenticationFilter 用户名称和密码的过滤器 浏览器发送用户名称和密码 ----》 经过过滤器「UsernamePasswordAuthenticationFitler」 1.2 UsernamePasswordAuthenticationFilter核心方法 重写父类「AbstractAuthenticationProcessing…...

低空经济发展加速碳纤维行业迎增量市场

近日,小鹏汇天旅航者X2在廊坊市成功完成首飞,标志着载人低空飞行器在京津冀地区实现首飞。根据德邦证券的测算,单台eVTOL对碳纤维的需求为100公斤至400公斤。业内人士表示,低空经济腾飞将为碳纤维复合材料带来增量市场,碳纤维行业有望迎来爆发式增长。利好政策频出2024年中…...

售价53.86万元新款奔驰E350eL插混版正式上市

6月1日,在 2024 粤港澳车展上,新款梅赛德斯-奔驰 E 350e L 插混版正式上市,售价 53.86 万元。外观方面,新车整体依旧延续燃油版车型的样子,标志性的“花生”大灯,大尺寸格栅以及立标等元素均得以保留。尺寸方面,新车也是保持一直,长宽高分别为 5092/1880/1489mm,轴距为…...

QT截图程序,可多屏幕截图二,增加调整截图区域功能

上一篇QT截图程序&#xff0c;可多屏幕截图只是实现了最基本的截图功能&#xff0c;虽然能用但是缺点也有&#xff0c;没办法更改选中的区域&#xff0c;这在实际使用时不太方便。这篇增加了这个功能。先看看效果。 实现代码为&#xff1a; 头文件 #ifndef MASKWIDGET_H #de…...

0基础认识C语言(理论+实操 2)

小伙伴们大家好&#xff0c;今天也要撸起袖子加油干&#xff01;万事开头难&#xff0c;越学到后面越轻松~ 话不多说&#xff0c;开始正题~ 前提回顾&#xff1a; 接上次博客&#xff0c;我们学到了转义字符&#xff0c;最后留下两个转义字符不知道大家有没有动手尝试了一遍&a…...

RTKLIB学习--前向滤波

#前言 如果要详细了解RTKLIB或进行二次开发&#xff0c;了解obs指针所存储每个历元的卫星观测数据是必不可少的环节&#xff0c;此文对RTKLIB的&#xff08;由于后处理和实时运行都要用到前向滤波&#xff09;前向滤波&#xff08;从文件头读取观测数据到obs结构体中&#xff0…...

Pi 母公司将开发情感 AI 商业机器人;Meta 科学家:Sora 不是视频生成唯一方向丨RTE 开发者日报 Vol.214

开发者朋友们大家好&#xff1a; 这里是 「RTE 开发者日报」 &#xff0c;每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享 RTE&#xff08;Real-Time Engagement&#xff09; 领域内「有话题的新闻」、「有态度的观点」、「有意思的数据」、「有思考的文章」、「…...