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. We zouden het zeer waarderen als je kon Als je deze tutorial nuttig vindt. ⭐ star CocoIndex op GitHub CocoIndex op GitHub Use Cases Academisch zoeken en ophalen, evenals op onderzoek gebaseerde AI-agenten Papier aanbevelingssystemen Onderzoek kennis grafieken Semantische analyse van wetenschappelijke literatuur Wat we zullen bereiken Laten we eens kijken naar dit als een voorbeeld. De PDF Hier is wat we willen bereiken: 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. Dit maakt betere metagegevensgestuurde semantische zoekresultaten mogelijk.Bijvoorbeeld kunt u tekstverzoeken matchen met titels en abstracten. 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 Hier vindt u de volledige code . hier Als dit artikel nuttig voor u is, geef ons dan een ster ⭐ bij om ons te helpen groeien. GitHub Core Components 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? Voorwaarden . Install PostgreSQL CocoIndex uses PostgreSQL internally for incremental processing. . Configure your OpenAI API key Als alternatief hebben we native ondersteuning voor Gemini, Ollama, LiteLLM, checkout de . gids U kunt uw favoriete LLM-aanbieder kiezen en volledig on-premises werken. Het indexeren van de flow Dit project demonstreert een iets uitgebreider voorbeeld van metagegevens begrip dichter bij real-world gebruiksgevallen. Je zult zien hoe gemakkelijk het is om dit ontwerp te bereiken door CocoIndex binnen 100 lijnen van indexlogica - . De code Om u beter te helpen te navigeren wat we zullen doorlopen, hier is een stroomdiagram. Importeer een lijst met documenten in PDF. 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. Zoom in de stappen. Importeren van de papieren @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), ) zal een tabel met subvelden maken ( - het - het flow_builder.add_source filename content We kunnen verwijzen naar de Voor meer details. Documentatie Metadata extraheren en verzamelen Extract eerste pagina voor basisinformatie Definieer een aangepaste functie om de eerste pagina en het aantal pagina's van de PDF te extraheren. @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()) Sluit dit in je stroom. We extraheren metagegevens van de eerste pagina om de verwerkingskosten te minimaliseren, omdat de hele PDF erg groot kan zijn. with data_scope["documents"].row() as doc: doc["basic_info"] = doc["content"].transform(extract_basic_info) Na deze stap moet je de basisinformatie van elk papier hebben. Parse basisinformatie We converteren de eerste pagina naar Markdown met behulp van Marker. Als alternatief kunt u gemakkelijk uw favoriete PDF-parser aansluiten, zoals Docling. Definieer een marker-converterfunctie en cacheer deze, omdat de initialisatie resource-intensief is. Dit zorgt ervoor dat dezelfde converter-instantie wordt hergebruikt voor verschillende invoerbestanden. @cache def get_marker_converter() -> PdfConverter: config_parser = ConfigParser({}) return PdfConverter( create_model_dict(), config=config_parser.generate_config_dict() ) Plug het in een custom functie. @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 Geef het door aan je transformatie with data_scope["documents"].row() as doc: doc["first_page_md"] = doc["basic_info"]["first_page"].transform( pdf_to_markdown ) Na deze stap moet u de eerste pagina van elk papier in Markdown-formaat hebben. Extract basisinformatie met LLM CocoIndex ondersteunt LLM-gestructureerde extractie met complexe en geanimeerde schema's. Als u geïnteresseerd bent om meer te leren over nest schema's, verwijzen naar . Dit artikel @dataclasses.dataclass class PaperMetadata: """ Metadata for a paper. """ title: str authors: list[Author] abstract: str Plug het in de Met een gegevensklasse gedefinieerd, zal CocoIndex automatisch de LLM-reactie in de gegevensklasse analyseren. 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.", ) ) Na deze stap moet u de metagegevens van elk papier hebben. Papier metadata verzamelen 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"], ) Verzamel gewoon wat je nodig hebt :) verzamelen Twee Informatie auteur Filenamen auteur Filenamen Hier willen we auteur → papers in een aparte tabel verzamelen om een zoekfunctionaliteit op te bouwen. Gewoon door de auteur verzameld. 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"], ) Berekenen en verzamelen embeddings Titel van doc["title_embedding"] = doc["metadata"]["title"].transform( cocoindex.functions.SentenceTransformerEmbed( model="sentence-transformers/all-MiniLM-L6-v2" ) ) Abstractie Verdeel abstracten in stukjes, invoeg elke stuk en verzamel hun invoegingen. Soms kan het abstract erg lang zijn. 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, ) Na deze stap moet je de abstracte stukjes van elk papier hebben. Verwijder elk stukje en verzamel hun ingebedingen. with doc["abstract_chunks"].row() as chunk: chunk["embedding"] = chunk["text"].transform( cocoindex.functions.SentenceTransformerEmbed( model="sentence-transformers/all-MiniLM-L6-v2" ) ) Na deze stap moet je de embeddings van de abstracte stukken van elk papier hebben. Verzamelen van embeddings 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"], ) Exporten Ten slotte exporteren we de gegevens naar 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, ) ], ) In dit voorbeeld gebruiken we PGVector als embedding stores/ Met CocoIndex kunt u één lijn schakelen op andere ondersteunde Vector-databases zoals Qdrant, zie dit Voor meer details. gids We streven ernaar om interfaces te standaardiseren en het als het bouwen van LEGO te maken. Bekijk in CocoInsight stap voor stap Je kunt stap voor stap door het project lopen in Zie CocoInsight precies hoe elk veld is gebouwd en wat er achter de schermen gebeurt. Wilt u de index U kunt verwijzen naar deze sectie van Over Tekst ingebouwd Hoe een query op te bouwen tegen embeddings. Op dit moment biedt CocoIndex geen extra query-interface.We kunnen SQL schrijven of vertrouwen op de query-engine door de doelopslag. Veel databases hebben al query-implementaties geoptimaliseerd met hun eigen best practices De query-ruimte heeft uitstekende oplossingen voor querying, re-ranking en andere zoekgerelateerde functionaliteiten. Als je hulp nodig hebt bij het schrijven van de query, voel je vrij om contact met ons op te nemen op . Discord Ondersteun ons We verbeteren voortdurend en er komen binnenkort meer functies en voorbeelden. Als dit artikel nuttig voor u is, geef ons dan een ster ⭐ bij om ons te helpen groeien. GitHub Bedankt voor het lezen!