set long 999999
set pages 1000
set lines 200

/* --------------------------------

HNSW INDEX 

-------------------------------- */ 

-- crear indice HNSW para busquedas vectoriales aproximadas
DROP INDEX IF EXISTS markdown_chunks_hnsw_idx;

CREATE VECTOR INDEX markdown_chunks_hnsw_idx
ON markdown_chunks (embedding)
ORGANIZATION INMEMORY NEIGHBOR GRAPH
DISTANCE COSINE
WITH TARGET ACCURACY 90
PARAMETERS (
    TYPE HNSW,
    NEIGHBORS 32,
    EFCONSTRUCTION 200
);


/* --------------------------------

IVF INDEX 

-------------------------------- */ 

-- crear indice IVF con DOC_ID incluido para filtros por documento
DROP INDEX IF EXISTS markdown_chunks_ivf_idx;

CREATE VECTOR INDEX markdown_chunks_ivf_idx
ON markdown_chunks (embedding)
INCLUDE (doc_id)
ORGANIZATION NEIGHBOR PARTITIONS
DISTANCE COSINE
WITH TARGET ACCURACY 90
PARAMETERS (
    TYPE IVF,
    NEIGHBOR PARTITIONS 4,
    MIN_VECTORS_PER_PARTITION 1
);


/* --------------------------------

TEXT INDEX + VECTOR SEARCH

-------------------------------- */ 
-- hybrid indexes / text indexes para busquedas textuales y combinadas
DROP INDEX IF EXISTS markdown_chunks_text_idx;

CREATE SEARCH INDEX markdown_chunks_text_idx
ON markdown_chunks (chunk_text)
FOR TEXT;

select
    doc_id,
    chunk_id,
    SCORE(1) as text_score,
    VECTOR_DISTANCE(embedding, 
                    VECTOR_EMBEDDING(MULTILINGUAL_E5_BASE 
                                    USING 'estaciones de servicio' as DATA
                                    )
                    ) as vector_distance,
    chunk_text    
from markdown_chunks
where contains(chunk_text, 'Beneficio 
                            AND FUZZY(Benefcio) 
                            AND ABOUT(estaciones)
                            AND (Visa accum Mastercard)
                            AND (Clásica OR Oro)
                            AND (crédito NOT débito) 
                            AND NEAR((POS, Infonet), 5)
                            AND NEAR((App, Premmia, Petrobras), 1)
                            AND (consumo AND personal)', 1) > 0
order by vector_distance
fetch first 3 rows only;



/* --------------------------------

HYBRID VECTOR INDEX

-------------------------------- */ 

-- crear indice hibrido para combinar busqueda textual y semantica
DROP INDEX IF EXISTS markdown_chunks_hybrid_idx;

CREATE HYBRID VECTOR INDEX markdown_chunks_hybrid_idx
ON markdown_chunks (chunk_text)
PARAMETERS ('MODEL MULTILINGUAL_E5_BASE
             VECTOR_IDXTYPE HNSW
             MEMORY 128M')
PARALLEL 2;


-- ejemplo de consulta usando el indice hibrido
SELECT JSON_SERIALIZE(
    DBMS_HYBRID_VECTOR.SEARCH(
        JSON('{
            "hybrid_index_name" : "markdown_chunks_hybrid_idx",            
            "search_fusion"     : "UNION",
            "vector" : {
                "search_text"  : "beneficios en estaciones de servicio",
                "search_mode"  : "CHUNK"
            },
            "text" : {
                "contains"     : "estaciones AND Petrobras"
            },
            "return" : {
                "values" : [
                    "chunk_id",
                    "chunk_text",
                    "score",
                    "vector_score",
                    "text_score"
                ],
                "topN" : 5
            }
        }')
    ) RETURNING CLOB PRETTY
) AS hybrid_results;


SELECT jt.*
FROM
   JSON_TABLE(
        dbms_hybrid_vector.search(
                json_object(
                  'hybrid_index_name' VALUE 'markdown_chunks_hybrid_idx',      
                  'search_fusion'     VALUE 'INTERSECT',
                  'search_scorer'     VALUE 'rsf',
                  'vector'            VALUE json_object('search_text' VALUE 'beneficios en estaciones de servicio'), 
                  'text'              VALUE json_object('contains'    VALUE 'estaciones AND Petrobras'),
                  'return' VALUE json_object(
                                  'values' VALUE json_array('rowid', 'score', 'vector_score', 'vector_rank', 'text_score', 'text_rank', 'chunk_text'),
                                  'topN'   VALUE 3
                                )
                  RETURNING JSON
                )
            ),
        '$[*]' COLUMNS idx for ORDINALITY,
                score        NUMBER PATH '$.score',                
                vector_score NUMBER PATH '$.vector_score',                
                vector_rank  NUMBER PATH '$.vector_rank',
                text_score   NUMBER PATH '$.text_score',
                text_rank    NUMBER PATH '$.text_rank',
                chunk_text   VARCHAR2(4000) PATH '$.chunk_text'
    ) jt;