In this blog we will walk through a comprehensive example of indexing research papers with extracting different metadata — beyond full text chunking and embedding — and build semantic embeddings for indexing and querying. Būtume labai dėkingi, jei galėtumėte Jei manote, kad šis tutorial yra naudingas. ⭐ star CocoIndex Github svetainėje CocoIndex Github svetainėje Naudokite atvejus Akademinė paieška ir paieška, taip pat moksliniais tyrimais pagrįsti AI agentai Popierinės rekomendacijos Moksliniai žinių grafikai Semantinė mokslinės literatūros analizė Ką mes pasieksime Pažvelkime į tai Kaip pavyzdį PDF puslapis Štai ką mes norime pasiekti: Extract the paper metadata, including file name, title, author information, abstract, and number of pages. Build vector embeddings for the metadata, such as the title and abstract, for semantic search. Tai suteikia geresnių metaduomenų varomų semantinių paieškos rezultatų. Pavyzdžiui, galite suderinti tekstines užklausas su antraštėmis ir abstrakcijomis. Build an index of authors and all the file names associated with each author to answer questions like "Give me all the papers by Jeff Dean." If you want to perform full PDF embedding for the paper, you can also refer to . this article Galite rasti visą kodą . čia Jei šis straipsnis jums yra naudingas, prašome suteikti mums žvaigždutę Padėti mums augti. „GitHub“ Pagrindiniai komponentai PDF Preprocessing Reads PDFs using and extracts: pypdf Total number of pages First page content (used as a proxy for metadata-rich information) Markdown Conversion Converts the first page to Markdown using . Marker LLM-Powered Metadata Extraction Sends the first-page Markdown to GPT-4o using CocoIndex's function. ExtractByLlm Extracted metadata includes and more. (string) title (with name, email, and affiliation) authors (string) abstract Semantic Embedding The title is embedded directly using the model by the SentenceTransformer. all-MiniLM-L6-v2 Abstracts are chunked based on semantic punctuation and token count, then each chunk is embedded individually. Relational Data Collection Authors are unrolled and collected into an relation, enabling queries like: author_papers Show all papers by X Which co-authors worked with Y? Išankstinės sąlygos . Install PostgreSQL CocoIndex uses PostgreSQL internally for incremental processing. . Configure your OpenAI API key Arba mes turime gimtąją paramą Gemini, Ollama, LiteLLM, užsisakyti . Vadovas Galite pasirinkti savo mėgstamą LLM teikėjo ir gali dirbti visiškai vietoje. Indeksavimo srauto apibrėžimas Šis projektas demonstruoja šiek tiek išsamesnį metaduomenų supratimo pavyzdį, arčiau realaus pasaulio naudojimo atvejų. Jūs pamatysite, kaip lengva pasiekti šį CocoIndex dizainą per 100 indeksavimo logikos eilučių - . Kodą Norėdami geriau padėti jums naršyti, ką mes einame, čia yra srauto diagrama. Importuokite dokumentų sąrašą PDF formatu. For each file: Extract the first page of the paper. Convert the first page to Markdown. Extract metadata (title, authors, abstract) from the first page. Split the abstract into chunks, and compute embeddings for each chunk. Export to the following tables in Postgres with PGVector: Metadata (title, authors, abstract) for each paper. Author-to-paper mapping, for author-based query. Embeddings for titles and abstract chunks, for semantic search. Pažvelkime į žingsnius. Importuoti dokumentus @cocoindex.flow_def(name="PaperMetadata") def paper_metadata_flow( flow_builder: cocoindex.FlowBuilder, data_scope: cocoindex.DataScope ) -> None: data_scope["documents"] = flow_builder.add_source( cocoindex.sources.LocalFile(path="papers", binary=True), refresh_interval=datetime.timedelta(seconds=10), ) bus sukurta lentelė su pogrupiais ( , • , flow_builder.add_source filename content Galime kalbėti apie Dėl daugiau detalių. Dokumentacijos Išgauti ir rinkti metaduomenis Ištraukite pirmąjį puslapį pagrindinei informacijai Nustatykite individualią funkciją, kad būtų išgautas pirmasis puslapis ir PDF puslapių skaičius. @dataclasses.dataclass class PaperBasicInfo: num_pages: int first_page: bytes @cocoindex.op.function() def extract_basic_info(content: bytes) -> PaperBasicInfo: """Extract the first pages of a PDF.""" reader = PdfReader(io.BytesIO(content)) output = io.BytesIO() writer = PdfWriter() writer.add_page(reader.pages[0]) writer.write(output) return PaperBasicInfo(num_pages=len(reader.pages), first_page=output.getvalue()) Dabar įjunkite tai į savo srautą. Mes išgauname metaduomenis iš pirmojo puslapio, kad sumažintume apdorojimo išlaidas, nes visas PDF gali būti labai didelis. with data_scope["documents"].row() as doc: doc["basic_info"] = doc["content"].transform(extract_basic_info) Po šio žingsnio turėtumėte turėti pagrindinę informaciją apie kiekvieną popierių. Pagrindinė informacija Mes konvertuosime pirmąjį puslapį į "Markdown" naudojant žymeklį. Arba galite lengvai prijungti savo mėgstamą PDF analizatorių, pvz., Docling. Nustatykite žymeklio konverterio funkciją ir užfiksuokite ją, nes jos inicijavimas yra daug išteklių. Tai užtikrina, kad ta pati konverterio instancija būtų pakartotinai naudojama skirtingiems įvesties failams. @cache def get_marker_converter() -> PdfConverter: config_parser = ConfigParser({}) return PdfConverter( create_model_dict(), config=config_parser.generate_config_dict() ) Prijunkite jį į įprastą funkciją. @cocoindex.op.function(gpu=True, cache=True, behavior_version=1) def pdf_to_markdown(content: bytes) -> str: """Convert to Markdown.""" with tempfile.NamedTemporaryFile(delete=True, suffix=".pdf") as temp_file: temp_file.write(content) temp_file.flush() text, _, _ = text_from_rendered(get_marker_converter()(temp_file.name)) return text Perkelkite jį į savo transformaciją with data_scope["documents"].row() as doc: doc["first_page_md"] = doc["basic_info"]["first_page"].transform( pdf_to_markdown ) Po šio žingsnio turėtumėte turėti pirmąjį kiekvieno popieriaus puslapį Markdown formatu. Išgauti pagrindinę informaciją su LLM CocoIndex natūraliai palaiko LLM struktūrizuotą gavybą su sudėtingomis ir įtvirtintomis schemomis. Jei jus domina daugiau sužinoti apie nested schemas, kreipkitės į . Šis straipsnis @dataclasses.dataclass class PaperMetadata: """ Metadata for a paper. """ title: str authors: list[Author] abstract: str Įdėkite jį į Su apibrėžta duomenų klase, CocoIndex automatiškai analizuoja LLM atsakymą į duomenų klasę. ExtractByLlm doc["metadata"] = doc["first_page_md"].transform( cocoindex.functions.ExtractByLlm( llm_spec=cocoindex.LlmSpec( api_type=cocoindex.LlmApiType.OPENAI, model="gpt-4o" ), output_type=PaperMetadata, instruction="Please extract the metadata from the first page of the paper.", ) ) Po šio žingsnio turėtumėte turėti kiekvieno popieriaus metaduomenis. Popieriaus metaduomenų rinkimas paper_metadata = data_scope.add_collector() with data_scope["documents"].row() as doc: # ... process # Collect metadata paper_metadata.collect( filename=doc["filename"], title=doc["metadata"]["title"], authors=doc["metadata"]["authors"], abstract=doc["metadata"]["abstract"], num_pages=doc["basic_info"]["num_pages"], ) Surinkite viską, ko jums reikia :) surinkti dviejų Informacijos Autorius Filė Autorius Filė Čia norime surinkti Autorius → Dokumentus atskiroje lentelėje, kad sukurtume paieškos funkciją. Paprasčiausiai surinkta autoriaus. author_papers = data_scope.add_collector() with data_scope["documents"].row() as doc: with doc["metadata"]["authors"].row() as author: author_papers.collect( author_name=author["name"], filename=doc["filename"], ) Apskaičiuoti ir rinkti įdėklus Titulinis doc["title_embedding"] = doc["metadata"]["title"].transform( cocoindex.functions.SentenceTransformerEmbed( model="sentence-transformers/all-MiniLM-L6-v2" ) ) Abstrakcijos Suskaidykite abstraktus į gabalus, įdėkite kiekvieną gabalėlį ir surinkite jų įdėklus. Kartais abstrakcija gali būti labai ilga. doc["abstract_chunks"] = doc["metadata"]["abstract"].transform( cocoindex.functions.SplitRecursively( custom_languages=[ cocoindex.functions.CustomLanguageSpec( language_name="abstract", separators_regex=[r"[.?!]+\s+", r"[:;]\s+", r",\s+", r"\s+"], ) ] ), language="abstract", chunk_size=500, min_chunk_size=200, chunk_overlap=150, ) Po šio žingsnio turėtumėte turėti abstrakčius kiekvieno popieriaus gabaliukus. Įdėkite kiekvieną gabalėlį ir surinkite jų įdėklus. with doc["abstract_chunks"].row() as chunk: chunk["embedding"] = chunk["text"].transform( cocoindex.functions.SentenceTransformerEmbed( model="sentence-transformers/all-MiniLM-L6-v2" ) ) Po šio žingsnio turėtumėte turėti kiekvieno popieriaus abstrakčių gabalėlių įterpimus. Surinkti įdėklus metadata_embeddings = data_scope.add_collector() with data_scope["documents"].row() as doc: # ... process # collect title embedding metadata_embeddings.collect( id=cocoindex.GeneratedField.UUID, filename=doc["filename"], location="title", text=doc["metadata"]["title"], embedding=doc["title_embedding"], ) with doc["abstract_chunks"].row() as chunk: # ... process # collect abstract chunks embeddings metadata_embeddings.collect( id=cocoindex.GeneratedField.UUID, filename=doc["filename"], location="abstract", text=chunk["text"], embedding=chunk["embedding"], ) eksportuoti Galiausiai duomenis eksportuojame į „Postgres“. paper_metadata.export( "paper_metadata", cocoindex.targets.Postgres(), primary_key_fields=["filename"], ) author_papers.export( "author_papers", cocoindex.targets.Postgres(), primary_key_fields=["author_name", "filename"], ) metadata_embeddings.export( "metadata_embeddings", cocoindex.targets.Postgres(), primary_key_fields=["id"], vector_indexes=[ cocoindex.VectorIndexDef( field_name="embedding", metric=cocoindex.VectorSimilarityMetric.COSINE_SIMILARITY, ) ], ) Šiame pavyzdyje mes naudojame PGVector kaip įterpimo parduotuves / Naudodami „CocoIndex“, galite atlikti vieną eilutės perjungimą kitose palaikytose „Vector“ duomenų bazėse, pvz., „Qdrant“. Dėl daugiau detalių. Vadovas Mes siekiame standartizuoti sąsajas ir padaryti tai kaip statyti LEGO. „CocoInsight“ žingsnis po žingsnio Galite vaikščioti per projektą žingsnis po žingsnio Žiūrėti Kokosų apžvalga Tiksliai, kaip kiekvienas laukas yra pastatytas ir kas vyksta už scenų. Rekomenduojamas indeksas Galite kreiptis į šį skyrių Apie Teksto įterpimas Kaip sukurti užklausą prieš įterpimus. Kol kas CocoIndex nesuteikia papildomų užklausų sąsajų.Galime rašyti SQL arba pasikliauti užklausų varikliu pagal tikslinę saugyklą. Daugelis duomenų bazių jau optimizavo užklausų įgyvendinimą savo geriausia praktika Užklausų erdvė turi puikius sprendimus užklausoms, perrankavimui ir kitoms su paieška susijusioms funkcijoms. Jei jums reikia pagalbos rašant užklausą, nedvejodami kreipkitės į mus . Nesutarimai Palaikyk mus Mes nuolat tobuliname, ir netrukus bus daugiau funkcijų ir pavyzdžių. Jei šis straipsnis jums yra naudingas, prašome suteikti mums žvaigždutę Padėti mums augti. „GitHub“ Ačiū už skaitymą!