国产亚洲精品福利在线无卡一,国产精久久一区二区三区,亚洲精品无码国模,精品久久久久久无码专区不卡

當(dāng)前位置: 首頁 > news >正文

沭陽網(wǎng)站設(shè)計蘭州百度推廣的公司

沭陽網(wǎng)站設(shè)計,蘭州百度推廣的公司,建設(shè)銀行黨建網(wǎng)站,合肥中小企業(yè)網(wǎng)站制作一、全文搜索 全文搜索是一種通過匹配文本中特定關(guān)鍵詞或短語來檢索文檔的傳統(tǒng)方法。它根據(jù)詞頻等因素計算出的相關(guān)性分?jǐn)?shù)對結(jié)果進(jìn)行排序。語義搜索更善于理解含義和上下文,而全文搜索則擅長精確的關(guān)鍵詞匹配,因此是語義搜索的有益補充。BM25 算法被廣泛…

一、全文搜索

全文搜索是一種通過匹配文本中特定關(guān)鍵詞或短語來檢索文檔的傳統(tǒng)方法。它根據(jù)詞頻等因素計算出的相關(guān)性分?jǐn)?shù)對結(jié)果進(jìn)行排序。語義搜索更善于理解含義和上下文,而全文搜索則擅長精確的關(guān)鍵詞匹配,因此是語義搜索的有益補充。BM25 算法被廣泛用于全文搜索的排序,并在檢索增強生成(RAG)中發(fā)揮著關(guān)鍵作用。

Milvus 2.5 引入了使用 BM25 的本地全文搜索功能。這種方法將文本轉(zhuǎn)換為代表 BM25 分?jǐn)?shù)的稀疏向量。我們只需輸入原始文本,Milvus 就會自動生成并存儲稀疏向量,無需手動生成稀疏嵌入。

LangChain 與 Milvus 的集成也引入了這一功能,簡化了將全文檢索納入 RAG 應(yīng)用程序的過程。通過將全文搜索與密集向量的語義搜索相結(jié)合,可以實現(xiàn)一種混合方法,既能利用密集嵌入的語義上下文,又能利用單詞匹配的精確關(guān)鍵詞相關(guān)性。這種整合提高了搜索系統(tǒng)的準(zhǔn)確性、相關(guān)性和用戶體驗。

本文將展示如何使用 LangChainMilvus 在應(yīng)用程序中實現(xiàn) 全文搜索。

二、前提條件

1、依賴安裝

pip install --upgrade --quiet  langchain langchain-core langchain-community langchain-text-splitters langchain-milvus langchain-openai pymilvus[model]

2、OPENAI API 服務(wù)

這里需要用到嵌入模型 bge-m3,當(dāng)然也可以使用其他模型,最簡單的方法就是申請 OPENAI_API_KEY 或者在國內(nèi)大模型服務(wù)平臺申請一個,例如硅基流動、阿里云百煉、火山引擎等,如果有硬件條件可以使用 Ollama 或者 vLLM 本地部署。

參考:LangChain × vLLM:手把手教你實現(xiàn)高效大語言模型推理與集成

import os# 設(shè)置環(huán)境變量
os.environ["OPENAI_BASE_URL"] = "http://localhost:8000/v1"
os.environ["OPENAI_API_KEY"] = "EMPTY"

3、Milvus 服務(wù)器

使用本地服務(wù)器或者云服務(wù)器,都可以。

參考:LangChain × Milvus:手把手教你搭建智能向量數(shù)據(jù)庫

URI = "http://localhost:19530"

4、數(shù)據(jù)準(zhǔn)備

準(zhǔn)備一些示例文檔,即按主題或流派分類的虛構(gòu)故事摘要。

from langchain_core.documents import Documentdocs = [Document(page_content="I like this apple", metadata={"category": "fruit"}),Document(page_content="I like swimming", metadata={"category": "sport"}),Document(page_content="I like dogs", metadata={"category": "pets"}),
]

三、使用 BM25 函數(shù)初始化

1、混合搜索

對于全文檢索,Milvus VectorStore 接受一個 builtin_function 參數(shù)。通過該參數(shù),可以傳入 BM25BuiltInFunction 的實例。這與語義搜索不同,語義搜索通常將密集嵌入傳入 VectorStore 。

下面是一個在 Milvus 中使用 OpenAI dense embedding 進(jìn)行語義搜索和 BM25 進(jìn)行全文搜索的混合搜索的簡單示例:

from langchain_milvus import Milvus, BM25BuiltInFunction
from langchain_openai import OpenAIEmbeddingsvectorstore = Milvus.from_documents(documents=docs,embedding=OpenAIEmbeddings(model="BAAI/bge-m3),builtin_function=BM25BuiltInFunction(),# `dense` is for OpenAI embeddings, `sparse` is the output field of BM25 functionvector_field=["dense", "sparse"],connection_args={"uri": URI,...},drop_old=False,
)

在上面的代碼中,我們定義了 BM25BuiltInFunction 的一個實例,并將其傳遞給 Milvus 對象。BM25BuiltInFunction 是一個輕量級的封裝類,Function 的輕量級封裝類。

我們可以在 BM25BuiltInFunction 的參數(shù)中指定該函數(shù)的輸入和輸出字段:

  • input_field_names (str):輸入字段的名稱,默認(rèn)為 text。它表示此函數(shù)讀取哪個字段作為輸入。
  • output_field_names (str):輸出字段的名稱,默認(rèn)為 sparse。它表示此函數(shù)將計算結(jié)果輸出到哪個字段。

請注意,在上述 Milvus 初始化參數(shù)中,我們也指定了 vector_field=["dense", "sparse"] 。由于 sparse 字段被當(dāng)作由BM25BuiltInFunction 定義的輸出字段,因此其他 dense 字段將被自動分配給 OpenAIEmbeddings 的輸出字段。

在實踐中,尤其是在組合多個 Embeddings 或函數(shù)時,建議明確指定每個函數(shù)的輸入和輸出字段,以避免歧義。

在下面的示例中,我們明確指定了 BM25BuiltInFunction 的輸入字段和輸出字段,從而清楚地說明了內(nèi)置函數(shù)用于哪個字段。

# from langchain_voyageai import VoyageAIEmbeddingsembedding1 = OpenAIEmbeddings(model="text-embedding-ada-002")
embedding2 = OpenAIEmbeddings(model="text-embedding-3-large")
# embedding2 = VoyageAIEmbeddings(model="voyage-3")  # You can also use embedding from other embedding model providers, e.g VoyageAIEmbeddingsvectorstore = Milvus.from_documents(documents=docs,embedding=[embedding1, embedding2],builtin_function=BM25BuiltInFunction(input_field_names="text", output_field_names="sparse"),text_field="text",  # `text` is the input field name of BM25BuiltInFunction# `sparse` is the output field name of BM25BuiltInFunction, and `dense1` and `dense2` are the output field names of embedding1 and embedding2vector_field=["dense1", "dense2", "sparse"],connection_args={"uri": URI,},drop_old=False,
)vectorstore.vector_fields
['dense1', 'dense2', 'sparse']

在這個示例中,我們有三個向量字段。其中,sparse 作為 BM25BuiltInFunction 的輸出字段,而其他兩個字段 dense1dense2 則被自動指定為兩個 OpenAIEmbeddings 模型的輸出字段(根據(jù)順序)。

這樣,就可以定義多個向量場,并為其分配不同的嵌入或函數(shù)組合,從而實現(xiàn)混合搜索。

執(zhí)行混合搜索時,我們只需傳入查詢文本,并選擇性地設(shè)置 topKReranker 參數(shù)。vectorstore 實例會自動處理向量嵌入和內(nèi)置函數(shù),最后使用 Reranker 對結(jié)果進(jìn)行細(xì)化。搜索過程的底層實現(xiàn)細(xì)節(jié)對用戶是隱藏的。

vectorstore.similarity_search("Do I like apples?", k=1
)  # , ranker_type="weighted", ranker_params={"weights":[0.3, 0.3, 0.4]})
[Document(metadata={'category': 'fruit', 'pk': 454646931479251897}, page_content='I like this apple')]

2、無嵌入的 BM25 搜索

如果只想使用 BM25 函數(shù)執(zhí)行全文搜索,而不想使用任何基于嵌入的語義搜索,可以將嵌入?yún)?shù)設(shè)置為 None ,并只保留指定為 BM25 函數(shù)實例的 builtin_function ,向量字段只有 "稀疏 "字段。

vectorstore = Milvus.from_documents(documents=docs,embedding=None,builtin_function=BM25BuiltInFunction(output_field_names="sparse",),vector_field="sparse",connection_args={"uri": URI,},drop_old=False,
)vectorstore.vector_fields
['sparse']

四、自定義分析器

分析器在全文檢索中至關(guān)重要,它可以將句子分解成詞塊,并執(zhí)行詞法分析,如詞干分析和停止詞刪除。

分析器通常針對特定語言。

Milvus 支持兩種類型的分析器:內(nèi)置分析器和自定義分析器。默認(rèn)情況下,BM25BuiltInFunction 將使用標(biāo)準(zhǔn)的內(nèi)置分析器,這是最基本的分析器,會用標(biāo)點符號標(biāo)記文本。

如果想使用其他分析器或自定義分析器,可以在 BM25BuiltInFunction 初始化時傳遞analyzer_params 參數(shù)。

analyzer_params_custom = {"tokenizer": "standard","filter": ["lowercase",  # Built-in filter{"type": "length", "max": 40},  # Custom filter{"type": "stop", "stop_words": ["of", "to"]},  # Custom filter],
}vectorstore = Milvus.from_documents(documents=docs,embedding=OpenAIEmbeddings(),builtin_function=BM25BuiltInFunction(output_field_names="sparse",enable_match=True,analyzer_params=analyzer_params_custom,),vector_field=["dense", "sparse"],connection_args={"uri": URI,},drop_old=False,
)

我們可以看看 Milvus CollectionsSchema,確保定制的分析器設(shè)置正確。

vectorstore.col.schema
{'auto_id': True, 'description': '', 'fields': [{'name': 'text', 'description': '', 'type': <DataType.VARCHAR: 21>, 'params': {'max_length': 65535, 'enable_match': True, 'enable_analyzer': True, 'analyzer_params': {'tokenizer': 'standard', 'filter': ['lowercase', {'type': 'length', 'max': 40}, {'type': 'stop', 'stop_words': ['of', 'to']}]}}}, {'name': 'pk', 'description': '', 'type': <DataType.INT64: 5>, 'is_primary': True, 'auto_id': True}, {'name': 'dense', 'description': '', 'type': <DataType.FLOAT_VECTOR: 101>, 'params': {'dim': 1536}}, {'name': 'sparse', 'description': '', 'type': <DataType.SPARSE_FLOAT_VECTOR: 104>, 'is_function_output': True}, {'name': 'category', 'description': '', 'type': <DataType.VARCHAR: 21>, 'params': {'max_length': 65535}}], 'enable_dynamic_field': False, 'functions': [{'name': 'bm25_function_de368e79', 'description': '', 'type': <FunctionType.BM25: 1>, 'input_field_names': ['text'], 'output_field_names': ['sparse'], 'params': {}}]}

五、在 RAG 中使用混合搜索

我們已經(jīng)學(xué)習(xí)了如何在 LangChain 和 Milvus 中使用基本的 BM25 內(nèi)置函數(shù),接下來我們結(jié)合混合搜索來實現(xiàn)一個 RAG 例子。

在這里插入圖片描述

該圖顯示了混合檢索和重排過程,將用于關(guān)鍵詞匹配的 BM25 和用于語義檢索的向量搜索結(jié)合在一起。來自兩種方法的結(jié)果經(jīng)過合并、Rerankers 和傳遞給 LLM 生成最終答案。

混合搜索兼顧了精確性和語義理解,提高了不同查詢的準(zhǔn)確性和穩(wěn)健性。它通過 BM25 全文檢索和向量搜索檢索候選內(nèi)容,同時確保語義、上下文感知和精確檢索。

1、準(zhǔn)備數(shù)據(jù)

我們使用 PyPDFLoader 加載 PDF 文檔,并使用 RecursiveCharacterTextSplitter 將文檔分割成塊。

from langchain_community.document_loaders import PyPDFLoaderfile_path = "data/0001.pdf"
loader = PyPDFLoader(file_path)docs = loader.load()print(f"文檔頁數(shù):{len(docs)} 頁")
文檔頁數(shù):2 頁
# 頁面的字符串內(nèi)容
print(f"{docs[0].page_content[:200]}\n")
# 包含文件名和頁碼的元數(shù)據(jù)
print(docs[0].metadata)
標(biāo)題:意大利面與 42 號混凝土混合對挖掘機扭矩和環(huán)境穩(wěn)定性的跨學(xué)科影響分析:劍橋大學(xué)研究
報告
摘要:
本研究報告深入研究了烹飪制品和建筑材料的融合,特別調(diào)查了將意大利面與 42 號混凝土混合對
挖掘機扭矩效率的潛在影響。 令人驚訝的是,螺絲長度、高能蛋白質(zhì)、核污染、核擴散、三角函
數(shù)和地緣政治人物之間的相互作用成為一個重要的研究點。 通過利用畢達(dá)哥拉斯定理和歷史類比
進(jìn)行細(xì)致的檢查,該研究闡明{'producer': 'LibreOffice 24.2', 'creator': 'Writer', 'creationdate': '2025-05-29T15:22:12+08:00', 'source': 'data/0001.pdf', 'total_pages': 2, 'page': 0, 'page_label': '1'}
from langchain_text_splitters import RecursiveCharacterTextSplittertext_splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=100, add_start_index=True
)
all_splits = text_splitter.split_documents(docs)len(all_splits)
4

2、將文檔加載到 Milvus 向量存儲中

如果數(shù)據(jù)庫 milvus_demo 已經(jīng)儲存了其他類型的數(shù)據(jù),測試時可以設(shè)置 drop_old=True 清掉

vectorstore = Milvus.from_documents(documents=all_splits,embedding=OpenAIEmbeddings(model="BAAI/bge-m3"),builtin_function=BM25BuiltInFunction(),vector_field=["dense", "sparse"],connection_args={"uri": URI,"token": "root:Milvus", "db_name": "milvus_demo"},consistency_level="Strong",  # Supported values are (`"Strong"`, `"Session"`, `"Bounded"`, `"Eventually"`). See https://milvus.io/docs/consistency.md#Consistency-Level for more details.drop_old=False,
)
2025-06-16 14:24:36,268 [DEBUG][_create_connection]: Created new connection using: 5490932c80494891865d6e46857b5cf2 (async_milvus_client.py:599)

3、構(gòu)建 RAG 鏈

我們準(zhǔn)備好 LLM 實例和提示,然后使用 LangChain 表達(dá)式語言將它們結(jié)合到 RAG 管道中。

from langchain_openai import ChatOpenAI
import osos.environ["DASHSCOPE_API_KEY"] = "sk-xxx"# Initialize the OpenAI language model for response generation
llm = ChatOpenAI(api_key=os.getenv("DASHSCOPE_API_KEY"),base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",model="qwen-plus",  # 此處以qwen-plus為例,您可按需更換模型名稱。模型列表:https://help.aliyun.com/zh/model-studio/getting-started/models# other params...
)
messages = [{"role": "system", "content": "You are a helpful assistant."},{"role": "user", "content": "你是誰?"}]
response = llm.invoke(messages)
print(response.json())
{"content":"我是通義千問,阿里巴巴集團旗下的超大規(guī)模語言模型。我能夠回答問題、創(chuàng)作文字,如寫故事、公文、郵件、劇本等,還能進(jìn)行邏輯推理、編程等任務(wù)。如果你有任何問題或需要幫助,歡迎隨時告訴我!","additional_kwargs":{"refusal":null},"response_metadata":{"token_usage":{"completion_tokens":54,"prompt_tokens":22,"total_tokens":76,"completion_tokens_details":null,"prompt_tokens_details":{"audio_tokens":null,"cached_tokens":0}},"model_name":"qwen-plus","system_fingerprint":null,"id":"chatcmpl-a5a8e18e-efbd-9c10-85bb-30dfe7242854","service_tier":null,"finish_reason":"stop","logprobs":null},"type":"ai","name":null,"id":"run--c570416c-b01f-493a-9d87-778a44f93ddf-0","example":false,"tool_calls":[],"invalid_tool_calls":[],"usage_metadata":{"input_tokens":22,"output_tokens":54,"total_tokens":76,"input_token_details":{"cache_read":0},"output_token_details":{}}}/tmp/ipykernel_4268/4214353893.py:17: PydanticDeprecatedSince20: The `json` method is deprecated; use `model_dump_json` instead. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.11/migration/print(response.json())
from langchain_core.runnables import RunnablePassthrough
from langchain_core.prompts import PromptTemplate
from langchain_core.output_parsers import StrOutputParser# Define the prompt template for generating AI responses
PROMPT_TEMPLATE = """
Human: You are an AI assistant, and provides answers to questions by using fact based and statistical information when possible.
Use the following pieces of information to provide a concise answer to the question enclosed in <question> tags.
If you don't know the answer, just say that you don't know, don't try to make up an answer.
<context>
{context}
</context><question>
{question}
</question>The response should be specific and use statistics or numbers when possible.Assistant:"""# Create a PromptTemplate instance with the defined template and input variables
prompt = PromptTemplate(template=PROMPT_TEMPLATE, input_variables=["context", "question"]
)
# Convert the vector store to a retriever
retriever = vectorstore.as_retriever()# Define a function to format the retrieved documents
def format_docs(docs):return "\n\n".join(doc.page_content for doc in docs)

使用 LCEL(LangChain 表達(dá)式語言)構(gòu)建 RAG 鏈。

# Define the RAG (Retrieval-Augmented Generation) chain for AI response generation
rag_chain = ({"context": retriever | format_docs, "question": RunnablePassthrough()}| prompt| llm| StrOutputParser()
)
# LangGraph 還附帶內(nèi)置實用程序,用于可視化您應(yīng)用程序的控制流
from IPython.display import Image, displaydisplay(Image(rag_chain.get_graph().draw_mermaid_png()))

在這里插入圖片描述

使用特定問題調(diào)用 RAG 鏈并獲取響應(yīng):

query = "如何理解混凝土拌意大利面?"
res = rag_chain.invoke(query)
res
'根據(jù)研究報告《Mysterious Speghetti-Concrete Mixtures: A Study in Index Dynamics》(Smith, J., 2023),混凝土拌意大利面的結(jié)合是一種跨學(xué)科研究中的非常規(guī)材料混合,旨在探索其對挖掘機扭矩效率、環(huán)境穩(wěn)定性和地緣政治影響的復(fù)雜作用。\n\n### 理解混凝土拌意大利面的關(guān)鍵點:\n1. **物理特性與數(shù)學(xué)模型**:\n   - 研究利用了基于勾股定理的數(shù)學(xué)推論,分析了螺桿長度和意大利面-混凝土成分之間的關(guān)系。研究表明,螺桿長度的變化直接影響挖掘活動期間的扭矩產(chǎn)生。\n   - 具體而言,當(dāng)意大利面與42號混凝土混合時,扭矩效率的變化可以通過以下公式近似計算:  \n     \\[\n     T = k \\cdot L^2 + C\n     \\]\n     其中,\\(T\\) 表示扭矩,\\(L\\) 是螺桿長度,\\(k\\) 和 \\(C\\) 是與材料特性相關(guān)的常數(shù)。\n\n2. **材料相互作用**:\n   - 意大利面的纖維結(jié)構(gòu)與混凝土的礦物化合物相結(jié)合,可能改變材料的整體強度和粘性。這種結(jié)合對挖掘機的操作產(chǎn)生了深遠(yuǎn)的影響。\n   - 高能蛋白質(zhì)(研究報告中稱為“不明飛行物”或UFO)進(jìn)一步增強了這種混合物的復(fù)雜性,可能導(dǎo)致經(jīng)濟發(fā)展的重大挑戰(zhàn)。\n\n3. **環(huán)境與地緣政治影響**:\n   - 報告指出,這種混合物可能引發(fā)核污染擴散的風(fēng)險,特別是在太平洋地區(qū)以及沃爾瑪?shù)裙I(yè)環(huán)境中。\n   - 歷史類比表明,類似秦始皇的地緣政治人物可能會受到這種技術(shù)變革的影響,從而改變國際關(guān)系格局。\n\n4. **跨學(xué)科視角**:\n   - 這項研究整合了多個領(lǐng)域的知識,包括核物理、古代歷史和企業(yè)外交,以全面理解這種非常規(guī)材料組合的潛在影響。\n   - 例如,《The UFO Phenomenon: Implications for Economic Development and Nuclear Pollution》(Doe, A., 2022) 提供了關(guān)于高能蛋白質(zhì)如何影響工業(yè)環(huán)境的具體數(shù)據(jù)。\n\n### 結(jié)論:\n混凝土拌意大利面的研究揭示了看似無關(guān)元素之間的復(fù)雜關(guān)聯(lián)性,并強調(diào)了跨學(xué)科研究在應(yīng)對當(dāng)代工程和社會挑戰(zhàn)中的重要性。盡管具體數(shù)值和統(tǒng)計結(jié)果尚未完全量化,但研究表明,這種混合物對挖掘機操作、環(huán)境穩(wěn)定性和地緣政治動態(tài)具有顯著影響。因此,未來需要進(jìn)一步探索這些材料的協(xié)同作用及其潛在后果。'

至此,我們已經(jīng)構(gòu)建了由 MilvusLangChain 支持的混合(密集向量 + 稀疏 BM25 函數(shù))搜索 RAG 鏈。

補充:全文搜索與混合搜索對比

1、全文搜索(Full-Text Search, FTS)?

?核心原理?

基于關(guān)鍵詞匹配的傳統(tǒng)檢索方法,依賴 ?BM25 算法?計算文本相關(guān)性。將文本轉(zhuǎn)化為?稀疏向量?(高維、大部分值為零),通過統(tǒng)計詞頻、逆文檔頻率等指標(biāo)對文檔排序。

  • 稀疏向量特點?:維度高,僅少量非零值,適合精確匹配關(guān)鍵詞(如產(chǎn)品型號、代碼變量)。
  • 優(yōu)勢?:擅長處理專有名詞、精確短語和完全匹配的查詢(如“ERROR_CODE_404”)。

?Milvus 實現(xiàn)?

  • 用戶直接輸入文本,Milvus 自動生成稀疏向量并執(zhí)行檢索,無需手動處理向量轉(zhuǎn)換。
  • 默認(rèn)使用 ?BM25 評分?,支持模糊匹配、拼寫容錯等傳統(tǒng)搜索引擎能力。

2、混合搜索(Hybrid Search)?

?核心原理?

同時執(zhí)行?多路檢索?(如語義搜索 + 全文搜索),通過融合策略(如 ?RRF 算法?)合并結(jié)果,返回綜合排序的列表。

  • 多向量支持?:允許在一個 Collection 中存儲多個向量字段(如密集向量、稀疏向量),并行檢索不同模態(tài)的數(shù)據(jù)。
  • 典型場景?:
    • 稀疏-密集融合?:結(jié)合關(guān)鍵詞匹配(FTS)與語義理解(密集向量)。
    • 多模態(tài)搜索?:同時檢索圖像特征向量、聲紋向量等不同模態(tài)數(shù)據(jù)。

?Milvus 實現(xiàn)?

  • 支持為不同向量字段創(chuàng)建獨立索引(如 filmVector 用 IVF_FLAT,posterVector 用 HNSW)。

  • 查詢時指定各字段的權(quán)重(例如:weight: 0.8 給語義字段,weight: 0.2 給關(guān)鍵詞字段),動態(tài)調(diào)整結(jié)果偏向。

特性?全文搜索 (FTS)??混合搜索?
檢索目標(biāo)?精確關(guān)鍵詞匹配綜合語義 + 關(guān)鍵詞 + 多模態(tài)數(shù)據(jù)
? 技術(shù)基礎(chǔ)?稀疏向量 (BM25)多路 ANN 搜索 + RRF 融合
? 優(yōu)勢場景?代碼搜索、產(chǎn)品型號查詢RAG、多模態(tài)交叉驗證(如指紋+聲紋)
? 局限?缺乏語義理解能力需調(diào)參優(yōu)化權(quán)重平衡

推薦閱讀:混合搜索

提升語義搜索效率:LangChain 與 Milvus 的混合搜索實戰(zhàn)

參考文檔

  • https://milvus.io/docs/zh/full_text_search_with_langchain.md
http://aloenet.com.cn/news/41854.html

相關(guān)文章:

  • 坪山建設(shè)網(wǎng)站網(wǎng)絡(luò)推廣員
  • wordpress 手動安裝seo怎么做教程
  • 餐飲公司網(wǎng)站建設(shè)的特點免費b站推廣網(wǎng)址有哪些
  • 網(wǎng)站底部代碼下載百度文庫首頁
  • python網(wǎng)站開發(fā)實踐免費網(wǎng)站申請域名
  • 自己做的網(wǎng)站可以有多個前端嗎網(wǎng)站建設(shè)公司是怎么找客戶
  • 網(wǎng)站建設(shè) 上市公司杭州網(wǎng)站seo外包
  • 網(wǎng)站開發(fā)還找到工作嗎鏈網(wǎng)
  • 做網(wǎng)站建設(shè)要什么證小網(wǎng)站
  • 影樓網(wǎng)站推廣seo系統(tǒng)優(yōu)化
  • 網(wǎng)站建設(shè)方案模板高校引流軟件下載站
  • 做優(yōu)化網(wǎng)站是什么意思誰有推薦的網(wǎng)址
  • 有什么好看的網(wǎng)站seo系統(tǒng)培訓(xùn)
  • 如何侵入網(wǎng)站服務(wù)器免費企業(yè)黃頁查詢官網(wǎng)
  • 宜興網(wǎng)站制作百度seo優(yōu)化及推廣
  • 政府網(wǎng)站建設(shè)運行情況寧波seo免費優(yōu)化軟件
  • 新網(wǎng)站優(yōu)化怎么做武漢seo優(yōu)化
  • 界面網(wǎng)站的風(fēng)格關(guān)鍵字c語言
  • 成都哪里有做網(wǎng)站建設(shè)的青島網(wǎng)站建設(shè)公司電話
  • 在小說網(wǎng)站做責(zé)編如何免費發(fā)布廣告
  • 網(wǎng)站制作公司智能 樂云踐新做網(wǎng)站怎么優(yōu)化
  • 網(wǎng)站模板購買房地產(chǎn)估價師考試
  • 小程序開發(fā)平臺哪里做得好seo網(wǎng)站優(yōu)化培訓(xùn)怎么做
  • 可以免費發(fā)帖的網(wǎng)站品牌廣告投放
  • asp如何做網(wǎng)站河北網(wǎng)站seo策劃
  • 網(wǎng)站瀏覽思路上海網(wǎng)絡(luò)推廣公司網(wǎng)站
  • 哪個網(wǎng)站推廣做的好引流獲客app下載
  • 關(guān)于藥品網(wǎng)站建設(shè)策劃書seo軟件哪個好
  • 做網(wǎng)站公司在深圳杭州疫情最新情況
  • 網(wǎng)站建設(shè)在線視頻上海百度推廣官網(wǎng)