精品欧美一区二区三区在线观看 _久久久久国色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??

?著作權歸作者所有,如需轉載,請注明出處,否則將追究法律責任
收藏
回復
舉報
回復
相關推薦
色呦呦中文字幕| 中文字幕一区二区三区人妻在线视频 | 欧美一区深夜视频| 国产亚洲精品熟女国产成人| 中文字幕av一区二区三区佐山爱| 中文字幕制服丝袜一区二区三区| 99国产在线| 久久久久久久久久成人| 中出一区二区| 亚洲网站免费| 国产欧美日韩不卡免费| 91成人免费看| 正在播放亚洲精品| 伊人成年综合电影网| 欧美美女黄色| 中文字幕一区二区视频| 国产日韩一区欧美| 国产女优在线播放| 在线国产欧美| 欧美成人合集magnet| 国产手机在线观看| 岛国av一区| 这里只有精品视频在线观看| 一本久道中文无码字幕av| 日本午夜一区二区| 欧美日韩一区三区| 精品人妻少妇一区二区| 四虎久久免费| 久久亚洲二区三区| 不卡视频一区二区三区| 亚洲一区在线观| 久久一区中文字幕| 97av在线视频| 久久中文字幕无码| 一区二区三区四区电影| 综合国产在线观看| 午夜理伦三级做爰电影| 欧美性生活一级片| 日韩精品综合一本久道在线视频| 亚洲欧美日韩中文在线制服| 久久撸在线视频| 久久丫精品忘忧草西安产品| 国产日韩在线观看一区| 麻豆精品国产传媒mv男同| 日本精品久久久久久久| 性无码专区无码| 国产一区二区三区久久| 午夜精品www| 国产精品6666| 亚洲日韩视频| 国模叶桐国产精品一区| 日本三级理论片| 亚洲韩日在线| 欧美一级视频在线观看| 国产精品777777| 美女久久网站| 国产精品成人观看视频国产奇米| 夜夜爽妓女8888视频免费观看| 91精品国产乱码久久久久久| 欧美xxxx做受欧美.88| 永久免费看mv网站入口| 午夜激情久久| 欧美激情精品久久久久久变态 | 精品日韩一区| 在线观看久久久久久| 国产传媒在线看| 91成人超碰| 欧美激情亚洲自拍| 久久久久免费看黄a片app| 97中文字幕在线观看| 不卡亚洲精品| 制服丝袜亚洲播放| av电影中文字幕| 色婷婷狠狠五月综合天色拍 | 日本视频在线免费| 亚洲国产精品久久久天堂| 欧美丰满少妇xxxx| 影音先锋在线国产| 麻豆传媒一区二区三区| av成人动漫在线观看| 成人黄色片网站| 性一交一乱一乱一视频| 97久久人人超碰| 亚洲成人网上| 色综合999| 日韩欧美中文第一页| 国产一伦一伦一伦| 成人91在线观看| 亚洲人成网站在线播| 亚洲一品av免费观看| 91久久精品国产| 国产成人精品一区二区无码呦| 成人午夜激情影院| 欧美人与性禽动交精品| 日本在线看片免费人成视1000| 一区二区三区影院| 国产精品-区区久久久狼| 欧美成人三级| 亚洲精品国产suv| 老司机深夜福利网站| 亚洲最黄网站| 成人亚洲综合色就1024| 神马电影在线观看| 亚洲免费高清视频在线| 黄色片久久久久| 日韩黄色av| 国产一级揄自揄精品视频| 久久久久成人网站| 蜜臀av一区二区在线免费观看| 国产在线资源一区| 黄网址在线观看| 日本韩国精品在线| 亚洲精品久久一区二区三区777 | 日韩经典中文字幕| 裸体武打性艳史| 日韩二区在线观看| 久久精品ww人人做人人爽| 超碰公开在线| 欧美日韩在线一区二区| 中文文字幕文字幕高清| 国产精品视频一区二区高潮| 在线观看一区二区三区三州| 欧美黑人xx片| 欧美日韩激情一区二区| 在线免费观看日韩av| 黄色亚洲在线| 亚洲综合在线小说| 日本中文字幕在线2020| 在线亚洲免费视频| 蜜桃精品成人影片| 亚洲激情偷拍| 国产精品亚洲不卡a| 最爽无遮挡行房视频在线| 欧美日韩美女一区二区| 69视频在线观看免费| 午夜亚洲影视| 欧美少妇一区| 亚洲欧洲美洲av| 日韩精品极品在线观看播放免费视频| 久久国产精品波多野结衣| 国产综合久久久久久鬼色 | 国产91成人video| 天堂在线中文网| 五月婷婷久久综合| 欧美肉大捧一进一出免费视频 | av动漫免费看| 精品久久不卡| 国产精品久久久久一区二区| 福利视频在线看| 欧美日精品一区视频| 欧美成人久久久免费播放| 日本vs亚洲vs韩国一区三区二区 | 永久91嫩草亚洲精品人人| 91精品久久久久久久久青青| 麻豆视频在线| 日韩视频免费观看高清完整版| 久久久久99精品成人片试看| 国产91在线看| 久久久久久久中文| 伊人久久大香线蕉av不卡| 日韩av电影国产| 91在线看片| 5858s免费视频成人| 青青草手机视频在线观看| 国产91精品精华液一区二区三区 | 日本丰满大乳奶| 五月亚洲婷婷| 69影院欧美专区视频| 丝袜视频国产在线播放| 欧美日韩色综合| 国产少妇在线观看| 成人黄色777网| 激情五月开心婷婷| 亚州av乱码久久精品蜜桃| 成人动漫视频在线观看免费| 涩涩视频在线播放| 日韩在线视频播放| 亚洲经典一区二区三区| 色婷婷久久99综合精品jk白丝| 四虎影视一区二区| 成人小视频在线观看| 50路60路老熟妇啪啪| 久久久久久久久久久妇女| 国产精品一区在线观看| 欧美日韩精品一区二区三区视频| 欧美精品制服第一页| 日韩av地址| 日韩视频在线你懂得| 国产污视频网站| 一区二区三区在线不卡| 中文字幕第4页| 风流少妇一区二区| 国产视频一区二区视频| 欧美日韩一区二区三区四区在线观看| 欧美第一黄网| 中文在线免费一区三区| 国产成人亚洲综合91精品| 少女频道在线观看免费播放电视剧| 亚洲免费一在线| 国产高中女学生第一次| 欧美亚洲国产怡红院影院| 国产在线视频你懂的| 国产精品美女久久久久aⅴ | 国产精品高潮久久久久无| 日本三级日本三级日本三级极| 蜜臀av性久久久久蜜臀aⅴ四虎 | 不卡一二三区| 久久久久久久成人| 欧美13一16娇小xxxx| 精品亚洲国产视频| www.亚洲黄色| 欧美电影一区二区| 亚洲 欧美 中文字幕| 亚洲电影第三页| 国产尤物在线播放| 欧美激情中文不卡| 在线观看日韩精品视频| 高清国产一区二区| 91精产国品一二三产区别沈先生| 日韩二区三区在线观看| 噜噜噜久久亚洲精品国产品麻豆| 欧美精品一线| 午夜探花在线观看| 日韩免费在线| 手机看片福利永久国产日韩| 亚州av一区| 久久久久一区二区| 久久久久观看| 国产福利不卡| 99精品中文字幕在线不卡| 亚洲一区二区久久久久久久| 亚洲国产91视频| 国产精品视频一| 欧美大陆国产| 成人精品一区二区三区电影黑人| 成人国产精品入口免费视频| 国产a∨精品一区二区三区不卡| 亚洲精品88| 日本精品视频一区二区三区| 久久久久亚洲AV成人网人人小说| 狠狠网亚洲精品| 91激情视频在线| 日本亚洲免费观看| 九热视频在线观看| 日韩电影在线一区二区三区| 无码人妻丰满熟妇区毛片| 久久亚洲影院| 手机看片福利盒子久久| 日韩和欧美的一区| 九热视频在线观看| 久久成人羞羞网站| 日韩欧美理论片| 国产成人在线色| 中文字幕天堂av| 99精品欧美一区二区蜜桃免费| 中国极品少妇videossexhd| 95精品视频在线| 少妇毛片一区二区三区| 久久精品亚洲精品国产欧美 | 久久一区二区三区四区| jizz欧美性20| 中文字幕高清不卡| 亚洲色偷偷综合亚洲av伊人| 亚洲香蕉伊在人在线观| 国产www在线| 欧美午夜精品久久久久久孕妇| 一级特黄录像免费看| 日韩欧美激情在线| 午夜一区在线观看| 亚洲一级片在线看| jizzjizz亚洲| 91成人在线播放| 日本成人福利| 高清不卡日本v二区在线| 偷拍亚洲精品| www.国产成人| 国产成人在线网站| 日本一区二区免费视频| 国产99久久久国产精品潘金| 99热超碰在线| 久久精品一区二区三区不卡牛牛| 在线免费观看日韩视频| 亚洲精品国产品国语在线app| 亚洲天堂黄色片| 亚洲大片一区二区三区| 国语对白永久免费| 午夜成人免费视频| 亚洲一区二区三区三州| 国产成人免费在线视频| 无码av免费精品一区二区三区| 26uuu国产日韩综合| 久久av免费观看| 天堂av中文在线| 97香蕉久久超级碰碰高清版| 欧美极品影院| 5566中文字幕一区二区| 一本色道久久综合亚洲精品酒店| 手机成人av在线| 久久aⅴ乱码一区二区三区| 亚洲一二三不卡| 久久久久久99久久久精品网站| 色欲人妻综合网| 国产精品国产三级国产aⅴ| 日韩精品一区二区三区视频| 手机亚洲第一页| 欧美成人三级视频网站| 黑人巨大亚洲一区二区久| 91人成网站www| 国产精选一区| 国产精品久久..4399| 九色|91porny| 国产一二三四五区| 好吊色在线观看| 亚洲国产精品成人va在线观看| 成人在线免费电影| 久久久久中文字幕2018| 日本免费一区二区三区等视频| 国产精品制服诱惑| 欧美~级网站不卡| 污片在线免费看| 91在线播放网址| 国产一级二级毛片| 国产精品私人影院| 日本五十肥熟交尾| 国产精品午夜在线观看| 日韩av黄色片| 在线播放一区二区三区| 国产小视频在线播放| 18性欧美xxxⅹ性满足| 成人三级毛片| 成人在线免费观看视频网站| 久久99精品国产91久久来源| 9.1片黄在线观看| 欧美日韩亚洲一区三区| 男女男精品视频站| 国产欧美日韩在线| 国产成人无码专区| 亚洲视频自拍偷拍| 亚洲天堂一区二区| 日本一区免费在线观看| 久久国产精品久久w女人spa| 91精品人妻一区二区三区蜜桃欧美 | 五月天亚洲婷婷| 少妇高潮一区二区三区99小说| 欧美黄色免费网站| 精品无人区一区二区| 久久久久久久久久网| 99久久久精品免费观看国产蜜| 99免费在线观看| 亚洲精品电影在线观看| 日韩伦理在线| 日本不卡一区二区三区在线观看| 爽爽淫人综合网网站| 天堂资源在线视频| 在线成人小视频| 三级福利片在线观看| 波多野结衣成人在线| 亚洲视频二区| 精品国产av无码| 欧美日韩精品综合在线| 粗大黑人巨茎大战欧美成人| 高清视频一区| 羞羞答答国产精品www一本 | 亚洲一二三区视频在线观看| 天天插天天干天天操| 国产91九色视频| 91欧美在线| 天天躁日日躁狠狠躁免费麻豆| 精品久久久精品| av电影在线观看| 99国精产品一二二线| 国产精品嫩草99av在线| 国产三级黄色片| 日韩美女视频一区二区在线观看| 亚洲私拍视频| 亚洲永久一区二区三区在线| 国产ts人妖一区二区| 一级黄色在线视频| 久久影视免费观看| 婷婷精品在线观看| 特黄视频免费观看| 亚洲一区二区三区四区不卡| 蝌蚪视频在线播放| 91色精品视频在线| 亚洲少妇诱惑| 国产激情无码一区二区三区| 日韩成人黄色av| 亚洲网站三级| 日本精品一区二区三区四区| 日韩理论片网站| 嫩草精品影院| 69堂成人精品视频免费| 久久久精品午夜少妇| 欧美成人免费看| 男人添女人下面免费视频| 久久网站最新地址| 国产免费视频一区二区三区| 97视频国产在线| 小小影院久久| 黄色aaa视频|