精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

線上RAG應用pdf文檔頻繁更新,老板下了死命令要節省預算,不能重復做embedding,我這么做..... 原創

發布于 2024-12-3 08:51
瀏覽
0收藏

我們最近在一個項目中遇到了一個問題。項目的場景是這樣的:用戶將他們的PDF文檔存儲在磁盤的某個特定目錄中,然后有一個定時任務來掃描此目錄并從中的PDF文檔構建知識庫。

一開始,我們采用"增量更新"策略。在掃描目錄中的文檔時,我們會對每個文檔進行哈希運算以生成其指紋,并檢查該指紋是否已存在于數據庫中。如果指紋不存在,就表示這是一個新文件,我們會對新文件的document做embedding,然后將其加入到知識庫中。

然而,這種方法存在一個問題。如果同一文件進行了增量添加,例如我們已經將A.pdf文件加入到了知識庫,但后來這個文件添加了新的內容。當我們重新計算其指紋并在數據庫中查找時,由于指紋不存在,我們會將這個更新過的文件作為新文件處理,并重新做embedding加入到知識庫。這樣一來,對于未更新的部分,知識庫會有兩份相同的數據記錄,第二份相同的記錄可能會"占據"原本應該被召回的數據記錄的位置,從而降低問答效果。

那么應該怎么解決這個問題呢?對于增量更新,做hash指紋這一點毋庸置疑,但是hash的對象不能是文件了,而應該聚焦于真實存到知識庫的數據: document.

在這里,我們將查看使用LangChain index API的基本索引工作流。

index API允許您將來自任何源的文檔加載到矢量存儲中并保持同步。具體來說,它有助于:

  • 避免將重復的內容寫入vector存儲
  • 避免重寫未更改的內容
  • 避免在未更改的內容上重新計算embedding

所有這些都可以節省你的時間和金錢,并改善你的矢量搜索結果。

如何工作

LangChain索引使用記錄管理器(RecordManager)來跟蹤寫入矢量存儲的文檔。

當索引內容時,為每個文檔計算哈希值,并將以下信息存儲在記錄管理器中:

  • 文檔hash(頁面內容和元數據的散列)
  • 寫時間
  • 源id——每個文檔應該在其元數據中包含信息,以便我們確定該文檔的最終來源

刪除模式

將文檔索引到矢量存儲時,可能會刪除矢量存儲中的一些現有文檔。在某些情況下,您可能希望刪除與正在索引的新文檔來自相同來源的所有現有文檔。在其他情況下,您可能希望批量刪除所有現有文檔。索引API刪除模式可以讓你選擇你想要的行為:

Cleanup Mode

De-Duplicates Content

Parallelizable

Cleans Up Deleted Source Docs

Cleans Up Mutations of Source Docs and/or Derived Docs

Clean Up Timing

None

?

?

?

?

-

Incremental

?

?

?

?

Continuously

Full

?

?

?

?

At end of indexing

快速開始

首先,需要明確的是,無論使用何種清理模式,index函數都會自動去重。也就是說,調用index([doc1, doc1, doc2])的效果等同于調用index([doc1, doc2])。然而,在我們的實際應用場景中,情況并不完全如此。

可能在第一次運行時,我們對[doc1, doc2]進行了索引操作,而在下次定時任務執行時,我們又對[doc1, doc3]進行了索引。換言之,我們從源文檔中刪除了一部分內容,并添加了一些新的內容。這才是我們真正面臨的場景:我們希望保持doc1不變,新增doc3,并能夠自動刪除doc2。這種需求可以通過Incremental增量模式得到滿足。

話不多說,我們來看看三種模式的使用效果吧。

None

None模式的功能可以理解為去重和添加,而不包括刪除。例如,如果你首次調用index([doc1, doc2]),然后再次調用index([doc1, doc3]),那么在向量庫中的數據就會是[doc1, doc2, doc3]。需要注意的是,這種模式下,舊版本的doc2并不會被刪除。

from langchain.embeddings import OpenAIEmbeddings
from langchain.schema import Document
from langchain.vectorstores.elasticsearch import ElasticsearchStore
from langchain.indexes import SQLRecordManager, index


collection_name = "test_index"

embedding = OpenAIEmbeddings()

vectorstore = ElasticsearchStore(
    es_url="http://localhost:9200",
    index_name="test_index",
    embedding=embedding)

namespace = f"elasticsearch/{collection_name}"
record_manager = SQLRecordManager(
    namespace, db_url="sqlite:///record_manager_cache.sql"
)
# record_manager.create_schema()

doc1 = Document(page_content="kitty", metadata={"source": "kitty.txt"})
doc2 = Document(page_content="doggy", metadata={"source": "doggy.txt"})
doc3 = Document(page_content="doggy1", metadata={"source": "doggy.txt"})


def _clear():
    """Hacky helper method to clear content. See the `full` mode section to to understand why it works."""
    index(
        [],
        record_manager,
        vectorstore,
        cleanup="full",
        source_id_key="source")

_clear()

res = index(
    [doc1, doc1, doc2],
    record_manager,
    vectorstore,
    cleanup=None,
    source_id_key="source",
)
print(res)

得到的結果:

{'num_added': 2, 'num_updated': 0, 'num_skipped': 0, 'num_deleted': 0}

我們發現做了去重并且幫我們增加了兩條數據。

然后我們再執行index操作:

res = index(
    [doc1, doc3],
    record_manager,
    vectorstore,
    cleanup=None,
    source_id_key="source",
)
print(res)

執行結果發現添加了doc3, 跳過了doc1, doc2 還在數據庫記錄里:

{'num_added': 1, 'num_updated': 0, 'num_skipped': 1, 'num_deleted': 0}

線上RAG應用pdf文檔頻繁更新,老板下了死命令要節省預算,不能重復做embedding,我這么做.....-AI.x社區


full

full 含義是用戶應該將所有需要進行索引的全部內容傳遞給index函數,任何沒有傳遞到索引函數并且存在于vectorstore中的文檔將被刪除! 此行為對于處理源文檔的刪除非常有用。我們還是使用上面的代碼,這次只是把模式換成 full. 首先,我們需要重置并清空數據,這可以通過調用??_clear()??函數實現。

res = index(
    [doc1, doc1, doc2],
    record_manager,
    vectorstore,
    cleanup="full",
    source_id_key="source",
)
print(res)

我們發現添加了2個文檔:

{'num_added': 2, 'num_updated': 0, 'num_skipped': 0, 'num_deleted': 0}

接著我們執行:

res = index(
    [doc1, doc3],
    record_manager,
    vectorstore,
    cleanup="full",
    source_id_key="source",
)
print(res)

我們發現添加了一個文檔doc3,跳過了一個文檔doc1,刪除了一個文檔doc2:

線上RAG應用pdf文檔頻繁更新,老板下了死命令要節省預算,不能重復做embedding,我這么做.....-AI.x社區

{'num_added': 1, 'num_updated': 0, 'num_skipped': 1, 'num_deleted': 1}

incremental

"增量模式"是我們最常用的一種。顧名思義,這種模式主要進行增量操作,即添加最新記錄并刪除舊版記錄。在這種模式下,如果我們傳入一個空的文檔數組,即index([]),將不會發生任何操作。然而,如果我們在"全量模式"下傳入同樣的空數組,系統則會清除所有數據。

首先,執行以下操作:

_clear()

res = index(
    [doc1, doc1, doc2],
    record_manager,
    vectorstore,
    cleanup="incremental",
    source_id_key="source",
)
print(res)

res = index(
    [doc1, doc3],
    record_manager,
    vectorstore,
    cleanup="incremental",
    source_id_key="source",
)
print(res)

得到的結果如下:

{'num_added': 2, 'num_updated': 0, 'num_skipped': 0, 'num_deleted': 0}
{'num_added': 1, 'num_updated': 0, 'num_skipped': 1, 'num_deleted': 1}

可以看出,第一次操作添加了兩個文檔。在第二次操作中,系統跳過了doc1,并刪除了之前屬于"doggy.txt"的doc2,因為現在我們只傳入了doc3。因此,增量模式會將這個舊版本(doc2)刪除。

然后執行以下操作:

res = index(
    [doc1],
    record_manager,
    vectorstore,
    cleanup="incremental",
    source_id_key="source",
)
print(res)

這次對于"doggy.txt"沒有任何新的文檔被傳入,所以數據沒有任何改動,結果如下:

{'num_added': 0, 'num_updated': 0, 'num_skipped': 1, 'num_deleted': 0}

但是,如果我們只傳入doc2,則會發現系統增加了doc2,并刪除了同一源文件("doggy.txt")的doc3。結果如下:

{'num_added': 1, 'num_updated': 0, 'num_skipped':

源碼

def index(
    docs_source: Union[BaseLoader, Iterable[Document]],
    record_manager: RecordManager,
    vector_store: VectorStore,
    *,
    batch_size: int = 100,
    cleanup: Literal["incremental", "full", None] = None,
    source_id_key: Union[str, Callable[[Document], str], None] = None,
    cleanup_batch_size: int = 1_000,
) -> IndexingResult:
    ...

    if isinstance(docs_source, BaseLoader):
        try:
            doc_iterator = docs_source.lazy_load()
        except NotImplementedError:
            doc_iterator = iter(docs_source.load())
    else:
        doc_iterator = iter(docs_source)

    source_id_assigner = _get_source_id_assigner(source_id_key)

    # Mark when the update started.
    index_start_dt = record_manager.get_time()
    num_added = 0
    num_skipped = 0
    num_updated = 0
    num_deleted = 0
    
    
    for doc_batch in _batch(batch_size, doc_iterator):
        hashed_docs = list(
            _deduplicate_in_order(
                [_HashedDocument.from_document(doc) for doc in doc_batch]
            )
        )

        source_ids: Sequence[Optional[str]] = [
            source_id_assigner(doc) for doc in hashed_docs
        ]

        ....

        exists_batch = record_manager.exists([doc.uid for doc in hashed_docs])

        # Filter out documents that already exist in the record store.
        uids = []
        docs_to_index = []
        
        # 判斷哪些是要更新,哪些是要添加的
        for hashed_doc, doc_exists in zip(hashed_docs, exists_batch):
            if doc_exists:
                # Must be updated to refresh timestamp.
                record_manager.update([hashed_doc.uid], time_at_least=index_start_dt)
                num_skipped += 1
                continue
            uids.append(hashed_doc.uid)
            docs_to_index.append(hashed_doc.to_document())

      
        # 知識入向量庫
        if docs_to_index:
            vector_store.add_documents(docs_to_index, ids=uids)
            num_added += len(docs_to_index)

        # 更新數據庫記錄時間
        record_manager.update(
            [doc.uid for doc in hashed_docs],
            group_ids=source_ids,
            time_at_least=index_start_dt,
        )

        # 根據時間和source_ids 清理舊版本數據
        if cleanup == "incremental":
            ...

            uids_to_delete = record_manager.list_keys(
                group_ids=_source_ids, before=index_start_dt
            )
            if uids_to_delete:
                vector_store.delete(uids_to_delete)
                record_manager.delete_keys(uids_to_delete)
                num_deleted += len(uids_to_delete)

    if cleanup == "full":
        while uids_to_delete := record_manager.list_keys(
            before=index_start_dt, limit=cleanup_batch_size
        ):
            # First delete from record store.
            vector_store.delete(uids_to_delete)
            # Then delete from record manager.
            record_manager.delete_keys(uids_to_delete)
            num_deleted += len(uids_to_delete)

    return {
        "num_added": num_added,
        "num_updated": num_updated,
        "num_skipped": num_skipped,
        "num_deleted": num_deleted,
    }

通過上述代碼,我們可以了解到一個常見的優化策略:對于涉及大量數據操作的數據庫和向量庫,我們通常使用批處理(batch)方式進行操作。上面代碼的流程圖如下:

線上RAG應用pdf文檔頻繁更新,老板下了死命令要節省預算,不能重復做embedding,我這么做.....-AI.x社區

本文轉載自公眾號AI 博物院 作者:longyunfeigu

原文鏈接:??https://mp.weixin.qq.com/s/BFgtECvWMnUSDxH-JswbyQ??

?著作權歸作者所有,如需轉載,請注明出處,否則將追究法律責任
收藏
回復
舉報
回復
相關推薦
99久久婷婷国产综合精品| 国产一区二区在线视频你懂的| 日本一区二区成人在线| 国产精品羞羞答答| 久久久久久久国产精品毛片| 美女av一区| 精品视频一区三区九区| 老司机激情视频| 国产在线小视频| 国产精品资源网站| 日韩免费黄色av| 国产女人被狂躁到高潮小说| 国产精品免费大片| 日韩欧美123| 青青在线免费观看视频| 日韩123区| 国产欧美日韩麻豆91| 97视频热人人精品| 成人黄色片在线观看| 精品成人免费| 久久久精品免费视频| 国产伦精品一区二区三区妓女| 未满十八勿进黄网站一区不卡| 精品久久中文字幕| 无码人妻aⅴ一区二区三区日本| 人成免费电影一二三区在线观看| 国产在线播放一区三区四| 91高潮在线观看| 青青草在线观看视频| 欧美日韩在线网站| 日韩成人在线视频观看| 日本女人黄色片| 久久av影院| 色婷婷激情久久| 天天夜碰日日摸日日澡性色av| 亚洲区欧洲区| 亚洲婷婷综合色高清在线| 欧美亚洲另类久久综合| 日本精品999| 国产精品2024| 91久久中文字幕| 在线免费观看中文字幕| 三级欧美在线一区| 国产91ⅴ在线精品免费观看| 国产真实乱人偷精品视频| 欧美黄在线观看| 久久99久国产精品黄毛片入口| 天天做夜夜爱爱爱| 欧美激情777| 深夜福利一区二区| 在线观看日本黄色| 成人动漫免费在线观看| 中文字幕亚洲无线码a| 国产成人福利在线| 免费国产自久久久久三四区久久| 亚洲国产欧美日韩精品| 东京热av一区| 欧美三级电影在线| 五月婷婷激情在线| 久久久久久穴| 日本精品视频在线播放| 69精品久久久| 国产亚洲精品bv在线观看| 91精品国产高清自在线| 日韩高清精品免费观看| 亚洲精品裸体| 2018中文字幕一区二区三区| 韩国av中文字幕| 羞羞答答国产精品www一本| 欧美亚洲激情视频| 无码人妻丰满熟妇区bbbbxxxx | 久久激情视频免费观看| 三级黄色录像视频| 欧美日韩精品免费观看视频完整| 欧美黄网免费在线观看| 日韩成人免费在线视频| 久久精品日产第一区二区| 国产精品精品久久久| 国产毛片毛片毛片毛片毛片| 高清在线观看日韩| 精品成人一区二区三区免费视频| 日韩乱码一区二区| 中文在线资源| 欧美日韩一区二区在线播放| 色综合av综合无码综合网站| 午夜无码国产理论在线| 欧美日韩一区二区三区在线| 亚洲制服在线观看| 奇米影视777在线欧美电影观看| 亚洲欧美成人网| 日韩免费av一区| 伊人久久成人| 国产精品igao视频| 国产99久一区二区三区a片| 9久草视频在线视频精品| 神马一区二区影院| av免费网站在线观看| 亚洲va在线va天堂| 亚欧美在线观看| 成人动态视频| 最好看的2019年中文视频| 九九热精品免费视频| 美女诱惑黄网站一区| 国产专区精品视频| 天堂а√在线8种子蜜桃视频| 国产精品热久久久久夜色精品三区| 欧洲精品视频在线| 免费高清视频在线一区| 精品国产亚洲一区二区三区在线观看| 久久九九亚洲综合| 中文字幕五月天| 香蕉久久a毛片| av成人免费观看| 触手亚洲一区二区三区| 香蕉加勒比综合久久| 亚洲精品20p| 一区三区在线欧| 免费一区二区视频| 国产日本欧美一区二区三区| 偷拍精品一区二区三区| 中文字幕一区不卡| 99久久激情视频| 国内露脸中年夫妇交换精品| 色妞久久福利网| 亚洲不卡视频在线观看| 成人夜色视频网站在线观看| 国产精品亚洲天堂| 成人a在线观看高清电影| 亚洲精品久久久久久久久久久久久 | 欧洲一区二区三区| 欧洲另类一二三四区| 欧美 变态 另类 人妖| 国产综合欧美| 亚洲影影院av| 日本在线视频站| 欧美系列亚洲系列| 日本高清www| 亚洲视频二区| 国产精品日本一区二区| 日本大胆在线观看| 欧美一级精品大片| 成年人av电影| 国产精品一区二区久激情瑜伽| 在线一区日本视频| www.91精品| 日韩一区视频在线| 国产又粗又大又爽| 成人免费在线播放视频| 国产女同无遮挡互慰高潮91| 国产精品99久久| 亚洲va欧美va在线观看| av片在线观看永久免费| 日韩欧美国产麻豆| 久久免费精彩视频| jlzzjlzz亚洲日本少妇| 免费看又黄又无码的网站| 美女福利一区| 日韩av电影院| 日本中文字幕在线观看| 欧美色男人天堂| 日韩精品一区二区三区在线视频| 久久精品国产亚洲高清剧情介绍| 在线观看欧美亚洲| 成人av在线播放| 欧美激情亚洲视频| 亚洲三级中文字幕| 欧美色老头old∨ideo| 国产麻豆视频在线观看| 国产一区二区三区日韩| 国产欧美日韩小视频| 任你躁在线精品免费| 国产成人精品最新| 自拍视频在线| 精品国产网站在线观看| 成人a v视频| 国产精品黄色在线观看| 日本少妇一级片| 麻豆精品网站| 自拍视频一区二区三区| 果冻天美麻豆一区二区国产| 国产成人精品国内自产拍免费看| 久久bbxx| 精品五月天久久| 亚洲一区二区三区高清视频| 亚洲午夜精品网| 久久精品—区二区三区舞蹈| 国产精品一区二区久久不卡| 日本一本二本在线观看| 日韩欧美视频专区| 国产精品一码二码三码在线| www.一区| 欧美一级片在线播放| 日韩免费啪啪| 日韩精品免费电影| 国产女无套免费视频| 高潮白浆女日韩av免费看| 欧美风情第一页| 99久久er热在这里只有精品66| www.com黄色片| 夜久久久久久| 黄黄视频在线观看| 色综合久久一区二区三区| 狠狠色综合一区二区| 国产精品美女久久久久| 奇门遁甲1982国语版免费观看高清 | 日韩一区二区三区四区五区| 欧美精品九九久久| 麻豆传媒在线观看| 亚洲人成77777在线观看网| www.天堂av.com| 欧美三级资源在线| 四虎成人永久免费视频| 亚洲精品国久久99热| 日韩影视一区二区三区| 91一区二区三区在线观看| 永久看看免费大片| 男女激情视频一区| 欧美成人免费高清视频| 国产综合自拍| 狠狠精品干练久久久无码中文字幕 | 亚洲成av人片一区二区三区| 日本精品久久久久中文| 91视频在线看| xfplay5566色资源网站| 国产激情视频一区二区三区欧美| 999精品视频在线| 久久中文精品| 欧美成人xxxxx| 亚洲黄色精品| 欧美中文字幕在线观看视频| 我不卡神马影院| 亚洲一区二区三区免费观看| 欧美日韩在线二区| 深夜福利成人| 日韩精品欧美| 色综合视频二区偷拍在线| 亚洲香蕉视频| 免费电影一区| 亚洲人成网站77777在线观看| 国产视频99| 风间由美一区二区av101| www.成人av.com| 国产一区二区av在线| 91久久精品国产91性色| 9999精品视频| 69174成人网| 动漫av一区| 国内精品国语自产拍在线观看| 久久九九热re6这里有精品| 久久国产日韩欧美| 亚洲性视频大全| 日韩精品一区二区三区外面 | 久久人人爽人人爽人人片av免费| 色综合久久久久| 区一区二在线观看| 欧美性感一区二区三区| 一级视频在线播放| 日韩久久久精品| 五月婷婷六月丁香| 亚洲人成网站777色婷婷| 成人精品一区二区三区免费| 日韩在线观看免费网站 | 欧美一区三区| 偷拍盗摄高潮叫床对白清晰| 国产一区观看| 久久久免费视频网站| 日本特黄久久久高潮| 日本在线播放一区二区| 福利一区福利二区| 美女脱光内衣内裤| 中文字幕一区二区三区在线观看| 国产波霸爆乳一区二区| 欧美日韩免费一区| 中文字幕777| 欧美一区二区三区思思人| 欧洲av在线播放| 影音先锋欧美精品| 新版中文在线官网| 日产精品99久久久久久| 成人51免费| 久久综合伊人77777麻豆| 色琪琪久久se色| 国产不卡一区二区视频| 日韩精品五月天| 国产精品19p| www日韩大片| 澳门黄色一级片| 色婷婷av久久久久久久| 国产一区二区麻豆| 日韩精品高清在线| 精品176二区| 欧美怡春院一区二区三区| 国产精品xnxxcom| 久中文字幕一区| 欧美精品综合| 中文字幕第80页| 不卡的av网站| 欧美大片xxxx| 日本久久电影网| 欧美自拍第一页| 久久国产精品视频| 欧美极度另类| 国产美女99p| 91精品国产乱码久久久久久| 免费午夜视频在线观看| 国产不卡高清在线观看视频| 国产视频不卡在线| 欧美视频中文在线看| www.超碰在线.com| 日韩在线观看免费网站 | 亚洲乱码视频| 一级做a爱视频| 日本一区二区三区高清不卡| 国产精品成人久久| 欧美一卡2卡三卡4卡5免费| av网站在线播放| 日本亚洲欧洲色α| 欧美一区自拍| 久久久久久久9| 国产美女在线精品| 免费黄色激情视频| 91福利国产成人精品照片| 亚洲色图欧美视频| 欧美激情按摩在线| 91精品啪在线观看国产爱臀| 伊人av成人| 老司机免费视频一区二区| 色综合99久久久无码国产精品| 精品国产91久久久| 日韩在线观看视频网站| 欧美激情久久久久久| 视频在线观看免费影院欧美meiju| 亚洲欧美在线网| 蜜臀av性久久久久蜜臀av麻豆| www.中文字幕av| 欧美性生交xxxxx久久久| 亚洲欧洲国产综合| 69视频在线免费观看| 欧美一区自拍| 99福利在线观看| 国产亚洲一区二区三区在线观看| 日韩精品一区二区亚洲av| 亚洲欧美日韩在线高清直播| 欧美极品免费| 手机成人在线| 国内精品伊人久久久久av一坑| 国产中文av在线| 制服丝袜中文字幕一区| av免费在线观| 国产精品视频免费一区| 国产日韩欧美三区| 免费看污片的网站| 欧美日韩成人综合| 成人在线网址| 国产精品区一区| 久久久久久久高潮| 91av手机在线| 日韩一区二区不卡| 僵尸再翻生在线观看免费国语| 久久精品午夜一区二区福利| 美女精品一区| 久久久久人妻一区精品色| 日韩免费看网站| 中文字幕成在线观看| 日韩欧美视频第二区| 黄色日韩网站视频| 久草视频在线资源站| 日韩高清av在线| 精品亚洲a∨| www.日本在线视频| 久久久精品免费免费| 亚洲一级av毛片| 国语自产在线不卡| 精品一级毛片| 午夜性福利视频| 色成年激情久久综合| 99自拍视频在线观看| 久久日韩精品| 精品一区二区三区蜜桃| 日产电影一区二区三区| 在线电影av不卡网址| 日韩一区二区三区高清在线观看| 日本在线xxx| 亚洲欧洲韩国日本视频| 免费av一级片| 国产精品视频一区国模私拍 | 国语对白做受xxxxx在线中国| 国产精品免费视频一区| 好男人在线视频www| 国产精品久久综合av爱欲tv| 国内精品久久久久久久影视蜜臀| 日本xxxxxxxxx18| 日韩欧美电影一区| 岛国精品在线| 精品欧美一区免费观看α√| 国产精品传媒入口麻豆| 亚州av在线播放| 91传媒免费看| 奇米影视一区二区三区| 国产欧美日韩另类|