使用 Elasticsearch、OpenAI 和 LangChain 进行语义搜索
在本教程中,我将引导您使用 Elasticsearch、OpenAI、LangChain 和 FastAPI 构建语义搜索服务。
LangChain 是这个领域的新酷孩子。 它是一个旨在帮助你与大型语言模型 (LLM) 交互的库。 LangChain 简化了与 LLMs 相关的许多日常任务,例如从文档中提取文本或在向量数据库中对它们建立索引。 如果你现在正在与 LLMs 一起工作,LangChain 可以节省你的工作时间。
然而,它的一个缺点是,尽管它的文档很广泛,但可能比较分散,对于新手来说很难理解。 此外,大多数在线内容都集中在最新一代的向量数据库上。 由于许多组织仍在使用 Elasticsearch 这样经过实战考验的技术,我决定使用它编写一个教程。
我将 LangChain 和 Elasticsearch 结合到了最常见的 LLM 应用之一:语义搜索。 在本教程中,我将引导你使用 Elasticsearch、OpenAI、LangChain 和 FastAPI 构建语义搜索服务。 你将创建一个应用程序,让用户可以提出有关马可·奥勒留《沉思录》的问题,并通过从书中提取最相关的内容为他们提供简洁的答案。
让我们深入了解吧!
前提条件
你应该熟悉这些主题才能充分利用本教程:
-
Elasticsearch:语义搜索、知识图和向量数据库概述
-
Elasticsearch:关于在 Python 中使用 Elasticsearch 你需要知道的一切 - 8.x
此外,你必须安装 Docker 并在 OpenAI 上创建一个帐户。
设计语义搜索服务
你将构建一个包含三个组件的服务:
- 索引器:这将创建索引,生成嵌入和元数据(在本例中为书籍的来源和标题),并将它们添加到向量数据库中。
- 矢量数据库:这是一个用于存储和检索生成的嵌入的数据库。
- 搜索应用程序:这是一个后端服务,它使用用户的搜索词,从中生成嵌入,然后在矢量数据库中查找最相似的嵌入。
这是该架构的示意图:
接下来,你将设置本地环境。
设置你的本地环境
请按照以下步骤设置您的本地环境:
1)安装 Python 3.10。
2)安装 Poetry。 它是可选的,但强烈推荐。
sudo pip install poetry
3) 克隆项目的存储库:
git clone https://github.com/liu-xiao-guo/semantic-search-elasticsearch-openai-langchain
4)从项目的根文件夹中,安装依赖项:
- 使用 Poetry:在项目同目录下创建虚拟环境并安装依赖:
poetry config virtualenvs.in-project true
poetry install
- 使用 venv 和 pip:创建虚拟环境并安装 requirements.txt 中列出的依赖项:
python3.10 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
5)打开 src/.env-example,添加你的 OpenAI 密钥,并将文件另存为 .env。
(.venv) $ pwd
/Users/liuxg/python/semantic-search-elasticsearch-openai-langchain/src
(.venv) $ ls -al
total 32
drwxr-xr-x 7 liuxg staff 224 Sep 17 17:27 .
drwxr-xr-x 13 liuxg staff 416 Sep 17 21:23 ..
-rw-r--r-- 1 liuxg staff 41 Sep 17 17:27 .env-example
-rw-r--r-- 1 liuxg staff 870 Sep 17 17:27 app.py
-rw-r--r-- 1 liuxg staff 384 Sep 17 17:27 config.py
drwxr-xr-x 3 liuxg staff 96 Sep 17 17:27 data
-rw-r--r-- 1 liuxg staff 840 Sep 17 17:27 indexer.py
(.venv) $ mv .env-example .env
(.venv) $ vi .env
到目前为止,你将设置一个包含所需库和存储库的本地副本的虚拟环境。 你的项目结构应该如下所示:
.
├── LICENSE
├── README.md
├── docker-compose.yml
├── .env
├── poetry.lock
├── pyproject.toml
├── requirements.txt
└── src├── app.py├── config.py├── .env├── .env-example ├── data│ └── Marcus_Aurelius_Antoninus_-_His_Meditations_concerning_himselfe└── indexer.py
请注意:在上面的文件结构中,有两个 .env 文件。根目录下的 .env 文件是为 docker-compose.yml 文件所使用,而 src 目录里的文件是为应用所示使用。我们可以在根目录里的 .env 文件中定义想要的 Elastic Stack 版本号。
这些是项目中最相关的文件和目录:
- poetry.lock 和 pyproject.toml:这些文件包含项目的规范和依赖项,被 Poetry 用来创建虚拟环境。
- requirements.txt:该文件包含项目所需的 Python 包列表。
- docker-compose.yml:此文件包含用于在本地运行 Elasticsearch 集群及 Kibana。
- src/app.py:该文件包含搜索应用程序的代码。
- src/config.py:此文件包含项目配置规范,例如 OpenAI 的 API 密钥(从 .env 文件读取)、数据路径和索引名称。
- src/data/:该目录包含最初从维基文库下载的 Meditations 。 你将使用它作为本教程的文本语料库。
- src/indexer.py:此文件包含用于创建索引并将文档插入 Elasticsearch 的代码。
- .env-example:此文件通常用于环境变量。 在本例中,你可以使用它将 OpenAI 的 API 密钥传递给您的应用程序。
- .venv/:该目录包含项目的虚拟环境。
全做完了! 我们继续向下进行吧。
启动本地 Elasticsearch 集群
在我们进入代码之前,你应该启动一个本地 Elasticsearch 集群。 打开一个新终端,导航到项目的根文件夹,然后运行:
docker-compose up
在上面的部署中,出于方便,我们使用了没有带安全的 Elastic Stack 的安装以方便进行开发。具体的安装步骤,请参阅另外一篇文章 “Elasticsearch:如何在 Docker 上运行 Elasticsearch 8.x 进行本地开发”。如果一切顺利,我们可以使用如下的命令来进行查看:
docker ps
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a2866c0356a2 kibana:8.9.2 "/bin/tini -- /usr/l…" 4 minutes ago Up 4 minutes 0.0.0.0:5601->5601/tcp kibana
b504079c59ea elasticsearch:8.9.2 "/bin/tini -- /usr/l…" 4 minutes ago Up 4 minutes 0.0.0.0:9200->9200/tcp, 9300/tcp elasticsearch
我们可以在浏览器中针对 Elasticsearch 进行访问:
我们还可以在 localhost:5601 上访问 Kibana:
拆分书籍并为其建立索引
在此步骤中,你将执行两件事:
- 通过将书中的文本拆分为 1,000 个 token 的块来处理该文本。
- 对你在 Elasticsearch 集群中生成的文本块(从现在开始称为文档)建立索引。
看一下 src/indexer.py:
from langchain.document_loaders import BSHTMLLoader
from langchain.embeddings.openai import OpenAIEmbeddings
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.vectorstores import ElasticVectorSearchfrom config import Paths, openai_api_keydef main():loader = BSHTMLLoader(str(Paths.book))data = loader.load()text_splitter = RecursiveCharacterTextSplitter.from_tiktoken_encoder(chunk_size=1000, chunk_overlap=0)documents = text_splitter.split_documents(data)embeddings = OpenAIEmbeddings(openai_api_key=openai_api_key)db = ElasticVectorSearch.from_documents(documents,embeddings,elasticsearch_url="http://localhost:9200",index_name="elastic-index",)print(db.client.info())if __name__ == "__main__":main()
此代码采用 Meditations(书),将其拆分为 1,000 个 token 的文本块,然后在 Elasticsearch 集群中为这些块建立索引。 以下是详细的细分:
- 第 1 行到第 4 行从 langchain 导入所需的组件:
- BSHTMLLoader:此 Loader 使用 BeautifulSoup4 来解析文档。
- OpenAIembeddings:该组件是 OpenAI 嵌入的包装器。 它可以帮助你生成文档和查询的嵌入。
- RecursiveCharacterTextSplitter:此实用程序函数通过尝试按旨在保持语义相似内容邻近的顺序尝试各种字符来分割输入文本。 用于分割的字符按以下顺序排列为:“\n\n”、“\n”、“ ”、“”。
- ElasticSearchVector:这是 Elasticsearch 客户端的包装器,可简化与集群的交互。
- 第 6 行从 config.py 导入相关配置
- 第 11 行和第 12 行使用 BSHTMLLoader 提取书籍的文本。
- 第 13 至 16 行初始化文本拆分器,并将文本拆分为不超过 1,000 个标记的块。 在这种情况下,你可以使用 tiktoken 来计算 token,但你也可以使用不同长度的函数,例如计算字符数而不是 token 或不同的 token 化函数。
- 第 18 至 25 行初始化嵌入函数,创建新索引,并对文本拆分器生成的文档建立索引。 在 elasticsearch_url 中,你指定应用程序在本地运行的端口,在index_name 中指定你将使用的索引的名称。 最后,打印 Elasticsearch 客户端信息。
要运行此脚本,请打开终端,激活虚拟环境,然后从项目的 src 文件夹中运行以下命令:
# ../src/
export export OPENAI_API_KEY=your_open_ai_token
python indexer.py
注意:你如果使用 OpenAI 来进行矢量化,那么你需要在你的账号中有充分的钱来支付这种费用,否则你可能得到如下的错误信息:
Retrying langchain.embeddings.openai.embed_with_retry.<locals>._embed_with_retry in 4.0 seconds as it raised RateLimitError: You exceeded your current quota, please check your plan and billing details..
如果一切顺利,你应该得到与此类似的输出:
{'name': '0e1113eb2915', 'cluster_name': 'docker-cluster', 'cluster_uuid': 'og6mFMqwQtaJiv_3E_q2YQ', 'version': {'number': '8.9.2', 'build_flavor': 'default', 'build_type': 'docker', 'build_hash': '09520b59b6bc1057340b55750186466ea715e30e', 'build_date': '2023-03-27T16:31:09.816451435Z', 'build_snapshot': False, 'lucene_version': '9.5.0', 'minimum_wire_compatibility_version': '7.17.0', 'minimum_index_compatibility_version': '7.0.0'}, 'tagline': 'You Know, for Search'}
接下来,让我们创建一个简单的 FastAPI 应用程序,以与你的集群进行交互。
创建搜索应用程序
在此步骤中,你将创建一个简单的应用程序来与 Meditations 交互。 你将连接到 Elasticsearch 集群,始化检索提问/应答 Chain,并创建一个 /ask 端点以允许用户与应用程序交互。
看一下 src/app.py 的代码:
from fastapi import FastAPI
from langchain.chains import RetrievalQA
from langchain.chat_models import ChatOpenAI
from langchain.embeddings.openai import OpenAIEmbeddings
from langchain.vectorstores import ElasticVectorSearchfrom config import openai_api_keyembedding = OpenAIEmbeddings(openai_api_key=openai_api_key)db = ElasticVectorSearch(elasticsearch_url="http://localhost:9200",index_name="elastic-index",embedding=embedding,
)
qa = RetrievalQA.from_chain_type(llm=ChatOpenAI(temperature=0),chain_type="stuff",retriever=db.as_retriever(),
)app = FastAPI()@app.get("/")
def index():return {"message": "Make a post request to /ask to ask questions about Meditations by Marcus Aurelius"}@app.post("/ask")
def ask(query: str):response = qa.run(query)return {"response": response,}
此代码允许用户提出有关马库斯·奥勒留《沉思录》的问题,并向用户提供答案。 让我向你展示它是如何工作的:
- 第 1 至 5 行导入所需的库:
- FastAPI:此类初始化应用程序。
- RetrievalQA:这是一个允许你询问有关向量数据库中文档的问题的 Chain。 它根据你的问题找到最相关的文档并从中生成答案。
- ChatOpenAI:这是 OpenAI 聊天模型的包装。
- OpenAIembeddings 和 ElasticVectorSearch:这些是上一节中讨论的相同包装器。
- 第 7 行导入 OpenAI 密钥。
- 第 9 至 15 行使用 OpenAI 嵌入初始化 Elasticsearch 集群。
- 第 16 至 20 行使用以下参数初始化 RetrievalQA Chain:
- llm:指定用于运行链中定义的提示的 LLM。
- chain_type:定义如何从向量数据库检索和处理文档。 通过指定内容,将检索文档并将其传递到链以按原样回答问题。 或者,你可以在回答问题之前使用 map_reduce 或 map_rerank 进行额外处理,但这些方法使用更多的 API 调用。 有关更多信息,请参阅 langchain 文档。
- retrieve:指定链用于检索文档的向量数据库。
- 第 22 至 36 行初始化 FastAPI 应用程序并定义两个端点。 / 端点为用户提供有关如何使用应用程序的信息。 /ask 端点接受用户的问题(查询参数)并使用先前初始化的链返回答案。
最后,你可以从终端运行该应用程序(使用你的虚拟环境):
uvicorn app:app --reload
然后,访问 http://127.0.0.1:8000/docs,并通过询问有关这本书的问题来测试 /ask:
如果一切顺利,你应该得到这样的结果:
就是这样! 您现在已经启动并运行了自己的基于 Elasticsearch、OpenAI、Langchain 和 FastAPI 的语义搜索服务。
结论
干得好! 在本教程中,你学习了如何使用 Elasticsearch、OpenAI 和 Langchain 构建语义搜索引擎。
特别是,你已经了解到:
- 如何构建语义搜索服务。
- 如何使用 LangChain 对文档进行拆分和索引。
- 如何使用 Elasticsearch 作为向量数据库与 LangChain 一起使用。
- 如何使用检索问答链通过向量数据库回答问题。
- 产品化此类应用程序时应考虑什么。
希望您觉得本教程有用。 如果你有任何疑问,请参入讨论!
相关文章:
![](https://img-blog.csdnimg.cn/4b5e0e360fe347ec88de69eafaee3454.png)
使用 Elasticsearch、OpenAI 和 LangChain 进行语义搜索
在本教程中,我将引导您使用 Elasticsearch、OpenAI、LangChain 和 FastAPI 构建语义搜索服务。 LangChain 是这个领域的新酷孩子。 它是一个旨在帮助你与大型语言模型 (LLM) 交互的库。 LangChain 简化了与 LLMs 相关的许多日常任务,例如从文档中提取文本…...
![](https://img-blog.csdnimg.cn/6b135972ea9b4c98b2a5c2e528f44efa.png)
NIFI集群_队列Queue中数据无法清空_清除队列数据报错_无法删除queue_解决_集群中机器交替重启删除---大数据之Nifi工作笔记0061
今天发现,有两个处理器,启动以后,数据流不过去,后来,锁定问题在,queue队列上面,因为别的队列都可以通过,右键,empty queue清空,就是 这个队列不行,这个队列无法被删除,至于为什么导致这样的, 猜测是因为之前,流程设计好以后,队列没有设置背压,也没有设置队列中的内容大小和fl…...
![](https://www.ngui.cc/images/no-images.jpg)
leetcode20. 有效的括号 [简单题]
题目 给定一个只包括 (,),{,},[,] 的字符串 s ,判断字符串是否有效。 有效字符串需满足: 左括号必须用相同类型的右括号闭合。左括号必须以正确的顺序闭合。每个右括号都有一个对应的相同类型…...
![](https://img-blog.csdnimg.cn/85716c98d531477abd339590036ed3d6.png)
ubuntu20.04下源码编译colmap
由于稠密重建需要CUDA,因此先安装CUDA,我使用的是3050GPU,nvidia-smi显示最高支持CUDA11.4。 不要用sudo apt安装,版本较低,30系显卡建议安装CUDA11.0以上,这里安装了11.1版本。 下载: cuda_1…...
![](https://img-blog.csdnimg.cn/f1c5d76452c14b6e9ca29e2efccadb87.png)
Jumpserver堡垒机
一、堡垒机概述 1、堡垒机的基本概念 堡垒机也是一台服务器,在一个特定的网络环境下,为了保障网络和数据不受来自外部和内部用户的入侵和破坏,而运用各种技术手段实时收集、监控网络环境中每一个组成部分(服务器)的系…...
![](https://img-blog.csdnimg.cn/08a9e73765d6475da10fdae4f4a3fda0.gif#pic_center)
第一百五十三回 如何实现滑动窗口
文章目录 概念介绍实现方法示例代码 我们在上一章回中介绍了自定义组件实现游戏摇杆相关的内容,本章回中将介绍 如何实现滑动窗口.闲话休提,让我们一起Talk Flutter吧。 概念介绍 我们在本章回中介绍的滑动窗口表示在屏幕底部向上滑动时弹出一个窗口&a…...
![](https://img-blog.csdnimg.cn/27f9d4f272b8465daa5300db8361dc07.png)
Oracle 12c自动化管理特性的新进展:自动备份、自动恢复和自动维护功能的优势|oracle 12c相对oralce 11g的新特性(3)
一、前言: 前面几期讲解了oracle 12c多租户的使用、In-Memory列存储来提高查询性能以及数据库的克隆、全局数据字典和共享数据库资源的使用 今天我们讲讲oracle 12c的另外的一个自动化管理功能新特性:自动备份、自动恢复、自动维护的功能 二、自动备份、自动恢复、自动维护…...
![](https://www.ngui.cc/images/no-images.jpg)
Redis——Jedis中hash类型使用
hset 和 hget hset可以逐一添加key和value,也可以通过map类型来直接添加多组fields 而hget则返回string类型,如果元素不存在则返回null private static void hsetAndHget(Jedis jedis) {jedis.flushAll();jedis.hset("key", "f1"…...
![](https://img-blog.csdnimg.cn/e5f9633b470f4b5dafef97a749c29ee2.png)
肖sir__项目实战讲解__004
项目实战讲解 一、项目的类型 金融类: 保险(健康险理财险)、证券、基金(股票型基金、混合型基金、指数型基金、债券型基金、 天天基金网(ETF基金、货币型基金、量化基金)、银行、贷款、信用卡、外汇、二元期权、期货原油、blockchain、 数字货币、黄金白…...
![](https://img-blog.csdnimg.cn/3dcc53e5c6fc4c73b27a5bb955e9cc70.jpeg)
数据库数据恢复-ORACLE常见故障有哪些?恢复数据的可能性高吗?
ORACLE数据库常见故障: 1、ORACLE数据库无法启动或无法正常工作。 2、ORACLE数据库ASM存储破坏。 3、ORACLE数据库数据文件丢失。 4、ORACLE数据库数据文件部分损坏。 5、ORACLE数据库DUMP文件损坏。 ORACLE数据库数据恢复可能性分析: 1、ORACLE数据库无…...
![](https://www.ngui.cc/images/no-images.jpg)
合规性管理如何帮助产品团队按时交付?
成功的产品和产品发布背后通常需要经过一个涉及多个监督机构、多功能团队和利益相关者的复杂流程。在组织的治理、风险管理和合规性(GRC)框架下,产品团队不仅需要追求市场创新,还需要确保符合所有适用的法规、标准和合同要求。由于…...
![](https://img-blog.csdnimg.cn/8d156eaeaf8d4845a6a28596d2c59b5a.png)
从平均数到排名算法
平均数用更少的数字,概括一组数字。属于概述统计量、集中趋势测度、位置测度。中位数是第二常见的概述统计量。许多情况下比均值更合适。算术平均数是3中毕达哥拉斯平均数之一,另外两种毕达哥拉斯平均数是几何平均数和调和平均数。 算术平均 A M 1 n ∑…...
![](https://www.ngui.cc/images/no-images.jpg)
如何使用ESP8266微控制器和Nextion显示器为Home Assistant展示温度传感器和互联网天气预报
第一部分:引言与项目概述 在智能家居领域,实时监控和显示环境数据已经成为了一个热门的话题。无论是室内温度、室外温度,还是游泳池的温度,都可以通过各种传感器轻松获取。但如何将这些数据以直观、美观的方式展现出来呢…...
![](https://img-blog.csdnimg.cn/9f2c96e7efd543e8a1fbd7e3f1d00198.png)
阻塞队列-生产者消费者模型
阻塞队列介绍标准库阻塞队列使用基于阻塞队列的简单生产者消费者模型。实现一个简单型阻塞队列 (基于数组实现) 阻塞队列介绍 不要和之前学多线程的就绪队列搞混; 阻塞队列:也是一个队列,先进先出。带有特殊的功能 &…...
![](https://img-blog.csdnimg.cn/097d0432541944d69ad3f4f912f09439.png#pic_center)
Vector Art - 矢量艺术
什么是矢量艺术? 矢量图形允许创意人员构建高质量的艺术作品,具有干净的线条和形状,可以缩放到任何大小。探索这种文件格式如何为各种规模的项目提供创造性的机会。 什么是矢量艺术作品? 矢量艺术是由矢量图形组成的艺术。这些图形是基于…...
![](https://www.ngui.cc/images/no-images.jpg)
ruoyi-nbcio增加flowable流程待办消息的提醒,并提供右上角的红字数字提醒(一)
更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码: https://gitee.com/nbacheng/ruoyi-nbcio 演示地址:RuoYi-Nbcio后台管理系统 1、数据库表方面 在原来sys_notice修改基础上增加一个表叫sys_notice_send 表结构如下: DROP …...
![](https://img-blog.csdnimg.cn/7890dfb757d443feaebe33d1430522a9.png)
数据结构:二叉树的基本概念
文章目录 1. 二叉树的定义2. 二叉树的特点3. 特殊二叉树斜树满二叉树完全二叉树 4. 二叉树的性质 1. 二叉树的定义 如果我们猜一个100以内的数字,该怎么猜才能理论最快呢? 第一种方式:从1,2一直猜到100, 反正数字都是100以内,总能猜到的 第二种方式:先猜50,如果比结果小,猜75…...
![](https://www.ngui.cc/images/no-images.jpg)
利用Socks5代理IP加强跨界电商爬虫的网络安全
随着跨界电商的兴起,爬虫技术在这个领域变得越来越重要。然而,网络安全一直是一个值得关注的问题。在本文中,我们将讨论如何利用代理IP和Socks5代理来增强跨界电商爬虫的网络安全,确保稳定和可靠的数据采集,同时避免封…...
![](https://img-blog.csdnimg.cn/87f874124d0245afb092f04a6c800ea5.png)
Spring学习笔记6 Bean的实例化方式
Spring学习笔记5 GoF之工厂模式_biubiubiu0706的博客-CSDN博客 Spring为Bean提供了多种实例化方式,通常包括4中(目的:更加灵活) 1.通过构造方法实例化 2.通过简单工厂模式实例化 3.通过factory-bean实例化 4.通过FactoryBean接口实例化 新建模块 spring-005 依赖 <!--S…...
![](https://www.ngui.cc/images/no-images.jpg)
大二毕设.3-网盘系统-用户模块讲解
目录 模块功能介绍 具体实现讲解 constants层:存放用户模块常量类 entity层:存放实体类,与数据库中的属性值基本保持一致 mapper层:对数据库进行数据持久化操作 service层:业务逻辑层,主要是针对具体…...
![](https://img-blog.csdnimg.cn/504bcf50186a4ababc6e8a63e42704d6.png)
(Vue2)智慧商城项目
新增两个目录api、utils api接口模块:发送ajax请求的接口模块 utils工具模块:自己封装的一些工具方法模块 第三方组件库vant-ui PC端:element-ui(element-plus) ant-design-vue 移动端:vant-ui Mint UI…...
![](https://img-blog.csdnimg.cn/9998bbc4dda843169da45b41770fa049.png)
Nginx实战
虚拟主机 虚拟主机指的就是⼀个独⽴的站点,具有独⽴的域名,有完整的www服务,例如⽹站、FTP、邮件等 。Nginx⽀持多虚拟主机,在⼀台机器上可以运⾏完全独⽴的多个站点。⼀些草根流量站⻓,常会搭建个⼈站点进⾏资源分享交…...
![](https://www.ngui.cc/images/no-images.jpg)
day-57 代码随想录算法训练营(19)动态规划 part 17
647.回文子串 思路:动态规划 1.dp存储:判断以i开始,j结尾的字符串是否是回文串2.动态转移方程:当s[i]s[j]时,如果j-i<1,d[i][j]true; 如果 dp[i1][j-1]true,那么dp[i][j…...
![](https://img-blog.csdnimg.cn/e59f7fc0219148028b1440de52dabf65.png)
在项目中,关于前端实现数据可视化的技术选择
前言 在项目中,数据可视化以图表、报表类型为主。 需求背景 技术框架是Vue2.x版本,组件库是Ant Design of Vue能够支撑足够多的图表类型开发图表大小/位置能够随意变动图表样式需要支持丰富多样的用户配置强大、开放的图表语法支持复杂的数据可视化场景…...
![](https://img-blog.csdnimg.cn/489187045d814824b2bf50269a502be4.png)
DT 卡通材质学习 一
渐变着色器 相交线 笔刷和卡通结合使用 修改器...
![](https://www.ngui.cc/images/no-images.jpg)
【游戏引擎架构】6.2 资源管理器
资源管理器可以分为离线部分系统和运行时系统 文章目录 离线资源管理数据库资产管道 运行时资源管理文件结构内存管理文件间引用 离线资源管理 数据库 UE的数据库可以直接浏览、编辑资产,看到运行时的状态;但也存在两个较大的缺点: 版本管…...
![](https://img-blog.csdnimg.cn/a33a9689603f4dfbb6362d1c65112d9a.png)
spring的ThreadPoolTaskExecutor装饰器传递调用线程信息给线程池中的线程
概述 需求是想在线程池执行任务的时候,在开始前将调用线程的信息传到子线程中,在子线程完成后,再清除传入的数据。 下面使用了spring的ThreadPoolTaskExecutor来实现这个需求. ThreadPoolTaskExecutor 在jdk中使用的是ThreadPoolExecutor…...
![](https://img-blog.csdnimg.cn/e5afb0442cf84b78b80079eb174ea66c.png)
转载 - 洞察问题本质,解决工作难题
作者:关苏哲 高效管理者的三大技能 问题界定的6个问题 1.你所需要解决的问题是什么? 2.你为什么需要解决这个问题? 3.你期待的理想结果是什么? 4.这个问题包括哪些子问题? 5.你曾经尝试过哪些解决方式?…...
![](https://img-blog.csdnimg.cn/img_convert/3fba9b34b546f6ea3dac50c54f543490.png)
关于计算机找不到d3dx9_43.dll,无法继续执行代码修复方法
d3dx9_43.dll是一个动态链接库文件,它是DirectX的一个组件,主要用于处理游戏中的图形、声音等多媒体元素。当这个文件丢失时,可能会导致以下问题: 1. 游戏无法正常运行:由于d3dx9_43.dll负责处理游戏中的多媒体元素&a…...
![](https://img-blog.csdnimg.cn/59e4caa7b6b5427fb00fab64b5442845.gif)
《从零开始的Java世界》01基本程序设计
《从零开始的Java世界》系列主要讲解Javase部分,从最简单的程序设计到面向对象编程,再到异常处理、常用API的使用,最后到注解、反射,涵盖Java基础所需的所有知识点。学习者应该从学会如何使用,到知道其实现原理全方位式…...
![](/images/no-images.jpg)
动漫制作技术就业前景/seo服务套餐
转自:https://www.pinlue.com/article/2020/01/1616/439904883431.html...
![](/images/no-images.jpg)
网站制作和网页制作区别/百度推广账户优化
一.类模板当做模板的参数 #include<iostream> #include<string> using namespace std; //类模板当做一个类的参数 template<class T> class ren //一个通用的类模板 { public:T name;ren(T t):name(t){}}; template<template<class T>class T1>…...
![](https://img-blog.csdnimg.cn/20210901155444662.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5L2O5ZCffua1heWUsQ==,size_18,color_FFFFFF,t_70,g_se,x_16)
建站系统下载 discuz/网络代运营推广
$x array(1,2,3,4,5); var_dump($x);//除去下标在为3底下的值 unset($x[3]); var_dump($x);//除去下标为3的值后面重新排序 $x array_values($x); var_dump($x);...
![](/images/no-images.jpg)
旅游wordpress/手机百度账号登录入口
一、简介 EhCache 是一个纯Java的进程内缓存框架,具有快速、精干等特点。ehcache官网:http://www.ehcache.org/ 可以下载文档看看,里面关于EhCache缓存写的非常清楚。 二、特点 主要的特性有: 1. 快速 2. 简单 3. 多种缓存策略 …...
![](https://img-blog.csdnimg.cn/img_convert/418da5a05c017579af16378ace10a9ab.png)
wordpress评论显示ua/百度电话客服24小时人工服务热线
spring源码阅读环境(几分钟下载包)简述: 1.下载spring源码: 2.安装gradle: 3.构建源码: 4.导入idea:简述:不能忍受慢(看到这里你就准备笑吧!!)其他大神的博客实在让我难受自己动手,下…...
![](/images/no-images.jpg)
灵犀科技 网站开发/网络推广工作能长久吗
<input type"number" name"phone" id"phone" /> IOS环境下,复制号码,粘贴到input,然后点击一个按钮,获取不到里面的值。 安卓环境可以 解决方法: <input type"text"…...