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. Ens agradaria molt si poguessis Si us sembla útil aquest tutorial. ⭐ star CocoIndex on GitHub CocoIndex a GitHub Utilitzar casos Cerca i recuperació acadèmica, així com agents d'IA basats en la investigació Sistemes de recomanació de paper Graus de coneixement de recerca Semantic analysis of scientific literature Què aconseguirem Anem a fer una ullada a això com a exemple. El PDF Això és el que volem aconseguir: 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. Això permet obtenir millors resultats de cerca semàntica basats en metadades. Per exemple, podeu combinar consultes de text amb títols i abstractes. 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 Podeu trobar el codi complet . Aquí Si aquest article és útil per a vostè, si us plau, donar-nos una estrella Per ajudar-nos a créixer GitHub Components bàsics 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? Prerequisits . Install PostgreSQL CocoIndex uses PostgreSQL internally for incremental processing. . Configure your OpenAI API key Alternativament, tenim suport natiu per a Gemini, Ollama, LiteLLM, checkout el . guide Vostè podria triar el seu proveïdor preferit LLM i pot treballar completament on-premises. Definició de flux d'index Aquest projecte demostra un exemple una mica més complet de comprensió de metadades més a prop dels casos d'ús del món real. Veuràs com és fàcil aconseguir aquest disseny de CocoIndex dins de 100 línies de lògica d'index . El codi Per ajudar-vos a navegar millor pel que anirem passant, aquí teniu un diagrama de flux. Importació d'una llista de documents en 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. Let’s zoom in the steps. Importar els papers @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), ) Es crearà una taula amb subcamps ( , , el flow_builder.add_source filename content Podem referir-nos a la Per a més detalls. Documentació Extracció i recollida de metadades Extraure la primera pàgina per a la informació bàsica Defineix una funció personalitzada per extreure la primera pàgina i el nombre de pàgines del PDF. @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()) Afegeix-ho al teu flux. Extraïm metadades de la primera pàgina per minimitzar el cost de processament, ja que tot el PDF pot ser molt gran. with data_scope["documents"].row() as doc: doc["basic_info"] = doc["content"].transform(extract_basic_info) Després d'aquest pas, hauríeu de tenir la informació bàsica de cada paper. Informació bàsica Convertim la primera pàgina a Markdown utilitzant Marker. Alternativament, podeu connectar fàcilment el vostre parser PDF preferit, com Docling. Defineix una funció de conversió de marcadors i la cache, ja que la seva inicialització és intensiva en recursos. Això garanteix que la mateixa instància de convertidor es reutilitzi per a diferents arxius d'entrada. @cache def get_marker_converter() -> PdfConverter: config_parser = ConfigParser({}) return PdfConverter( create_model_dict(), config=config_parser.generate_config_dict() ) Connecteu-lo a una funció custom. @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 Passa'l a la teva transformació with data_scope["documents"].row() as doc: doc["first_page_md"] = doc["basic_info"]["first_page"].transform( pdf_to_markdown ) Després d'aquest pas, hauríeu de tenir la primera pàgina de cada paper en format Markdown. Extraure informació bàsica amb LLM Definir un esquema per a l'extracció LLM. CocoIndex dóna suport natiu a l'extracció estructurada LLM amb esquemes complexos i embolicats. If you are interested in learning more about nested schemas, refer to . Aquest article @dataclasses.dataclass class PaperMetadata: """ Metadata for a paper. """ title: str authors: list[Author] abstract: str Connecta’l a la Amb una classe de dades definida, CocoIndex analitzarà automàticament la resposta LLM a la classe de dades. 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.", ) ) Després d'aquest pas, hauríeu de tenir les metadades de cada paper. Col·lecció de metadades de paper 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"], ) Recull tot el que necessites :) Col·lecció Dues Informació author Filòsof author Filòsof Aquí volem recollir Autor → Papers en una taula separada per construir una funcionalitat de cerca. Simply collect by author. 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"], ) Calcular i recollir embeddings Títol doc["title_embedding"] = doc["metadata"]["title"].transform( cocoindex.functions.SentenceTransformerEmbed( model="sentence-transformers/all-MiniLM-L6-v2" ) ) Abstracció Divideix l'abstracte en trossos, incrusta cada tros i recull les seves incrustacions. A vegades l’abstracte pot ser molt llarg. 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, ) Després d'aquest pas, hauríeu de tenir els trossos abstractes de cada paper. Col·loca cada peça i recull els seus embotits. with doc["abstract_chunks"].row() as chunk: chunk["embedding"] = chunk["text"].transform( cocoindex.functions.SentenceTransformerEmbed( model="sentence-transformers/all-MiniLM-L6-v2" ) ) Després d'aquest pas, hauríeu de tenir les incorporacions de les peces abstractes de cada paper. Col·lecció 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"], ) Exportació Finalment, exportem les dades a 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 this example we use PGVector as embedding stores/ Amb CocoIndex, podeu fer un canvi de línia en altres bases de dades vectorials compatibles com Qdrant. Per a més detalls. Guia Volem estandarditzar les interfícies i fer que sigui com construir LEGO. Veure en CocoInsight pas per pas Podeu fer un passeig pel projecte pas a pas Veure CocoInsight Exactament com es construeix cada camp i què passa darrere de les escenes. Desitja l'índex Podeu consultar aquesta secció de Sobre Textos incorporats Com crear una consulta contra embeddings. De moment, CocoIndex no proporciona interfície de consulta addicional. Podem escriure SQL o confiar en el motor de consulta per l'emmagatzematge objectiu. Moltes bases de dades ja han optimitzat les implementacions de consulta amb les seves pròpies millors pràctiques L'espai de consulta disposa d'excel·lents solucions per a la consulta, el rearrangament i altres funcionalitats relacionades amb la cerca. Si necessiteu ajuda amb l'escriptura de la consulta, si us plau sentiu lliure de contactar amb nosaltres a . Discòrdia Suport a nosaltres Estem millorant constantment, i aviat vindran més característiques i exemples. Si aquest article és útil per a vostè, si us plau, donar-nos una estrella Per ajudar-nos a créixer GitHub Gràcies per llegir!