整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          錄取查詢頁面怎么做?

          錄取查詢頁面怎么做?

          生錄取工作開始后,負責招生的老師需要完成一系列任務,其中包括確定招生錄取名單和及時向考生公布錄取情況。為了快速完成錄取查詢工作的發布,招生老師們可以采取以下步驟:

          1. 整理錄取名單:招生老師們首先需要整理好錄取名單,確保其中包含了所有被錄取的考生的相關信息,如姓名、學號、專業等。他們可以通過學校的招生系統或數據庫來獲取這些信息。

          2. 準備查詢頁面:招生老師們可以使用前面提到的創建錄取查詢頁面的步驟來準備一個查詢頁面。在該頁面上,他們可以設置一個查詢表單,要求考生輸入自己的相關信息,如姓名、學號等,然后點擊查詢按鈕。這個頁面可以利用易查分輕松實現,不需要任何費用,只需把錄取名單制作成Excel表格,導入易查分,就可以生成功能強大的錄取查詢頁面,考生輸入查詢條件,即可自己查錄取信息。


          3. 導入錄取名單:招生老師們可以將整理好的錄取名單導入到查詢頁面的后端數據庫中。這樣,當考生輸入查詢條件后,系統可以根據錄取名單進行查詢,快速返回相應的錄取情況。

          4. 測試查詢功能:在發布查詢頁面之前,招生老師們應該進行一次測試,確保查詢功能正常運行。他們可以模擬考生輸入不同的查詢條件,檢查系統是否能夠正確地返回相應的錄取情況。

          5. 發布查詢頁面:一旦測試通過,招生老師們可以將查詢頁面鏈接發布給考生。他們可以通過學校的官方網站、招生宣傳渠道或郵件等方式,將查詢頁面的鏈接提供給考生和家長。

          6. 監控查詢情況:在查詢頁面發布后,招生老師們應該密切關注查詢情況。他們可以設置一些監控機制,如記錄查詢次數和查詢結果等,以便及時發現和解決可能出現的問題。

          通過以上步驟,招生老師們可以快速完成錄取查詢工作的發布。這樣,考生和家長可以方便地查詢自己的錄取情況,同時也減輕了招生老師們的工作負擔。


          除此之外,老師們還可以通過以下傳統的制作錄取查詢頁面的步驟,來制作一個錄取查詢頁面:

          1. 設計頁面布局:確定頁面的整體結構和布局,包括標題、查詢表單和查詢結果顯示區域等。考慮使用響應式設計,以適應不同設備的屏幕大小。

          2. 創建查詢表單:在頁面上添加一個查詢表單,包括學生的相關信息,如姓名、學號、身份證號等。可以使用HTML表單元素,如輸入框、下拉菜單和復選框等,來收集用戶輸入的查詢條件。

          3. 驗證查詢條件:在后端或前端進行查詢條件的驗證,確保輸入的信息格式正確和完整。可以使用正則表達式或其他驗證方法來檢查輸入的學號、身份證號等是否符合規定的格式。

          4. 進行查詢操作:在后端處理查詢請求,根據用戶輸入的條件,在數據庫中進行查詢操作。根據查詢結果,可以返回相應的錄取信息或錯誤提示。

          5. 顯示查詢結果:將查詢結果顯示在頁面上,可以使用表格或列表等形式展示。如果查詢結果為空,可以顯示相應的提示信息。

          6. 添加樣式和交互效果:為查詢頁面添加適當的樣式和交互效果,以提升用戶體驗。可以使用CSS來美化頁面,如設置背景顏色、字體樣式和按鈕樣式等。可以使用JavaScript或其他前端框架,實現一些交互效果,如實時搜索和動態加載查詢結果等。

          7. 測試和優化:進行頁面的測試,確保查詢功能正常運行,并檢查頁面在不同瀏覽器和設備上的兼容性。根據用戶的反饋和測試結果,進行必要的優化和改進。

          8. 部署和發布:將查詢頁面部署到服務器上,并將查詢頁面的鏈接提供給學生和家長。確保服務器的穩定性和安全性,以保護學生信息的機密性。

          以上是創建一個錄取查詢頁面的一般步驟,具體實現可以根據需求和技術要求進行調整和修改。

          施 RAG 是一個挑戰,特別是在有效解析和理解非結構化文檔中的表格時。這對于掃描文檔或圖像格式的文檔尤其困難。這些挑戰至少有三個方面:

          • 掃描文檔或圖像文檔的復雜性,例如其不同的結構、包含的非文本元素以及手寫和打印內容的結合,給自動準確提取表格信息帶來了挑戰。不準確的解析會損壞表結構,并且使用不完整的表進行嵌入不僅無法捕獲表的語義信息,而且還很容易破壞RAG結果。
          • 如何提取表格標題并將其有效鏈接到各自的表格。
          • 如何設計索引結構來有效存儲表的語義信息。

          本文首先介紹RAG中管理表的關鍵技術。然后,在提出和實施新的解決方案之前,它會審查一些現有的開源解決方案。

          關鍵技術

          表解析

          該模塊的主要功能是從非結構化文檔或圖像中準確提取表結構。

          附加功能:最好能提取對應的表格標題,方便開發者將表格標題與表格關聯起來。

          根據我目前的理解,有以下幾種方法,如圖1所示:

          圖 1:表解析器。圖片由作者提供。

          (a) 利用多模態 LLM(例如GPT-4V)來識別表格并從每個 PDF 頁面中提取信息。

          • 輸入:圖像格式的 PDF 頁面
          • 輸出:JSON 或其他格式的表。如果多模態 LLM 無法提取表數據,它應該總結圖像并返回摘要。

          (b)利用專業的表檢測模型,如Table Transformer,來識別表結構。

          • 輸入:PDF 頁面作為圖像
          • 輸出:表格作為圖像

          (c)使用開源框架,例如非結構化框架和其他框架,它們也采用對象檢測模型(本文詳細介紹了非結構化的表檢測過程)。這些框架允許對整個文檔進行全面解析,并從解析結果中提取與表格相關的內容。

          • 輸入:PDF或圖像格式的文檔
          • 輸出:純文本或HTML格式的表格,從整個文檔的解析結果得到

          (d) 使用 Nougat、Donut等端到端模型來解析整個文檔并提取與表相關的內容。此方法不需要 OCR 模型。

          • 輸入:PDF或圖像格式的文檔
          • 輸出:LaTeX或JSON格式的表格,從整個文檔的解析結果獲得

          值得一提的是,無論采用何種方法提取表格信息,都應包含表格標題。這是因為在大多數情況下,表格標題是文檔或論文作者對表格的簡要描述,可以很大程度上概括整個表格。

          在上述四種方法中,方法(d)可以輕松檢索表格標題。這對開發人員來說是有益的,因為它允許他們將表格標題與表格關聯起來。這將在下面的實驗中進一步解釋。

          指數結構

          根據索引的結構,解決方案大致可以分為以下幾類:

          (e) 僅以圖像格式索引表。

          (f)僅索引純文本或 JSON 格式的表。

          (g)僅索引 LaTeX 格式的表。

          (h)只索引表的摘要。

          (i)從小到大或文檔摘要索引結構,如圖2所示。

          • 小塊的內容可以是來自表的每一行的信息或表的摘要。
          • 大塊的內容可以是圖像格式、純文本格式或LaTeX格式的表格。

          圖 2:從小到大索引(上)和文檔摘要索引(中和下)的結構。圖片由作者提供。

          如上所述,表格摘要通常是使用 LLM 生成的:

          • 輸入:圖像格式、文本格式或LaTeX格式的表格
          • 輸出:表格摘要

          不需要表解析、索引或 RAG 的算法

          有些算法不需要表解析。

          (j).將相關圖像(PDF頁面)和用戶的查詢發送到VQA模型(如DAN等)或多模態LLM,并返回答案。

          • 待索引內容:圖像格式的文檔
          • 發送到VQA模型或多模態LLM的內容:查詢+圖片形式的對應頁面

          (k)將相關文本格式的PDF頁面和用戶的查詢發送給LLM,然后返回答案。

          • 要索引的內容:文本格式的文檔
          • 發送給LLM的內容:查詢+文本格式對應頁面

          (l)相關圖像(PDF頁面)、文本塊和用戶查詢發送到多模態LLM(如GPT-4V等)并直接返回答案。

          • 要索引的內容:圖像格式的文檔和文本格式的文檔塊
          • 發送到多模態LLM的內容:查詢+文檔對應的圖像形式+對應的文本塊

          另外,下面是一些不需要索引的方法,如圖3和圖4所示:

          圖 3:類別 (m)。圖片由作者提供。

          (m)首先,應用類別(a)至(d)中的一種方法,將文檔中的所有表格解析為圖像形式。然后直接將所有表格圖像和用戶的查詢發送到多模態LLM(如GPT-4V等)并返回答案。

          • 要索引的內容:無
          • 發送到多模式LLM的內容:查詢+所有解析的表(圖像格式)

          圖 4:類別 (n)。圖片由作者提供。

          (n)使用(m)提取的圖像格式的表格,然后使用OCR模型識別表格中的所有文本,然后將表格中的所有文本和用戶的查詢直接發送給LLM并直接返回答案。

          • 要索引的內容:無
          • 發送給LLM的內容:用戶查詢+所有表內容(文本格式)

          值得注意的是,有些方法不依賴于 RAG 過程:

          • 第一種方法不使用 LLM,在特定數據集上進行訓練,并使模型(例如類似 BERT 的轉換器)能夠更好地支持表理解任務,例如TAPAS。
          • 第二種方法使用LLM,采用預訓練、微調方法或提示,使LLM能夠執行表理解任務,例如GPT4Table。

          現有的開源解決方案

          上一節對 RAG 中表的關鍵技術進行了總結和分類。在提出本文實現的解決方案之前,讓我們先探索一些開源解決方案。

          LlamaIndex 提出了四種方法,前三種使用多模態模型。

          1. 檢索相關圖像(PDF 頁面)并將其發送到 GPT-4V 以響應查詢。
          2. 將每個PDF頁面視為一個圖像,讓GPT-4V對每個頁面進行圖像推理。為圖像推理構建文本向量存儲索引。針對圖像推理向量存儲查詢答案。
          3. 使用 Table Transformer 從檢索到的圖像中裁剪表格信息,然后將這些裁剪后的圖像發送到 GPT-4V 以進行查詢響應。
          4. 對裁剪后的表格圖像應用 OCR 并將數據發送到 GPT4/GPT-3.5 以回答查詢。

          按照本文的分類:

          • 第一種方法與本文中的類別(j)類似,不需要表解析。然而,結果表明,即使答案在圖像中,也無法產生正確的答案。
          • 第二種方法涉及表解析,對應類別(a)。索引內容是表格內容或摘要,基于 GPT-4V 返回的結果,可能對應于類別 (f) 或 (h)。此方法的缺點是 GPT-4V 識別表格并從圖像中提取其內容的能力不穩定,特別是當圖像包含表格、文本和其他圖像的混合時(這在 PDF 格式中很常見)。
          • 第三種方法與類別 (m)類似,不需要索引。
          • 第四種方法與category (n)類似,也不需要索引。其結果表明,由于無法從圖像中提取表格信息,因此產生了錯誤的答案。

          經過測試,發現第三種方法總體效果最好。然而,根據我的測試,第三種方法很難檢測表格,更不用說正確地將表格標題與表格合并了。

          Langchain也提出了一些解決方案,半結構化RAG的關鍵技術包括:

          • 表解析使用非結構化,屬于類別 (c)
          • 索引方式為文檔摘要索引,屬于類別(i),小塊內容:表格摘要,大塊內容:原始表格內容(文本格式)。

          如圖5所示:

          圖 5:Langchain 的半結構化 RAG。來源:半結構化 RAG

          半結構化和多模態 RAG提出了三種解決方案,其架構如圖 6 所示。

          圖 6:Langchain 的半結構化和多模式 RAG。來源:半結構化和多模式 RAG。

          選項 1與本文的類別 (l)類似。它涉及使用多模態嵌入(例如CLIP)來嵌入圖像和文本,使用相似性搜索檢索兩者,并將原始圖像和塊傳遞到多模態 LLM 進行答案合成。

          選項 2利用多模態 LLM(例如GPT-4V、LLaVA或FUYU-8b)從圖像生成文本摘要。然后,嵌入和檢索文本,并將文本塊傳遞給 LLM 進行答案合成。

          • 表解析使用非結構化,即類別 (d)
          • 索引結構為文檔摘要索引(catogery(i)),小塊內容:表格摘要,大塊內容:文本格式的表格

          選項 3使用多模態 LLM(例如GPT-4V、LLaVA或FUYU-8b)從圖像生成文本摘要,然后參考原始圖像(類別 (i))嵌入和檢索圖像摘要,然后傳遞原始圖像將圖像和文本塊傳輸到多模式法學碩士以進行答案合成。

          建議的解決方案

          本文對關鍵技術和現有解決方案進行了總結、分類和討論。基于此,我們提出了以下解決方案,如圖 7 所示。為了簡單起見,省略了一些 RAG 模塊,例如重新排名和查詢重寫。

          圖 7:本文建議的解決方案。圖片由作者提供。

          • 表解析:使用Nougat(類別(d))。根據我的測試,它的表檢測比非結構化(類別(c))更有效。另外,Nougat可以很好地提取表格標題,非常方便與表格關聯。
          • 文檔摘要索引結構(類別(i)):小塊的內容包括表格摘要,大塊的內容包括LaTeX格式的相應表格和文本格式的表格標題。我們使用多向量檢索器來實現它。
          • 表格摘要獲取方法:將表格和表格標題發送給LLM進行摘要。

          這種方法的優點是能夠高效地解析表格,同時綜合考慮表格匯總和表格之間的關系。它還消除了對多模態LLM的需求,從而節省了成本。

          Nougat的原理

          Nougat是基于Donut架構開發的。它通過網絡隱式識別文本,無需任何 OCR 相關輸入或模塊,如圖 8 所示。

          圖 8:遵循Donut 的端到端架構。 Swin Transformer 編碼器獲取文檔圖像并將其轉換為潛在嵌入,隨后以自回歸方式將其轉換為標記序列。資料來源:Nougat:學術文檔的神經光學理解。

          Nougat 解析公式的能力令人印象深刻。它在解析表方面也很出色。它可以方便地關聯表格標題,如圖 9 所示:

          圖9:Nougat運行結果,結果文件為Mathpix Markdown格式(通過vscode插件打開),表格為LaTeX格式。

          在我對十幾篇論文的測試中,我發現表格標題總是固定在表格后面的行上。這種一致性表明這并非偶然。因此,我們有興趣了解Nougat是如何實現這種效果的。

          鑒于它是一個缺乏中間結果的端到端模型,它可能嚴重依賴于其訓練數據。

          根據格式化訓練數據的代碼,對于 table 來說,緊接著的一行\end{table}caption_parts,這看起來與提供的訓練數據的格式一致:

          def format_element(
              element: Element, keep_refs: bool=False, latex_env: bool=False
          ) -> List[str]:
              """
              Formats a given Element into a list of formatted strings.
          
              Args:
                  element (Element): The element to be formatted.
                  keep_refs (bool, optional): Whether to keep references in the formatting. Default is False.
                  latex_env (bool, optional): Whether to use LaTeX environment formatting. Default is False.
          
              Returns:
                  List[str]: A list of formatted strings representing the formatted element.
              """
              ...
              ...
              if isinstance(element, Table):
                  parts=[
                      "[TABLE%s]\n\\begin{table}\n"
                      % (str(uuid4())[:5] if element.id is None else ":" + str(element.id))
                  ]
                  parts.extend(format_children(element, keep_refs, latex_env))
                  caption_parts=format_element(element.caption, keep_refs, latex_env)
                  remove_trailing_whitespace(caption_parts)
                  parts.append("\\end{table}\n")
                  if len(caption_parts) > 0:
                      parts.extend(caption_parts + ["\n"])
                  parts.append("[ENDTABLE]\n\n")
                  return parts
              ...
              ...

          Nougat的優點和缺點

          優點:

          • Nougat 可以準確地將公式和表格等對以前的解析工具來說具有挑戰性的部分解析為 LaTeX 源代碼。
          • Nougat的解析結果是類似于markdown的半結構化文檔。
          • 輕松獲取表格標題并將其與表格方便地關聯起來。

          缺點:

          • Nougat的解析速度較慢,這對于大規模部署來說可能是一個挑戰。
          • 由于 Nougat 接受過科學論文方面的培訓,因此它擅長處理類似結構的文檔。對于非拉丁文本文檔,其性能會下降。
          • Nougat 模型一次僅在科學論文的一頁上進行訓練,缺乏對其他頁面的了解。這可能會導致解析的內容出現一些不一致。因此,如果識別效果不好,可以考慮將PDF分成單獨的頁面,然后一頁一頁地進行解析。
          • 解析兩列論文中的表格不如單列論文中的有效。

          代碼實現

          首先,安裝相關Python包

          pip install langchain
          pip install chromadb
          pip install nougat-ocr

          安裝完成后,我們可以查看Python包的版本:

          langchain                                 0.1 .12
           langchain-community                       0.0 .28
           langchain-core                            0.1 .31
           langchain-openai                          0.0 .8
           langchain-text-splitters                  0.0 .1
          
           chroma-hnswlib                            0.7 .3
           chromadb                                  0.4 .24
          
           nougat-ocr                                0.1 .17

          設置環境并導入:

          import os
          os.environ["OPENAI_API_KEY"]="YOUR_OPEN_AI_KEY"
          
          import subprocess
          import uuid
          
          from langchain_core.output_parsers import StrOutputParser
          from langchain_core.prompts import ChatPromptTemplate
          from langchain_openai import ChatOpenAI
          from langchain.retrievers.multi_vector import MultiVectorRetriever
          from langchain.storage import InMemoryStore
          from langchain_community.vectorstores import Chroma
          from langchain_core.documents import Document
          from langchain_openai import OpenAIEmbeddings
          from langchain_core.runnables import RunnablePassthrough

          下載《Attention Is All You Need to》論文YOUR_PDF_PATH,運行nougat解析PDF文件,從解析結果中獲取latex格式的表格和文本格式的表格標題。第一次執行將下載必要的模型文件。

          def june_run_nougat(file_path, output_dir):
              # Run Nougat and store results as Mathpix Markdown
              cmd=["nougat", file_path, "-o", output_dir, "-m", "0.1.0-base", "--no-skipping"]
              res=subprocess.run(cmd) 
              if res.returncode !=0:
                  print("Error when running nougat.")
                  return res.returncode
              else:
                  print("Operation Completed!")
                  return 0
          
          def june_get_tables_from_mmd(mmd_path):
              f=open(mmd_path)
              lines=f.readlines()
              res=[]
              tmp=[]
              flag=""
              for line in lines:
                  if line=="\\begin{table}\n":
                      flag="BEGINTABLE"
                  elif line=="\\end{table}\n":
                      flag="ENDTABLE"
                  
                  if flag=="BEGINTABLE":
                      tmp.append(line)
                  elif flag=="ENDTABLE":
                      tmp.append(line)
                      flag="CAPTION"
                  elif flag=="CAPTION":
                      tmp.append(line)
                      flag="MARKDOWN"
                      print('-' * 100)
                      print(''.join(tmp))
                      res.append(''.join(tmp))
                      tmp=[]
          
              return res
          
          file_path="YOUR_PDF_PATH"
          output_dir="YOUR_OUTPUT_DIR_PATH"
          
          if june_run_nougat(file_path, output_dir)==1:
              import sys
              sys.exit(1)
          
          mmd_path=output_dir + '/' + os.path.splitext(file_path)[0].split('/')[-1] + ".mmd" 
          tables=june_get_tables_from_mmd(mmd_path)

          該函數june_get_tables_from_mmd用于從圖 10 所示的文件中提取從 t\begin{table}到 的所有內容\end{table},包括 后面的行。\end{table}mmd

          圖10:Nougat運行結果,結果文件為Mathpix Markdown格式(通過vscode插件打開),表格為latex格式。The function of june_get_tables_from_mmd is to extract the table information in the red box圖片由作者提供。

          值得注意的是,目前還沒有找到官方文檔規定表格標題必須放在表格下方或者表格以 開頭\begin{table}和結尾\end{table}。因此,june_get_tables_from_mmd是啟發式的。

          以下是解析 PDF 中表格的結果:

          Operation Completed!
          ----------------------------------------------------------------------------------------------------
          \begin{table}
          \begin{tabular}{l c c c} \hline \hline Layer Type & Complexity per Layer & Sequential Operations & Maximum Path Length \\ \hline Self-Attention & \(O(n^{2}\cdot d)\) & \(O(1)\) & \(O(1)\) \\ Recurrent & \(O(n\cdot d^{2})\) & \(O(n)\) & \(O(n)\) \\ Convolutional & \(O(k\cdot n\cdot d^{2})\) & \(O(1)\) & \(O(log_{k}(n))\) \\ Self-Attention (restricted) & \(O(r\cdot n\cdot d)\) & \(O(1)\) & \(O(n/r)\) \\ \hline \hline \end{tabular}
          \end{table}
          Table 1: Maximum path lengths, per-layer complexity and minimum number of sequential operations for different layer types. \(n\) is the sequence length, \(d\) is the representation dimension, \(k\) is the kernel size of convolutions and \(r\) the size of the neighborhood in restricted self-attention.
          
          ----------------------------------------------------------------------------------------------------
          \begin{table}
          \begin{tabular}{l c c c c} \hline \hline \multirow{2}{*}{Model} & \multicolumn{2}{c}{BLEU} & \multicolumn{2}{c}{Training Cost (FLOPs)} \\ \cline{2-5}  & EN-DE & EN-FR & EN-DE & EN-FR \\ \hline ByteNet [18] & 23.75 & & & \\ Deep-Att + PosUnk [39] & & 39.2 & & \(1.0\cdot 10^{20}\) \\ GNMT + RL [38] & 24.6 & 39.92 & \(2.3\cdot 10^{19}\) & \(1.4\cdot 10^{20}\) \\ ConvS2S [9] & 25.16 & 40.46 & \(9.6\cdot 10^{18}\) & \(1.5\cdot 10^{20}\) \\ MoE [32] & 26.03 & 40.56 & \(2.0\cdot 10^{19}\) & \(1.2\cdot 10^{20}\) \\ \hline Deep-Att + PosUnk Ensemble [39] & & 40.4 & & \(8.0\cdot 10^{20}\) \\ GNMT + RL Ensemble [38] & 26.30 & 41.16 & \(1.8\cdot 10^{20}\) & \(1.1\cdot 10^{21}\) \\ ConvS2S Ensemble [9] & 26.36 & **41.29** & \(7.7\cdot 10^{19}\) & \(1.2\cdot 10^{21}\) \\ \hline Transformer (base model) & 27.3 & 38.1 & & \(\mathbf{3.3\cdot 10^{18}}\) \\ Transformer (big) & **28.4** & **41.8** & & \(2.3\cdot 10^{19}\) \\ \hline \hline \end{tabular}
          \end{table}
          Table 2: The Transformer achieves better BLEU scores than previous state-of-the-art models on the English-to-German and English-to-French newstest2014 tests at a fraction of the training cost.
          
          ----------------------------------------------------------------------------------------------------
          \begin{table}
          \begin{tabular}{c|c c c c c c c c|c c c c} \hline \hline  & \(N\) & \(d_{\text{model}}\) & \(d_{\text{ff}}\) & \(h\) & \(d_{k}\) & \(d_{v}\) & \(P_{drop}\) & \(\epsilon_{ls}\) & train steps & PPL & BLEU & params \\ \hline base & 6 & 512 & 2048 & 8 & 64 & 64 & 0.1 & 0.1 & 100K & 4.92 & 25.8 & 65 \\ \hline \multirow{4}{*}{(A)} & \multicolumn{1}{c}{} & & 1 & 512 & 512 & & & & 5.29 & 24.9 & \\  & & & & 4 & 128 & 128 & & & & 5.00 & 25.5 & \\  & & & & 16 & 32 & 32 & & & & 4.91 & 25.8 & \\  & & & & 32 & 16 & 16 & & & & 5.01 & 25.4 & \\ \hline (B) & \multicolumn{1}{c}{} & & \multicolumn{1}{c}{} & & 16 & & & & & 5.16 & 25.1 & 58 \\  & & & & & 32 & & & & & 5.01 & 25.4 & 60 \\ \hline \multirow{4}{*}{(C)} & 2 & \multicolumn{1}{c}{} & & & & & & & & 6.11 & 23.7 & 36 \\  & 4 & & & & & & & & 5.19 & 25.3 & 50 \\  & 8 & & & & & & & & 4.88 & 25.5 & 80 \\  & & 256 & & 32 & 32 & & & & 5.75 & 24.5 & 28 \\  & 1024 & & 128 & 128 & & & & 4.66 & 26.0 & 168 \\  & & 1024 & & & & & & 5.12 & 25.4 & 53 \\  & & 4096 & & & & & & 4.75 & 26.2 & 90 \\ \hline \multirow{4}{*}{(D)} & \multicolumn{1}{c}{} & & & & & 0.0 & & 5.77 & 24.6 & \\  & & & & & & 0.2 & & 4.95 & 25.5 & \\  & & & & & & & 0.0 & 4.67 & 25.3 & \\  & & & & & & & 0.2 & 5.47 & 25.7 & \\ \hline (E) & \multicolumn{1}{c}{} & \multicolumn{1}{c}{} & & \multicolumn{1}{c}{} & & & & & 4.92 & 25.7 & \\ \hline big & 6 & 1024 & 4096 & 16 & & 0.3 & 300K & **4.33** & **26.4** & 213 \\ \hline \hline \end{tabular}
          \end{table}
          Table 3: Variations on the Transformer architecture. Unlisted values are identical to those of the base model. All metrics are on the English-to-German translation development set, newstest2013. Listed perplexities are per-wordpiece, according to our byte-pair encoding, and should not be compared to per-word perplexities.
          
          ----------------------------------------------------------------------------------------------------
          \begin{table}
          \begin{tabular}{c|c|c} \hline
          **Parser** & **Training** & **WSJ 23 F1** \\ \hline Vinyals \& Kaiser et al. (2014) [37] & WSJ only, discriminative & 88.3 \\ Petrov et al. (2006) [29] & WSJ only, discriminative & 90.4 \\ Zhu et al. (2013) [40] & WSJ only, discriminative & 90.4 \\ Dyer et al. (2016) [8] & WSJ only, discriminative & 91.7 \\ \hline Transformer (4 layers) & WSJ only, discriminative & 91.3 \\ \hline Zhu et al. (2013) [40] & semi-supervised & 91.3 \\ Huang \& Harper (2009) [14] & semi-supervised & 91.3 \\ McClosky et al. (2006) [26] & semi-supervised & 92.1 \\ Vinyals \& Kaiser el al. (2014) [37] & semi-supervised & 92.1 \\ \hline Transformer (4 layers) & semi-supervised & 92.7 \\ \hline Luong et al. (2015) [23] & multi-task & 93.0 \\ Dyer et al. (2016) [8] & generative & 93.3 \\ \hline \end{tabular}
          \end{table}
          Table 4: The Transformer generalizes well to English constituency parsing (Results are on Section 23 of WSJ)* [5] Kyunghyun Cho, Bart van Merrienboer, Caglar Gulcehre, Fethi Bougares, Holger Schwenk, and Yoshua Bengio. Learning phrase representations using rnn encoder-decoder for statistical machine translation. _CoRR_, abs/1406.1078, 2014.

          然后用LLM總結一下表格:

          # Prompt
          prompt_text="""You are an assistant tasked with summarizing tables and text. \ 
          Give a concise summary of the table or text. The table is formatted in LaTeX, and its caption is in plain text format: {element}  """
          prompt=ChatPromptTemplate.from_template(prompt_text)
          
          # Summary chain
          model=ChatOpenAI(temperature=0, model="gpt-3.5-turbo")
          summarize_chain={"element": lambda x: x} | prompt | model | StrOutputParser()
          # Get table summaries
          table_summaries=summarize_chain.batch(tables, {"max_concurrency": 5})
          print(table_summaries)

          以下是Attention Is All You Need中找到的四個表的摘要,如圖 11 所示:

          圖 11: Attention Is All You Need中找到的四個表的表摘要。

          使用Multi-Vector Retriever構建文檔摘要索引結構。

          # The vectorstore to use to index the child chunks
          vectorstore=Chroma(collection_name="summaries", embedding_function=OpenAIEmbeddings())
          
          # The storage layer for the parent documents
          store=InMemoryStore()
          id_key="doc_id"
          
          # The retriever (empty to start)
          retriever=MultiVectorRetriever(
              vectorstore=vectorstore,
              docstore=store,
              id_key=id_key,
              search_kwargs={"k": 1} # Solving Number of requested results 4 is greater than number of elements in index..., updating n_results=1
          )
          
          # Add tables
          table_ids=[str(uuid.uuid4()) for _ in tables]
          summary_tables=[
              Document(page_content=s, metadata={id_key: table_ids[i]})
              for i, s in enumerate(table_summaries)
          ]
          retriever.vectorstore.add_documents(summary_tables)
          retriever.docstore.mset(list(zip(table_ids, tables)))

          一切準備就緒,構建一個簡單的RAG管道,并執行查詢:

          # Prompt template
          template="""Answer the question based only on the following context, which can include text and tables, there is a table in LaTeX format and a table caption in plain text format:
          {context}
          Question: {question}
          """
          prompt=ChatPromptTemplate.from_template(template)
          
          # LLM
          model=ChatOpenAI(temperature=0, model="gpt-3.5-turbo")
          
          
          # Simple RAG pipeline
          chain=(
              {"context": retriever, "question": RunnablePassthrough()}
              | prompt
              | model
              | StrOutputParser()
          )
          
          
          print(chain.invoke("when layer type is Self-Attention, what is the Complexity per Layer?"))  # Query about table 1
          
          print(chain.invoke("Which parser performs worst for BLEU EN-DE"))  # Query about table 2
          
          print(chain.invoke("Which parser performs best for WSJ 23 F1"))  # Query about table 4
          

          執行結果如下,說明幾個問題都得到了準確的解答,如圖12所示:

          圖 12:三個查詢的結果。第一行對應Attention Is All You Need中的查詢表1 ,第二行對應表2,第三行對應表4。

          整體代碼如下:

          import os
          os.environ["OPENAI_API_KEY"]="YOUR_OPEN_AI_KEY"
          
          import subprocess
          import uuid
          
          from langchain_core.output_parsers import StrOutputParser
          from langchain_core.prompts import ChatPromptTemplate
          from langchain_openai import ChatOpenAI
          from langchain.retrievers.multi_vector import MultiVectorRetriever
          from langchain.storage import InMemoryStore
          from langchain_community.vectorstores import Chroma
          from langchain_core.documents import Document
          from langchain_openai import OpenAIEmbeddings
          from langchain_core.runnables import RunnablePassthrough
          
          
          def june_run_nougat(file_path, output_dir):
              # Run Nougat and store results as Mathpix Markdown
              cmd=["nougat", file_path, "-o", output_dir, "-m", "0.1.0-base", "--no-skipping"]
              res=subprocess.run(cmd) 
              if res.returncode !=0:
                  print("Error when running nougat.")
                  return res.returncode
              else:
                  print("Operation Completed!")
                  return 0
          
          def june_get_tables_from_mmd(mmd_path):
              f=open(mmd_path)
              lines=f.readlines()
              res=[]
              tmp=[]
              flag=""
              for line in lines:
                  if line=="\\begin{table}\n":
                      flag="BEGINTABLE"
                  elif line=="\\end{table}\n":
                      flag="ENDTABLE"
                  
                  if flag=="BEGINTABLE":
                      tmp.append(line)
                  elif flag=="ENDTABLE":
                      tmp.append(line)
                      flag="CAPTION"
                  elif flag=="CAPTION":
                      tmp.append(line)
                      flag="MARKDOWN"
                      print('-' * 100)
                      print(''.join(tmp))
                      res.append(''.join(tmp))
                      tmp=[]
          
              return res
          
          file_path="YOUR_PDF_PATH"
          output_dir="YOUR_OUTPUT_DIR_PATH"
          
          if june_run_nougat(file_path, output_dir)==1:
              import sys
              sys.exit(1)
          
          mmd_path=output_dir + '/' + os.path.splitext(file_path)[0].split('/')[-1] + ".mmd" 
          tables=june_get_tables_from_mmd(mmd_path)
          
          
          # Prompt
          prompt_text="""You are an assistant tasked with summarizing tables and text. \ 
          Give a concise summary of the table or text. The table is formatted in LaTeX, and its caption is in plain text format: {element}  """
          prompt=ChatPromptTemplate.from_template(prompt_text)
          
          # Summary chain
          model=ChatOpenAI(temperature=0, model="gpt-3.5-turbo")
          summarize_chain={"element": lambda x: x} | prompt | model | StrOutputParser()
          # Get table summaries
          table_summaries=summarize_chain.batch(tables, {"max_concurrency": 5})
          print(table_summaries)
          
          # The vectorstore to use to index the child chunks
          vectorstore=Chroma(collection_name="summaries", embedding_function=OpenAIEmbeddings())
          
          # The storage layer for the parent documents
          store=InMemoryStore()
          id_key="doc_id"
          
          # The retriever (empty to start)
          retriever=MultiVectorRetriever(
              vectorstore=vectorstore,
              docstore=store,
              id_key=id_key,
              search_kwargs={"k": 1} # Solving Number of requested results 4 is greater than number of elements in index..., updating n_results=1
          )
          
          # Add tables
          table_ids=[str(uuid.uuid4()) for _ in tables]
          summary_tables=[
              Document(page_content=s, metadata={id_key: table_ids[i]})
              for i, s in enumerate(table_summaries)
          ]
          retriever.vectorstore.add_documents(summary_tables)
          retriever.docstore.mset(list(zip(table_ids, tables)))
          
          
          # Prompt template
          template="""Answer the question based only on the following context, which can include text and tables, there is a table in LaTeX format and a table caption in plain text format:
          {context}
          Question: {question}
          """
          prompt=ChatPromptTemplate.from_template(template)
          
          # LLM
          model=ChatOpenAI(temperature=0, model="gpt-3.5-turbo")
          
          # Simple RAG pipeline
          chain=(
              {"context": retriever, "question": RunnablePassthrough()}
              | prompt
              | model
              | StrOutputParser()
          )
          
          print(chain.invoke("when layer type is Self-Attention, what is the Complexity per Layer?"))  # Query about table 1
          
          print(chain.invoke("Which parser performs worst for BLEU EN-DE"))  # Query about table 2
          
          print(chain.invoke("Which parser performs best for WSJ 23 F1"))  # Query about table 4

          結論

          本文討論了RAG流程中表處理的關鍵技術和現有解決方案,并提出了解決方案及其實現。

          我們在本文中使用 nougat 來解析表格。但是,如果有更快、更有效的解析工具可用,我們會考慮替換 nougat。我們對待工具的態度是先有正確的想法,然后找到工具來實現,而不是依賴于某種工具。

          在本文中,我們將所有表格內容輸入到LLM中。然而,在實際場景中,我們應該考慮表超出LLM上下文長度的情況。我們可以通過使用有效的分塊方法來解決這個問題。

          人負責的項目主要采用阿里云數據庫 MySQL,最近頻繁出現慢 SQL 告警,執行時間最長的竟然高達 5 分鐘。

          圖片來自 Pexels

          導出日志后分析,主要原因竟然是沒有命中索引和沒有分頁處理。其實這是非常低級的錯誤,我不禁后背一涼,團隊成員的技術水平亟待提高啊。

          改造這些 SQL 的過程中,總結了一些經驗分享給大家,如果有錯誤歡迎批評指正。

          MySQL 性能

          ①最大數據量

          拋開數據量和并發數,談性能都是耍流氓。MySQL 沒有限制單表最大記錄數,它取決于操作系統對文件大小的限制。

          《阿里巴巴 Java 開發手冊》提出單表行數超過 500 萬行或者單表容量超過 2GB,才推薦分庫分表。

          性能由綜合因素決定,拋開業務復雜度,影響程度依次是硬件配置、MySQL 配置、數據表設計、索引優化。500 萬這個值僅供參考,并非鐵律。

          我曾經操作過超過 4 億行數據的單表,分頁查詢最新的 20 條記錄耗時 0.6 秒,SQL 語句大致是:

          select field_1,field_2 from table where id < #{prePageMinId} order by id desc limit 20 

          prePageMinId 是上一頁數據記錄的最小 ID。雖然當時查詢速度還湊合,隨著數據不斷增長,有朝一日必定不堪重負。

          分庫分表是個周期長而風險高的大活兒,應該盡可能在當前結構上優化,比如升級硬件、遷移歷史數據等等,實在沒轍了再分。對分庫分表感興趣的同學可以閱讀分庫分表的基本思想。

          ②最大并發數

          并發數是指同一時刻數據庫能處理多少個請求,由 max_connections 和 max_user_connections 決定。

          max_connections 是指 MySQL 實例的最大連接數,上限值是 16384,max_user_connections 是指每個數據庫用戶的最大連接數。

          MySQL 會為每個連接提供緩沖區,意味著消耗更多的內存。如果連接數設置太高硬件吃不消,太低又不能充分利用硬件。

          一般要求兩者比值超過 10%,計算方法如下:

          max_used_connections / max_connections * 100% = 3/100 *100% ≈ 3% 

          查看最大連接數與響應最大連接數:

          show variables like '%max_connections%'; 
          show variables like '%max_user_connections%'; 

          在配置文件 my.cnf 中修改最大連接數:

          [mysqld] 
          max_connections=100 
          max_used_connections=20 

          ③查詢耗時 0.5 秒

          建議將單次查詢耗時控制在 0.5 秒以內,0.5 秒是個經驗值,源于用戶體驗的 3 秒原則。如果用戶的操作 3 秒內沒有響應,將會厭煩甚至退出。

          響應時間=客戶端 UI 渲染耗時+網絡請求耗時+應用程序處理耗時+查詢數據庫耗時,0.5 秒就是留給數據庫 1/6 的處理時間。

          ④實施原則

          相比 NoSQL 數據庫,MySQL 是個嬌氣脆弱的家伙。它就像體育課上的女同學,一點糾紛就和同學鬧別扭(擴容難),跑兩步就氣喘吁吁(容量小并發低),常常身體不適要請假(SQL 約束太多)。

          如今大家都會搞點分布式,應用程序擴容比數據庫要容易得多,所以實施原則是數據庫少干活,應用程序多干活:

          • 充分利用但不濫用索引,須知索引也消耗磁盤和 CPU。
          • 不推薦使用數據庫函數格式化數據,交給應用程序處理。
          • 不推薦使用外鍵約束,用應用程序保證數據準確性。
          • 寫多讀少的場景,不推薦使用唯一索引,用應用程序保證唯一性。
          • 適當冗余字段,嘗試創建中間表,用應用程序計算中間結果,用空間換時間。
          • 不允許執行極度耗時的事務,配合應用程序拆分成更小的事務。
          • 預估重要數據表(比如訂單表)的負載和數據增長態勢,提前優化。

          數據表設計

          ①數據類型

          數據類型的選擇原則,更簡單或者占用空間更小:

          • 如果長度能夠滿足,整型盡量使用 tinyint、smallint、medium_int 而非 int。
          • 如果字符串長度確定,采用 char 類型。
          • 如果 varchar 能夠滿足,不采用 text 類型。
          • 精度要求較高的使用 decimal 類型,也可以使用 BIGINT,比如精確兩位小數就乘以 100 后保存。
          • 盡量采用 timestamp 而非 datetime。


          相比 datetime,timestamp 占用更少的空間,以 UTC 的格式儲存自動轉換時區。

          ②避免空值

          MySQL 中字段為 NULL 時依然占用空間,會使索引、索引統計更加復雜。從 NULL 值更新到非 NULL 無法做到原地更新,容易發生索引分裂影響性能。

          因此盡可能將 NULL 值用有意義的值代替,也能避免 SQL 語句里面包含 is not null 的判斷。

          ③Text 類型優化

          由于 Text 字段儲存大量數據,表容量會很早漲上去,影響其他字段的查詢性能。建議抽取出來放在子表里,用業務主鍵關聯。

          索引優化

          索引分類如下:

          • 普通索引:最基本的索引。
          • 組合索引:多個字段上建立的索引,能夠加速復合查詢條件的檢索。
          • 唯一索引:與普通索引類似,但索引列的值必須唯一,允許有空值。
          • 組合唯一索引:列值的組合必須唯一。
          • 主鍵索引:特殊的唯一索引,用于唯一標識數據表中的某一條記錄,不允許有空值,一般用 primary key 約束。
          • 全文索引:用于海量文本的查詢,MySQL 5.6 之后的 InnoDB 和 MyISAM 均支持全文索引。由于查詢精度以及擴展性不佳,更多的企業選擇 Elasticsearch。

          索引優化原則:

          • 分頁查詢很重要,如果查詢數據量超過 30%,MySQL 不會使用索引。
          • 單表索引數不超過 5 個、單個索引字段數不超過 5 個。
          • 字符串可使用前綴索引,前綴長度控制在 5-8 個字符。
          • 字段唯一性太低,增加索引沒有意義,如:是否刪除、性別。
          • 合理使用覆蓋索引,如下所示:
          select login_name, nick_name from member where login_name = ? 

          login_name, nick_name 兩個字段建立組合索引,比 login_name 簡單索引要更快。

          SQL 優化

          ①分批處理

          博主小時候看到魚塘挖開小口子放水,水面有各種漂浮物。浮萍和樹葉總能順利通過出水口,而樹枝會擋住其他物體通過,有時還會卡住,需要人工清理。

          MySQL 就是魚塘,最大并發數和網絡帶寬就是出水口,用戶 SQL 就是漂浮物。

          不帶分頁參數的查詢或者影響大量數據的 update 和 delete 操作,都是樹枝,我們要把它打散分批處理,下面舉例說明。

          業務描述:更新用戶所有已過期的優惠券為不可用狀態。

          SQL 語句:

          update status=0 FROM `coupon` WHERE expire_date <= #{currentDate} and status=1; 

          如果大量優惠券需要更新為不可用狀態,執行這條 SQL 可能會堵死其他 SQL,分批處理偽代碼如下:

          int pageNo=1; 
          int PAGE_SIZE=100; 
          while(true) { 
              List<Integer> batchIdList=queryList('select id FROM `coupon` WHERE expire_date <=#{currentDate} and status=1 limit #{(pageNo-1) * PAGE_SIZE},#{PAGE_SIZE}'); 
              if (CollectionUtils.isEmpty(batchIdList)) { 
                  return; 
              } 
              update('update status=0 FROM `coupon` where status=1 and id in #{batchIdList}') 
              pageNo ++; 
          } 

          ②操作符 <> 優化

          通常 <> 操作符無法使用索引,舉例如下,查詢金額不為 100 元的訂單:

          select id from orders where amount  != 100; 

          如果金額為 100 的訂單極少,這種數據分布嚴重不均的情況下,有可能使用索引。

          鑒于這種不確定性,采用 union 聚合搜索結果,改寫方法如下:

          (select id from orders where amount > 100) 
           union all 
          (select id from orders where amount < 100 and amount > 0) 

          ③OR 優化

          在 Innodb 引擎下 OR 無法使用組合索引,比如:

          select id,product_name from orders where mobile_no = '13421800407' or user_id = 100; 

          OR 無法命中 mobile_no + user_id 的組合索引,可采用 union,如下所示:

          (select id,product_name from orders where mobile_no='13421800407') 
           union 
          (select id,product_name from orders where user_id=100); 

          此時 id 和 product_name 字段都有索引,查詢才最高效。

          ④IN 優化

          IN 適合主表大子表小,EXIST 適合主表小子表大。由于查詢優化器的不斷升級,很多場景這兩者性能差不多一樣了。

          嘗試改為 Join 查詢,舉例如下:

          select id from orders where user_id in (select id from user where level = 'VIP'); 

          采用 Join 如下所示:

          select o.id from orders o left join user u on o.user_id = u.id where u.level = 'VIP'; 

          ⑤不做列運算

          通常在查詢條件列運算會導致索引失效,如下所示,查詢當日訂單:

          select id from order where date_format(create_time,'%Y-%m-%d') = '2019-07-01'; 

          date_format 函數會導致這個查詢無法使用索引,改寫后:

          select id from order where create_time between '2019-07-01 00:00:00' and '2019-07-01 23:59:59'; 

          ⑥避免Select All

          如果不查詢表中所有的列,避免使用 SELECT *,它會進行全表掃描,不能有效利用索引。

          ⑦Like 優化

          Like 用于模糊查詢,舉個例子(field 已建立索引):

          SELECT column FROM table WHERE field like '%keyword%'; 

          這個查詢未命中索引,換成下面的寫法:

          SELECT column FROM table WHERE field like 'keyword%'; 

          去除了前面的 % 查詢將會命中索引,但是產品經理一定要前后模糊匹配呢?全文索引 fulltext 可以嘗試一下,但 Elasticsearch 才是終極武器。

          ⑧Join 優化

          Join 的實現是采用 Nested Loop Join 算法,就是通過驅動表的結果集作為基礎數據,通過該結數據作為過濾條件到下一個表中循環查詢數據,然后合并結果。

          如果有多個 Join,則將前面的結果集作為循環數據,再次到后一個表中查詢數據。

          驅動表和被驅動表盡可能增加查詢條件,滿足 ON 的條件而少用 Where,用小結果集驅動大結果集。

          被驅動表的 Join 字段上加上索引,無法建立索引的時候,設置足夠的 Join Buffer Size。

          禁止 Join 連接三個以上的表,嘗試增加冗余字段。

          ⑨Limit 優化

          Limit 用于分頁查詢時越往后翻性能越差,解決的原則:縮小掃描范圍,如下所示:

          select * from orders order by id desc limit 100000,10  
          耗時0.4秒 
          select * from orders order by id desc limit 1000000,10 
          耗時5.2秒 

          先篩選出 ID 縮小查詢范圍,寫法如下:

          select * from orders where id > (select id from orders order by id desc  limit 1000000, 1) order by id desc limit 0,10 
          耗時0.5秒 

          如果查詢條件僅有主鍵 ID,寫法如下:

          select id from orders where id between 1000000 and 1000010 order by id desc 
          耗時0.3秒 

          如果以上方案依然很慢呢?只好用游標了,感興趣的朋友閱讀 JDBC 使用游標實現分頁查詢的方法。

          其他數據庫

          作為一名后端開發人員,務必精通作為存儲核心的 MySQL 或 SQL Server,也要積極關注 NoSQL 數據庫,他們已經足夠成熟并被廣泛采用,能解決特定場景下的性能瓶頸。

          作者:編碼磚家

          編輯:陶家龍

          出處:www.cnblogs.com/xiaoyangjia/p/11267191.html


          主站蜘蛛池模板: 亚洲A∨精品一区二区三区下载| 亚洲A∨精品一区二区三区| 蜜臀AV一区二区| 性色av闺蜜一区二区三区| 午夜精品一区二区三区免费视频| 国产综合精品一区二区| 日韩一区二区三区四区不卡| 国产亚洲福利精品一区| 91久久精一区二区三区大全| 国偷自产视频一区二区久| AV鲁丝一区鲁丝二区鲁丝三区| 国产精品毛片一区二区三区| 中文字幕精品亚洲无线码一区应用| 国产一区二区三区在线免费| 无码人妻一区二区三区免费手机| 文中字幕一区二区三区视频播放 | 亚洲Av无码一区二区二三区| 亚洲色无码一区二区三区| 综合久久久久久中文字幕亚洲国产国产综合一区首 | 免费观看一区二区三区| 人成精品视频三区二区一区 | 久久人妻av一区二区软件| 久久99精品国产一区二区三区| 亚洲AV日韩精品一区二区三区| 视频在线观看一区二区| 一区二区精品视频| 狠狠色婷婷久久一区二区| 日本一区二区免费看| 久久综合亚洲色一区二区三区 | 在线观看国产一区| 久久免费精品一区二区| 末成年女A∨片一区二区| 国产吧一区在线视频| 人妻av综合天堂一区| 国产肥熟女视频一区二区三区| 丝袜美腿高跟呻吟高潮一区| 亚洲国产一区明星换脸| 国产精品无圣光一区二区| 波多野结衣一区视频在线| 国产精品一区二区在线观看| 成人免费av一区二区三区|