LangChain+LLM实战---LlamaIndex、正确使用索引

LlamaIndex简介

LlamaIndex(也称为GPT Index)是一个用户友好的界面,它将您的外部数据连接到大型语言模型(Large Language Models, llm)。它提供了一系列工具来简化流程,包括可以与各种现有数据源和格式(如api、pdf、文档和SQL)集成的数据连接器。此外,LlamaIndex为结构化和非结构化数据提供索引,可以毫不费力地与大语言模型一起使用。

本文将讨论LlamaIndex提供的不同类型的索引以及如何使用它们。这可能包括列表索引、矢量存储索引、树索引和关键字表索引的分解,以及特殊索引,如图索引、Pandas索引、SQL索引和文档摘要索引。此外,我将详细介绍每个索引的情况,可能有必要讨论使用LlamaIndex的成本,并将其与其他选项进行比较。

为什么我们需要LlamaIndex ?

商业ChatGPT还不够好吗?

是的,它在一般用例中可能足够了,但请记住,我们的目标是在您的文档湖(类比数据湖)上构建通用聊天机器人应用程序。想想你的公司文档可能有超过1000页,那么ChatGPT广告将不足以分析你的东西。主要原因是token的限制。

  • GPT-3: 2000 tokens
  • GPT-3.5: 4000 tokens
  • GPT-4: 提升到32.000 tokens

1,000 tokens大概是750单词

img

GPT-3, GPT-3.5, GPT-4和LlamaIndex被Flyps接受的tokens数量

LlamaIndex是如何适应的?

如果可用的tokens不多,则无法在prompt中输入更大的数据集,这可能会限制您对模型的操作。然而,您仍然可以训练模型,尽管有一些优点和缺点需要考虑。不过别担心,LlamaIndex会帮你的!

使用LlamaIndex,您可以为各种数据集(如文档、pdf和数据库)建立索引,然后轻松地查询它们以查找所需的信息。

想象一下,只需点击几下就可以访问您需要的所有信息!您可以直接向知识库、Slack和其他通信工具以及数据库和几乎所有SaaS内容提出复杂的问题,而无需以任何特殊方式准备数据。最好的部分是什么?您将得到由GPT推理能力支持的答案,所有这些都在几秒钟内完成,甚至不必将任何内容复制和粘贴到prompts符中。

通过正确实现GPT Index,您可以使这一切成为可能!在下一节中,我们将深入研究不同类型的索引,以及为您的应用程序准备的适用代码。

用LlamaIndex索引

在能够有效地用自然语言提出问题并获得准确的答案之前,有必要对相关数据集进行索引。如前所述,LlamaIndex能够索引广泛的数据类型,随着GPT-4即将到来,多模式索引也将很快可用。这一部分,我们将研究LlamaIndex提供的不同类型的索引,看看什么索引用于什么用例。

在深入了解索引的细节之前,您应该知道LlamaIndex的核心是将文档分解为多个Node对象。节点是LlamaIndex中的一等公民。节点表示源文档的“块”,无论是文本块、图像块还是更多。它们还包含元数据以及与其他节点和索引结构的关系信息。当您创建索引时,它抽象了节点的创建,但是,如果您的需求需要,您可以手动为文档定义节点。

让我们先设置一些底层代码。

  • 安装库
1
2
pip install llama-index
pip install openai
  • 安装OpenAI API Key
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import os
os.environ['OPENAI_API_KEY'] = '<YOUR_OPENAI_API_KEY>'import logging
import sys## showing logs
logging.basicConfig(stream=sys.stdout, level=logging.INFO)
logging.getLogger().addHandler(logging.StreamHandler(stream=sys.stdout))## load the PDF
from langchain.text_splitter import RecursiveCharacterTextSplitter
from llama_index import download_loader# define loader
UnstructuredReader = download_loader('UnstructuredReader', refresh_cache=True)
loader = UnstructuredReader()# load the data
documents = loader.load_data('../notebooks/documents/Apple-Financial-Report-Q1-2022.pdf',split_documents=False)

列表Index

列表索引是一种简单的数据结构,其中节点按顺序存储。在索引构建期间,文档文本被分块、转换为节点并存储在列表中。

img

来自LlamaIndex官方文件

在查询期间,如果没有指定其他查询参数,LlamaIndex只是将列表中的所有node加载到Response Synthesis模块中。

img

来自LlamaIndex官方文件

列表索引确实提供了许多查询列表索引的方法,从基于嵌入的查询中获取前k个邻居,或者添加一个关键字过滤器,如下所示:

img

来自LlamaIndex官方文件

此列表索引对于综合跨多个数据源的信息的答案非常有用

LlamaIndex为列表索引提供Embedding支持。除了每个节点存储文本之外,每个节点还可以选择存储Embedding。在查询期间,我们可以在调用LLM合成答案之前,使用Embeddings对节点进行最大相似度检索。

由于使用Embeddings的相似性查找(例如使用余弦相似性)不需要LLM调用,Embeddings作为一种更便宜的查找机制,而不是使用大语言模型来遍历节点

这意味着在索引构建过程中,LlamaIndex不会调用LLM来生成Embedding,而是在查询时生成。这种设计选择避免了在索引构建期间为所有文本块生成Embeddings的需要,这可能会导致大量数据的开销。

您很快就会发现,将多个索引组合在一起可以帮助您避免高昂的Embedding成本。但这还不是全部——它还可以提高应用程序的整体性能!另一种方法是使用自定义Embedding(而不是使用OpenAI),但我们不会在本文中研究这种方法,因为它值得另一种方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from llama_index import GPTKeywordTableIndex, SimpleDirectoryReader
from IPython.display import Markdown, display
from langchain.chat_models import ChatOpenAI## by default, LlamaIndex uses text-davinci-003 to synthesise response
# and text-davinci-002 for embedding, we can change to
# gpt-3.5-turbo for Chat model
index = GPTListIndex.from_documents(documents)query_engine = index.as_query_engine()
response = query_engine.query("What is net operating income?")
display(Markdown(f"<b>{response}</b>"))## Check the logs to see the different between th
## if you wish to not build the index during the index construction
# then need to add retriever_mode=embedding to query engine
# query with embed_model specified
query_engine = new_index.as_query_engine(retriever_mode="embedding", verbose=True
)
response = query_engine.query("What is net operating income?")
display(Markdown(f"<b>{response}</b>"))

向量存储索引

它是最常见且易于使用的,允许对大型数据语料库回答查询

img

来自LlamaIndex官方文件

默认情况下,GPTVectorStoreIndex 使用内存中的 SimpleVectorStore作为默认存储上下文的一部分初始化。

与列表索引不同,基于向量存储的索引在索引构建期间生成Embeddings

这意味着在索引构建期间将调用LLM端点以生成Embeddings数据。

Query(查询)向量存储索引包括获取top-k最相似的节点,并将它们传递到我们的响应合成模块。

img

来自LlamaIndex官方文件

1
2
3
4
5
6
from llama_index import GPTVectorStoreIndexindex = GPTVectorStoreIndex.from_documents(documents)
query_engine = index.as_query_engine()
response = query_engine.query("What did the author do growing up?")
response

树状索引

它对总结一组文件很有用

树状索引是树结构索引,其中每个节点是子节点的摘要。在索引构建期间,树以自下而上的方式构建,直到我们最终得到一组根节点。

树状索引从一组节点(成为该树中的叶节点)构建层次树。

img

来自LlamaIndex官方文件

查询树状索引涉及从根节点向下遍历到叶节点。默认情况下(child_branch_factor=1 ),查询在给定父节点的情况下选择一个子节点。如果child_branch_factor=2,则查询在每个级别选择两个子节点。

img

来自LlamaIndex官方文件

与向量索引不同,LlamaIndex不会调用LLM来生成Embedding,而是在查询时生成。Embeddings被惰性地生成,然后缓存(如果retriver_mode ="Embedding" query(…)期间指定),而不是在索引构建期间。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from llama_index import GPTTreeIndexnew_index = GPTTreeIndex.from_documents(documents)
response = query_engine.query("What is net operating income?")
display(Markdown(f"<b>{response}</b>"))## if you want to have more content from the answer, 
# you can add the parameters child_branch_factor
# let's try using branching factor 2
query_engine = new_index.as_query_engine(child_branch_factor=2
)
response = query_engine.query("What is net operating income?")
display(Markdown(f"<b>{response}</b>"))

为了在查询期间构建树状索引,我们需要将retriver_moderesponse_mode添加到查询引擎,并将GPTTreeIndex中的build_tree参数设置为False

1
2
3
4
5
6
index_light = GPTTreeIndex.from_documents(documents, build_tree=False)
query_engine = index_light.as_query_engine(retriever_mode="all_leaf",response_mode='tree_summarize',
)
query_engine.query("What is net operating income?")

关键词表索引

这对于将查询路由到不同的数据源非常有用

关键字表索引从每个Node提取关键字,并构建从每个关键字到该关键字对应的Node的映射。

img

来自LlamaIndex官方文件

在查询时,我们从查询中提取相关关键字,并将其与预提取的Node关键字进行匹配,获取相应的Node。提取的节点被传递到响应合成模块。

img

来自LlamaIndex官方文件

注意到 GPTKeywordTableIndex-使用LLM从每个文档中提取关键字,这意味着它确实需要在构建期间调用LLM

但是,如果您使用GPTSimpleKeywordTableIndex,它使用regex关键字提取器从每个文档中提取关键字,则在构建期间不会调用LLM

1
2
3
4
from llama_index import GPTKeywordTableIndex
index = GPTKeywordTableIndex.from_documents(documents)
query_engine = index.as_query_engine()
response = query_engine.query("What is net operating income?")

可组合性图索引

它对于构建知识图谱很有用

使用LlamaIndex,您可以通过在现有索引之上构建索引来创建复合索引。该特性使您能够有效地索引完整的文档层次结构,并为GPT提供量身定制的知识。

通过利用可组合性,您可以在多个级别定义索引,例如为单个文档定义低级索引,为文档组定义高级索引。考虑下面的例子:

  • 您可以为每个文档中的文本创建树索引。

  • 生成一个列表索引,涵盖所有的树索引为您的整个文档集合。

通过一个场景编写代码:我们将执行以下步骤来演示可组合性图索引的能力:

  • 从多个文档创建树索引

  • 从树索引生成摘要。如前所述,Tree Index对于总结文档集合很有用。

  • 接下来,我们将在3个树索引的顶部创建一个列表索引的图。为什么?因为列表索引适合于合成跨多个数据源组合信息的答案。

  • 最后查询图。

实现:

我会阅读苹果2022年和2023年的10k报告,并在两个季度之间提出财务问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
## re
years = ['Q1-2023', 'Q2-2023']
UnstructuredReader = download_loader('UnstructuredReader', refresh_cache=True)loader = UnstructuredReader()
doc_set = {}
all_docs = []for year in years:year_docs = loader.load_data(f'../notebooks/documents/Apple-Financial-Report-{year}.pdf', split_documents=False)for d in year_docs:d.extra_info = {"quarter": year.split("-")[0], "year": year.split("-")[1],"q":year.split("-")[0]}doc_set[year] = year_docsall_docs.extend(year_docs)

为每个季度创建矢量指数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
## setting up vector indicies for each year
#---
# initialize simple vector indices + global vector index
# this will use OpenAI embedding as default with text-davinci-002
service_context = ServiceContext.from_defaults(chunk_size_limit=512)
index_set = {}
for year in years:storage_context = StorageContext.from_defaults()cur_index = GPTVectorStoreIndex.from_documents(documents=doc_set[year],service_context=service_context,storage_context=storage_context)index_set[year] = cur_index# store index in the local env, so you don't need to do it over againstorage_context.persist(f'./storage_index/apple-10k/{year}')

从树索引生成摘要。如前所述,Tree Index对于总结文档集合很有用。

1
2
# describe summary for each index to help traversal of composed graph
index_summary = [index_set[year].as_query_engine().query("Summary this document in 100 words").response for year in years]

接下来,我们将在3个树索引之上创建一个列表索引的Graph

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
### Composing a Graph to Synthesize Answers
from llama_index.indices.composability import ComposableGraphfrom langchain.chat_models import ChatOpenAI
from llama_index import LLMPredictor# define an LLMPredictor set number of output tokens
llm_predictor = LLMPredictor(llm=ChatOpenAI(temperature=0, max_tokens=512, model_name='gpt-3.5-turbo'))
service_context = ServiceContext.from_defaults(llm_predictor=llm_predictor)
storage_context = StorageContext.from_defaults()\## define a list index over the vector indicies 
## allow us to synthesize information across  each index
graph = ComposableGraph.from_indices(GPTListIndex,[index_set[y] for y in years],index_summaries=index_summary,service_context=service_context,storage_context=storage_context
)root_id = graph.root_id#save to disk
storage_context.persist(f'./storage_index/apple-10k/root')## querying graph
custom_query_engines = {index_set[year].index_id: index_set[year].as_query_engine() for year in years
}query_engine = graph.as_query_engine(custom_query_engines=custom_query_engines
)response = query_engine.query("Outline the financial statement of Q2 2023")
response.response

想知道我们如何利用Langchain Agent作为聊天机器人,请关注/订阅未来的更多更新:)

Pandas索引和SQL索引

它对结构化数据很有用

简单和非常直接,我将直接进入演示。

Pandas Index:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from llama_index.indices.struct_store import GPTPandasIndex
import pandas as pddf = pd.read_csv("titanic_train.csv")index = GPTPandasIndex(df=df)query_engine = index.as_query_engine(verbose=True
)
response = query_engine.query("What is the correlation between survival and age?",
)
response

img

SQL Index:

考虑一个很酷的应用程序,你可以将你的LLM应用程序附加到你的数据库,并在它上面提问。这个示例代码取自这里

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# install wikipedia python package
!pip install wikipediafrom llama_index import SimpleDirectoryReader, WikipediaReader
from sqlalchemy import create_engine, MetaData, Table, Column, String, Integer, select, columnwiki_docs = WikipediaReader().load_data(pages=['Toronto', 'Berlin', 'Tokyo'])engine = create_engine("sqlite:///:memory:")
metadata_obj = MetaData()# create city SQL table
table_name = "city_stats"
city_stats_table = Table(table_name,metadata_obj,Column("city_name", String(16), primary_key=True),Column("population", Integer),Column("country", String(16), nullable=False),
)
metadata_obj.create_all(engine)from llama_index import GPTSQLStructStoreIndex, SQLDatabase, ServiceContext
from langchain import OpenAI
from llama_index import LLMPredictorllm_predictor = LLMPredictor(llm=LLMPredictor(llm=ChatOpenAI(temperature=0, max_tokens=512, model_name='gpt-3.5-turbo')))
service_context = ServiceContext.from_defaults(llm_predictor=llm_predictor)sql_database = SQLDatabase(engine, include_tables=["city_stats"])
sql_database.table_info# NOTE: the table_name specified here is the table that you
# want to extract into from unstructured documents.
index = GPTSQLStructStoreIndex.from_documents(wiki_docs, sql_database=sql_database, table_name="city_stats",service_context=service_context
)# view current table to verify the answer later
stmt = select(city_stats_table.c["city_name", "population", "country"]
).select_from(city_stats_table)with engine.connect() as connection:results = connection.execute(stmt).fetchall()print(results)query_engine = index.as_query_engine(query_mode="nl"
)
response = query_engine.query("Which city has the highest population?")

img

在底层,有一个Langchain库插件可以使用。我们将在另一篇文章中介绍Langchain。

文档摘要索引

这是一个全新的LlamaIndex数据结构,它是为了问答而制作的。到目前为止,我们已经讨论了单个索引,当然我们可以通过使用单个索引或将多个索引组合在一起来构建LLMQA应用程序。

通常,大多数用户以以下方式开发基于llm的QA系统:

  1. 它们获取源文档并将其分成文本块。

  2. 然后将文本块存储在矢量数据库中。

  3. 在查询期间,通过使用相似度和/或关键字过滤器进行Embedding来检索文本块。

  4. 执行响应综合。

然而,这种方法存在一些影响检索性能的局限性。

现有方法的缺点:

  1. 文本块没有完整的全局上下文,这通常限制了问答过程的有效性。
  2. 需要仔细调优top-k /相似性分数阈值,因为过小的值可能会导致错过相关上下文,而过大的值可能会增加不相关上下文的成本和延迟。
  3. Embeddings可能并不总是为一个问题选择最合适的上下文,因为这个过程本质上是分别决定文本和上下文的。

为了增强检索结果,一些开发人员添加了关键字过滤器。然而,这种方法有其自身的挑战,例如通过手工或使用NLP关键字提取/主题标记模型为每个文档确定适当的关键字,以及从查询中推断正确的关键字。

img

这就是LlamaIndex引入文档摘要索引的地方,它可以为每个文档提取和索引非结构化文本摘要,从而提高了现有方法的检索性能。该索引包含比单个文本块更多的信息,并且比关键字标签具有更多的语义含义。它还允许灵活的检索,包括LLM和基于嵌入的方法。

在构建期间,该索引摄取文档并使用LLM从每个文档提取摘要。在查询期间,根据摘要检索相关文档进行查询,使用以下方法:

  • - **基于LLM的检索:**获取文档摘要集合,请求LLM识别相关文档+相关性评分

    - **基于嵌入的检索:**利用摘要Embedding相似度检索相关文档,并对检索结果的数量施加top-k限制。

注意:文档摘要索引的检索类为任何选定的文档检索所有节点,而不是在节点级返回相关块。

看看例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
import nest_asyncio
nest_asyncio.apply()from llama_index import (SimpleDirectoryReader,LLMPredictor,ServiceContext,ResponseSynthesizer
)
from llama_index.indices.document_summary import GPTDocumentSummaryIndex
from langchain.chat_models import ChatOpenAIwiki_titles = ["Toronto", "Seattle", "Chicago", "Boston", "Houston"]from pathlib import Pathimport requests
for title in wiki_titles:response = requests.get('https://en.wikipedia.org/w/api.php',params={'action': 'query','format': 'json','titles': title,'prop': 'extracts',# 'exintro': True,'explaintext': True,}).json()page = next(iter(response['query']['pages'].values()))wiki_text = page['extract']data_path = Path('data')if not data_path.exists():Path.mkdir(data_path)with open(data_path / f"{title}.txt", 'w') as fp:fp.write(wiki_text)# Load all wiki documents
city_docs = []
for wiki_title in wiki_titles:docs = SimpleDirectoryReader(input_files=[f"data/{wiki_title}.txt"]).load_data()docs[0].doc_id = wiki_titlecity_docs.extend(docs)# # LLM Predictor (gpt-3.5-turbo)
llm_predictor_chatgpt = LLMPredictor(llm=ChatOpenAI(temperature=0, model_name="gpt-3.5-turbo"))
service_context = ServiceContext.from_defaults(llm_predictor=llm_predictor_chatgpt, chunk_size_limit=1024)# default mode of building the index
response_synthesizer = ResponseSynthesizer.from_args(response_mode="tree_summarize", use_async=True)
doc_summary_index = GPTDocumentSummaryIndex.from_documents(city_docs, service_context=service_context,response_synthesizer=response_synthesizer
)doc_summary_index.get_document_summary("Boston")

知识图谱索引

它通过在一组文档上以以下形式提取知识三元组(主题、谓词、对象)来构建索引。

在查询期间,它可以只使用知识图作为上下文进行查询,也可以利用来自每个实体的底层文本作为上下文进行查询。通过利用底层文本,我们可以对文档的内容进行更复杂的查询。

把一个图想象成这样,你可以看到所有的边和顶点都是相互连接的。

img

来自LlamaIndex官方文件

你可以看看这个页面作为参考。

需要考虑的事实

在我们的PDF聊天机器人实施大语言模型期间,我提请注意我们想与您分享的重要方面,即:索引成本和索引时间(速度)。

索引的成本

索引费用是需要考虑的一个关键因素,正如我在本文前面所强调的那样。这在处理大量数据集时尤为重要,这也是我提倡使用LlamaIndex的原因。

你可以找到各个OpenAI模型的价格(https://openai.com/pricing)。

索引速度

第二个重要问题是文档索引的时间,即为操作准备整个解决方案的时间。根据我的实验,索引时间各不相同,但这是一次性的,也取决于OpenAI服务器。

通常,40页的pdf大约需要5秒。想象一下,一个拥有超过10万页的庞大数据集,可能需要几天的时间。我们可以利用async方法来减少索引时间。我将在另一篇文章中写这一点。

总结

img

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

GNU ld 链接器lang_process() (一)

一、lang_process() 从现在开始介绍 lang_process()函数&#xff0c;是GNU ld&#xff08;GNU链接器&#xff09;的一个核心函数&#xff0c;负责执行链接过程中的各个关键操作。lang_process(void) 函数涵盖了整个链接过程中的各个关键步骤&#xff0c;包括符号解析、重定位、…

初识jQuery

文章目录 一、jQuery介绍二、Jquery优势三、jQuery版本四、jQuery对象jQuery的引用js代码与jQuery代码对比标签对象与jQuery对象 五、jQuery查找标签1.基本选择器2.组合选择器3.层次选择器4.属性选择器5.基本筛选器6.表单筛选器 六、筛选器方法七、操作标签1.class操作2.文本操…

Java-Hbase介绍

1.1. 概念 base 是分布式、面向列的开源数据库&#xff08;其实准确的说是面向列族&#xff09;。HDFS 为 Hbase 提供可靠的 底层数据存储服务&#xff0c;MapReduce 为 Hbase 提供高性能的计算能力&#xff0c;Zookeeper 为 Hbase 提供 稳定服务和 Failover 机制&#xff0c…

Flutter 07 框架和三棵树(Widgets、Elements和RenderObjects)

一、Flutter框架的整体结构&#xff1a; Flutter是Google推出并开源的跨平台开发框架&#xff0c;主打跨平台、高保真、高性能。开发者可以通过Dart语 言开发Flutter应用&#xff0c;一套代码同时运行在ios和Android平台。不仅如此&#xff0c;Flutter还支持Web、桌面、嵌 入应…

【RabbitMQ】RabbitMQ 消息的堆积问题 —— 使用惰性队列解决消息的堆积问题

文章目录 一、消息的堆积问题1.1 什么是消息的堆积问题1.2 消息堆积的解决思路 二、惰性队列解决消息堆积问题2.1 惰性队列和普通队列的区别2.2 惰性队列的声明方式2.3 演示惰性队列接收大量消息2.4 惰性队列的优缺点 一、消息的堆积问题 1.1 什么是消息的堆积问题 消息的堆积…

同城售后系统退款业务重构心得 | 京东云技术团队

一、重构背景 1.1、退款 到家、小时购、天选退款有2套结构&#xff0c;代码逻辑混乱&#xff1b; 其中小时购、天选部分售后单是和平生pop交互退款&#xff0c;部分是和售后中台交互退款&#xff1b;并且兼容3套逻辑&#xff1b; 痛点&#xff1a;代码繁重&#xff0c;缺乏…

CCLINK IEFB总线转ETHERNET/IP网络的协议网关使欧姆龙和三菱的数据互通的简单配置方法

想要实现CCLINK IEFB总线和ETHERNET/IP网络的数据互通。 捷米JM-EIP-CCLKIE是一款ETHERNET/IP从站功能的通讯网关&#xff0c;该产品主要功能是实现CCLINK IEFB总线和ETHERNET/IP网络的数据互通。本网关连接到ETHERNET/IP总线和CCLINK IEFB总线上都可以做为从站使用。网关分别…

创建基于多任务的并发服务器

有几个请求服务的客户端&#xff0c;我们就创建几个子进程。 这个过程有以下三个阶段&#xff1a; 这里父进程传递的套接字文件描述符&#xff0c;实际上不需要传递&#xff0c;因为子进程会复制父进程拥有的所有资源。 #include <stdio.h> #include <stdlib.h>…

Android---App 的安装过程

Android 系统中两个比较重要的服务 ActivityManagerService(AMS) 和 WindowManagerService(WMS)&#xff0c;这篇文章中通过分析 apk 的安装过程&#xff0c;来了解 Android 中另一个比较重要的系统服务 -- PackageManagerService(PMS)。 编译阶段 在分析安装过程之前&#x…

ElasticSearch集群架构实战及其原理剖析

ES集群架构 为什么要使用ES集群架构 分布式系统的可用性与扩展性&#xff1a; 高可用性 服务可用性&#xff1a;允许有节点停止服务&#xff1b;数据可用性&#xff1a;部分节点丢失&#xff0c;不会丢失数据&#xff1b; 可扩展性 请求量提升/数据的不断增长(将数据分布…

上线项目问题——无法加载响应数据

目录 无法加载响应数据解决 无法加载响应数据 上线项目时 改用服务器上的redis和MySQL 出现请求能请求到后端&#xff0c;后端也能正常返回数据&#xff0c;但是在前端页面会显示 以为是跨域问题&#xff0c;但是环境还在本地&#xff0c;排除跨域问题以为是服务器问题&#…

一款简单而强大的文档翻译网站

一款文字/文件翻译的网站,支持多个领域的翻译&#xff0c;支持常见的语言翻译(韩/日/法/英/俄/德…),最大百分比的保持原文排版(及个别除外基本100%还原)。 新用户注册就有100页的免费额度&#xff0c;每月系统还会随机赠送翻译额度&#xff0c;说实话这比好多的企业要好的多了…