😽

LangChainを用いて大量ファイルをロードするVectorDBを作ってみた(4)

2024/05/21に公開

はじめに

前回までの投稿(※)で、VectorDBに「Chroma」を適用して大量ファイルを読み込ませて、「chainlit」で質問を受ける画面を立ち上げるようにしたのですが、ファイル数が多くなるにつれて、求めている回答が得られないという事象が発生しました。
「チャンクサイズ」や「emmbeddingモデル」にも左右されると思うのですが、あまりお金をかけたくないのでvectorDBで精度の違いを確認してみることにして、最適なものを利用することにしました。

https://qiita.com/ogi_kimura/items/fa16888c60dfae0a6479

https://qiita.com/ogi_kimura/items/ecedd7c85ca1b0b0fc58

https://qiita.com/ogi_kimura/items/155a83163849db593b51

VectorDBの選定

今回比較対象とするvectorDBは、以下です。

1.Chroma

これは、以前投稿した「LangChainを用いて大量ファイルをロードするVectorDBを作ってみた(1)~(3)」で試したことがあるので、あまり問題ないです。何とかなるでしょう。

2.Qdrant

https://zenn.dev/kun432/scraps/8eab42294bde75

kun432さんの記事を見ながら見様見真似でコーディングをしてみました。
kun432さんありがとうございます!大変参考になりました。

3.FAISS

https://qiita.com/tatsuki-tsuchiyama/items/b1ab77c7f8787dbbbfae

土山竜輝さんの記事を見ながら見様見真似でコーディングをしてみました。
土山さんありがとうございます! 大変参考になりました。

早速コーディング

3つそれぞれちょっとしたプログラム方言があるので、別ファイルでプログラムを作成し、vectorDBをローカルPCに格納するような処理としました。今回は読込み対象のファイルはxmlファイルのみにしました。
 PyMuPDFLoaderは本当にすごくて、今回のプログラミングで、ExcelファイルやWordファイルも読み込んでくれることがわかりました。これは便利です。

1.Chroma

chroma.py
import glob
import os
from dotenv import load_dotenv
from langchain.text_splitter import CharacterTextSplitter
from langchain.embeddings.openai import OpenAIEmbeddings
from langchain.document_loaders import PyMuPDFLoader
from langchain.vectorstores import Chroma

load_dotenv()

docs = []

files = glob.glob(os.path.join("C:\\Users\\***\\langchain_book\\", "**/*.*"), recursive=True)
for file in files:
   base, ext = os.path.splitext(file)
   if ext == '.xml':
       topic_name = os.path.splitext(os.path.basename(file))[0]
       print(file)
       loader = PyMuPDFLoader(file)
       documents = loader.load()
       text_splitter = CharacterTextSplitter(chunk_size=100, chunk_overlap=0)
       for document in documents:
           doc = text_splitter.create_documents(texts=[document.page_content], metadatas=[{"name": topic_name, "source": file}])
           docs.extend(doc)

embeddings = OpenAIEmbeddings(model="text-embedding-ada-002")
db = Chroma(persist_directory="C:\\Users\\***\\langchain_book\\local_chroma", embedding_function=embeddings)

# トークン数制限のため、500 documentずつ処理をする
intv = 500
ln = len(docs)
max_loop = int(ln / intv) + 1
for i in range(max_loop):
   splitted_documents = text_splitter.split_documents(docs[intv * i : intv * (i+1)])
   db.add_documents(splitted_documents)

最後の方に「トークン数制限のため、500 documentずつ処理をする」という部分があるのですが、いっぺんにChatGPTに読み込ませようとしたらファイルによってはエラーになる可能性もあるので、documentsの中のdocumentを500ずつに分けました。

2.Qdrant

qdrant.py
import glob
import os
from dotenv import load_dotenv
from langchain.text_splitter import CharacterTextSplitter
from langchain.embeddings.openai import OpenAIEmbeddings
from langchain.document_loaders import PyMuPDFLoader
from langchain.vectorstores import Qdrant

load_dotenv()

docs = []

files = glob.glob(os.path.join("C:\\Users\\***\\langchain_book\\", "**/*.*"), recursive=True)
for file in files:
   base, ext = os.path.splitext(file)
   if ext == '.xml':
       topic_name = os.path.splitext(os.path.basename(file))[0]
       print(file)
       loader = PyMuPDFLoader(file)
       documents = loader.load()
       text_splitter = CharacterTextSplitter(chunk_size=100, chunk_overlap=0)
       for document in documents:
           doc = text_splitter.create_documents(texts=[document.page_content], metadatas=[{"name": topic_name, "source": file}])
           docs.extend(doc)

embeddings = OpenAIEmbeddings(model="text-embedding-ada-002")

# トークン数制限のため、500 documentずつ処理をする
intv = 500
ln = len(docs)
max_loop = int(ln / intv) + 1
db = Qdrant.from_documents(docs[0:intv], embeddings, path="C:\\Users\\***\\langchain_book\\local_qdrant", collection_name="manga_data")
for i in range(max_loop):   
   db.add_documents(docs[intv * (i+1) : intv * (i+2)])

Qdrantのコーディングは、少し苦労をしました。
Chromaのように、Qdrantでも最初にコンストラクタを定義したかったのですが、書込み時のコンストラクタは存在しないようです。
仕方なく、doc[0~500]の場合はfrom_documentsを呼んで、その後doc[500~]の場合はadd_documentsを呼ぶようにしました。

3.FAISS

faiss_.py
import glob
import os
from dotenv import load_dotenv
from langchain.text_splitter import CharacterTextSplitter
from langchain.embeddings.openai import OpenAIEmbeddings
from langchain.document_loaders import PyMuPDFLoader
from langchain.vectorstores import FAISS

load_dotenv()

docs = []

files = glob.glob(os.path.join("C:\\Users\\***\\langchain_book\\", "**/*.*"), recursive=True)
for file in files:
   base, ext = os.path.splitext(file)
   if ext == '.xml':
       topic_name = os.path.splitext(os.path.basename(file))[0]
       print(file)
       loader = PyMuPDFLoader(file)
       documents = loader.load()
       text_splitter = CharacterTextSplitter(chunk_size=100, chunk_overlap=0)
       for document in documents:
           doc = text_splitter.create_documents(texts=[document.page_content], metadatas=[{"name": topic_name, "source": file}])
           docs.extend(doc)

embeddings = OpenAIEmbeddings(model="text-embedding-ada-002")

# トークン数制限のため、500 documentずつ処理をする
intv = 500
ln = len(docs)
max_loop = int(ln / intv)
db = FAISS.from_documents(docs[0:intv], embeddings)
for i in range(max_loop):
   db.add_documents(docs[intv * (i+1) : intv * (i+2)])
db.save_local("C:\\Users\\***\\langchain_book\\local_faiss")

FAISSの場合は相当苦労しました。
FAISSでは、Qdrantと同じくfrom_documentsadd_documentsの問題は同様に発生しました。
また、最終行のsave_localですが、forループの中に書くと、ローカルデータベースを上書きしてしまうこともわかりました。そのため、forループの中でadd_documentsを呼ぶようにして、ループを抜けて最後に1回だけsave_localを呼ぶことにしました。

それから、3種類全体に関わることなのですが、embeddingtext-embedding-ada-002を利用しているのですが、OpenAIのマイページで「USAGE」(利用料金の画面)を確認すると、結構コストがかかっていました。
サイトを見てみるとtext-embedding-3-smallの方が安いようです。
ただ、今回はファイル数が多いのと、ファイル自体が大きいため、text-embedding-ada-002にしました。今回のプログラムを流すだけで2~3千円かかりました。💦

インプットに利用したファイル

今回は、特許庁の公報発行サイトのxmlファイル群を読み込んで、vectorDBへ格納することにしました。

image.png

ここからダウンロードファイル(zip)を解凍して、所定のところに置きます。

その中の1つをxmlファイルのサンプルとして示します。

0007354483.xml
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="../../../../../XSL/JPRegisteredPatentPublication.xsl"?>
<jppat:RegisteredPatentPublication xmlns:jpcom="http://www.jpo.go.jp/standards/XMLSchema/ST96/JPCommon"
                                   xmlns:jppat="http://www.jpo.go.jp/standards/XMLSchema/ST96/JPPatent"
                                   xmlns:com="http://www.wipo.int/standards/XMLSchema/ST96/Common"
                                   xmlns:pat="http://www.wipo.int/standards/XMLSchema/ST96/Patent"
                                   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                                   xsi:schemaLocation="http://www.jpo.go.jp/standards/XMLSchema/ST96/JPPatent ../../../../../XSD/JPRegisteredPatentPublication_V1_0.xsd"
                                   com:languageCode="ja"
                                   com:st96Version="V3_1"
                                   com:ipoVersion="JP_V1_0">
   <com:IPOfficeCode>JP</com:IPOfficeCode>
   <jppat:RegisteredPatentPublicationBibliographicData com:languageCode="ja">
      <com:IPOfficeCode>JP</com:IPOfficeCode>
      <jppat:PatentPublicationIdentification>
         <com:IPOfficeCode>JP</com:IPOfficeCode>
         <pat:PublicationNumber>7354483</pat:PublicationNumber>
         <com:PublicationDate>2023-10-02</com:PublicationDate>
      </jppat:PatentPublicationIdentification>
      <pat:PlainLanguageDesignationText>特許公報(B1)</pat:PlainLanguageDesignationText>
      <com:RegistrationDate>2023-09-22</com:RegistrationDate>
      <jppat:ApplicationIdentification>
         <com:ApplicationNumber>
            <com:ApplicationNumberText>2023544159</com:ApplicationNumberText>
         </com:ApplicationNumber>
         <pat:FilingDate>2023-03-27</pat:FilingDate>
      </jppat:ApplicationIdentification>
      <pat:InventionTitle>感熱記録体</pat:InventionTitle>
      <jppat:RegisteredPatentPublicationPartyBag>
         <jppat:ApplicantsRegisteredPractitionersBag>
            <jppat:ApplicantRegisteredPractitionerBag com:sequenceNumber="1">
               <jppat:Applicant com:sequenceNumber="1">
                  <com:PartyIdentifier>000183484</com:PartyIdentifier>
                  <jpcom:Contact>
                     <com:Name>
                        <com:EntityName>日本製紙株式会社</com:EntityName>
                     </com:Name>
                     <com:PostalAddressBag>
                        <com:PostalAddress>
                           <com:PostalAddressText>東京都北区王子1丁目4番1号</com:PostalAddressText>
                        </com:PostalAddress>
                     </com:PostalAddressBag>
                  </jpcom:Contact>
               </jppat:Applicant>
               <jppat:RegisteredPractitioner com:sequenceNumber="1">
                  <jppat:AgentCategory>Representative</jppat:AgentCategory>
                  <pat:RegisteredPractitionerRegistrationNumber>100113022</pat:RegisteredPractitionerRegistrationNumber>
                  <jppat:RegisteredPractitionerCategory>Attorney</jppat:RegisteredPractitionerCategory>
                  <jpcom:Contact>
                     <com:Name>
                        <com:EntityName>赤尾  謙一郎</com:EntityName>
                     </com:Name>
                  </jpcom:Contact>
               </jppat:RegisteredPractitioner>
            </jppat:ApplicantRegisteredPractitionerBag>
         </jppat:ApplicantsRegisteredPractitionersBag>
         <jppat:InventorBag>
            <jppat:Inventor com:sequenceNumber="1">
               <jpcom:Contact>
                  <com:Name>
                     <com:EntityName>越  達朗</com:EntityName>
                  </com:Name>
                  <com:PostalAddressBag>
                     <com:PostalAddress>
                        <com:PostalAddressText>東京都北区王子5-21-1  日本製紙株式会社内</com:PostalAddressText>
                     </com:PostalAddress>
                  </com:PostalAddressBag>
               </jpcom:Contact>
            </jppat:Inventor>
            <jppat:Inventor com:sequenceNumber="2">
               <jpcom:Contact>
                  <com:Name>
                     <com:EntityName>緑川  佳美</com:EntityName>
                  </com:Name>
                  <com:PostalAddressBag>
                     <com:PostalAddress>
                        <com:PostalAddressText>東京都北区王子5-21-1  日本製紙株式会社内</com:PostalAddressText>
                     </com:PostalAddress>
                  </com:PostalAddressBag>
               </jpcom:Contact>
            </jppat:Inventor>
            <jppat:Inventor com:sequenceNumber="3">
               <jpcom:Contact>
                  <com:Name>
                     <com:EntityName>平井  健二</com:EntityName>
                  </com:Name>
                  <com:PostalAddressBag>
                     <com:PostalAddress>
                        <com:PostalAddressText>東京都北区王子5-21-1  日本製紙株式会社内</com:PostalAddressText>
                     </com:PostalAddress>
                  </com:PostalAddressBag>
               </jpcom:Contact>
            </jppat:Inventor>
         </jppat:InventorBag>
      </jppat:RegisteredPatentPublicationPartyBag>
      <jppat:PriorityClaimBag>
         <jppat:PriorityClaim com:sequenceNumber="1">
            <com:IPOfficeCode>JP</com:IPOfficeCode>
            <com:ApplicationNumber>
               <com:ApplicationNumberText>2022055915</com:ApplicationNumberText>
            </com:ApplicationNumber>
            <pat:FilingDate>2022-03-30</pat:FilingDate>
            <jppat:ApplicationFilingCategory>Patent</jppat:ApplicationFilingCategory>
         </jppat:PriorityClaim>
      </jppat:PriorityClaimBag>
      <jppat:IPCClassification>
         <com:Edition/>
         <pat:MainClassification>B41M   5/40        20060101AFI20230925BHJP        </pat:MainClassification>
         <pat:FurtherClassification>B41M   5/323       20060101ALI20230925BHJP        </pat:FurtherClassification>
      </jppat:IPCClassification>
      <jppat:NationalClassification>
         <com:IPOfficeCode>JP</com:IPOfficeCode>
         <jppat:MainNationalClassification>
            <pat:PatentClassificationText>B41M5/40 220</pat:PatentClassificationText>
         </jppat:MainNationalClassification>
         <jppat:FurtherNationalClassification>
            <pat:PatentClassificationText>B41M5/323 220</pat:PatentClassificationText>
         </jppat:FurtherNationalClassification>
      </jppat:NationalClassification>
      <jppat:SearchField>
         <jppat:PatentClassificationBag>
            <jppat:IPCClassification>
               <com:Edition/>
            </jppat:IPCClassification>
         </jppat:PatentClassificationBag>
         <pat:SearchFieldText>B41M      5/28-5/48</pat:SearchFieldText>
         <pat:SearchFieldText>CAplus/REGISTRY(STN)</pat:SearchFieldText>
      </jppat:SearchField>
      <pat:ReferenceCitationBag>
         <pat:ReferenceCitation>
            <com:PatentCitation com:sequenceNumber="1">
               <com:PatentCitationText>特開平11-208115(JP,A)      </com:PatentCitationText>
            </com:PatentCitation>
         </pat:ReferenceCitation>
         <pat:ReferenceCitation>
            <com:PatentCitation com:sequenceNumber="2">
               <com:PatentCitationText>特開2011-008089(JP,A)      </com:PatentCitationText>
            </com:PatentCitation>
         </pat:ReferenceCitation>
         <pat:ReferenceCitation>
            <com:PatentCitation com:sequenceNumber="3">
               <com:PatentCitationText>特開平5-032044(JP,A)      </com:PatentCitationText>
            </com:PatentCitation>
         </pat:ReferenceCitation>
         <pat:ReferenceCitation>
            <com:PatentCitation com:sequenceNumber="4">
               <com:PatentCitationText>特開平9-265149(JP,A)      </com:PatentCitationText>
            </com:PatentCitation>
         </pat:ReferenceCitation>
         <pat:ReferenceCitation>
            <com:PatentCitation com:sequenceNumber="5">
               <com:PatentCitationText>特開2006-084607(JP,A)      </com:PatentCitationText>
            </com:PatentCitation>
         </pat:ReferenceCitation>
         <pat:ReferenceCitation>
            <com:PatentCitation com:sequenceNumber="6">
               <com:PatentCitationText>特開2009-255551(JP,A)      </com:PatentCitationText>
            </com:PatentCitation>
         </pat:ReferenceCitation>
      </pat:ReferenceCitationBag>
      <jppat:ClaimTotalQuantitySet>
         <pat:ClaimTotalQuantity>4</pat:ClaimTotalQuantity>
         <jppat:AdoptedLawCategory>Claim</jppat:AdoptedLawCategory>
      </jppat:ClaimTotalQuantitySet>
      <jppat:InternationalFilingData>
         <jppat:ApplicationIdentification>
            <com:ApplicationNumber>
               <com:ApplicationNumberText>JP2023012159</com:ApplicationNumberText>
            </com:ApplicationNumber>
            <pat:FilingDate>2023-03-27</pat:FilingDate>
         </jppat:ApplicationIdentification>
      </jppat:InternationalFilingData>
      <com:ExaminationRequestDate>2023-07-20</com:ExaminationRequestDate>
      <jppat:AcceleratedApplication>Accelerated examination</jppat:AcceleratedApplication>
      <pat:ExaminerBag>
         <pat:PrimaryExaminer>
            <com:Name>
               <com:PersonName>
                  <com:PersonFullName>高草木  綾音</com:PersonFullName>
               </com:PersonName>
            </com:Name>
         </pat:PrimaryExaminer>
      </pat:ExaminerBag>
   </jppat:RegisteredPatentPublicationBibliographicData>
   <jppat:Description>
      <pat:TechnicalField>
         <com:P com:pNumber="0001">
  この発明は、背面に水蒸気バリア性を有する感熱記録体に関する。</com:P>
      </pat:TechnicalField>
      <pat:BackgroundArt>
         <com:P com:pNumber="0002">
  一般に、感熱記録体は、無色ないし淡色の電子供与性ロイコ染料(以下、「ロイコ染料」ともいう。)と電子受容性顕色剤(以下、「顕色剤」ともいう。)とを含有する塗工液を、紙、合成紙、フィルム、プラスチック等の支持体に塗工して感熱記録層を設けたものであり、サーマルヘッド、ホットスタンプ、熱ペン、レーザー光等の加熱による瞬時の化学反応により発色し、記録画像が得られる。感熱記録体は、ファクシミリ、コンピューターの端末プリンター、自動券売機、計測用レコーダー、スーパーマーケットやコンビニなどのレシート等の記録媒体として広範囲に使用されている。<com:Br/>
  良好な耐水性を得るために、ポリビニルアルコール等の接着剤を含有するバックコート層を設けた感熱記録材料が知られている(特許文献1等)。また、エチレン共重合ポリビニルアルコールやエチレン・アクリル共重合体を含む紙基材が水蒸気バリア性を有することが知られている(特許文献2~4等)。</com:P>
      </pat:BackgroundArt>
      <com:CitationBag>
         <com:PatentCitationBag>
            <com:P com:pNumber="0003">
               <com:PatentCitation com:sequenceNumber="1">
                  <com:PatentCitationText>特開2003-175671</com:PatentCitationText>
               </com:PatentCitation>
               <com:PatentCitation com:sequenceNumber="2">
                  <com:PatentCitationText>特開2013-169988</com:PatentCitationText>
               </com:PatentCitation>
               <com:PatentCitation com:sequenceNumber="3">
                  <com:PatentCitationText>特開2014-173201</com:PatentCitationText>
               </com:PatentCitation>
               <com:PatentCitation com:sequenceNumber="4">
                  <com:PatentCitationText>特開2020-190063</com:PatentCitationText>
               </com:PatentCitation>
            </com:P>
         </com:PatentCitationBag>
      </com:CitationBag>
      <pat:InventionSummary>
         <pat:TechnicalProblem>
            <com:P com:pNumber="0004">
・・・・・

ざっくり話すと、2023年10月2日に「日本製紙株式会社」が「背面に水蒸気バリア性を有する感熱記録体に関する特許」を出願したようです。難しくて内容はよくわかりませんが。

では、次回の記事でこの内容がちゃんと確認できるかをデータベースの中を見ていきます。

今日は疲れたのでこれで終わりにします。

Discussion