vistas salida procedimientos procedimiento parametros optimizar funciones ejemplos ejecutar developer consultas consultar con almacenado sql oracle plsql oracle11g oracle-sqldeveloper

sql - salida - Contando el número de visitas para una consulta/término de búsqueda dada por documento en Oracle



procedimientos y funciones oracle pl/sql (3)

Claro que puede manejar eso en pl / sql directamente (explicar le ayudará con eso), pero rápido y sucio, cree una vista de forma dinámica (una que filtre a su subconjunto) y ejecute count_hits.

Tengo una tabla que contiene blobs de texto del documento al que me estoy uniendo. Al usar el texto del oráculo, puedo obtener el fragmento de texto que contiene mi término de búsqueda (usando ctx_doc.snippet). Sin embargo, ahora debo especificar la cantidad de veces que se encontró este término de búsqueda para cada documento que coincidía con mi combinación, no todos los documentos que tengo. Tengo más de 100 000 documentos en total, pero me unen y el filtrado devuelve un subconjunto.

Leyendo en línea, hay CTX_QUERY.COUNT_HITS que puedo usar, pero que da el recuento de todos los documentos. Si tuviera un parámetro de clave de texto para COUNT_HITS, la vida sería buena, pero no existe ninguna.

¿Cómo puedo lograr el número de visitas para una consulta determinada en un documento en Oracle?


Si por "manchas de texto del documento" te refieres a "clob", entonces puedes usar este verdadero método probado. Tome la diferencia entre la longitud del documento y la longitud del documento con la cadena de búsqueda reemplazada por otra cosa. Eso te dará el número de coincidencias.

Por ejemplo:

select t.* from (select t.*, length(replace(t.doc, KEYWORD, KEYWORD || ''x'')) - length(t.doc) as nummatches from table t ) t order by nummatches desc;


Puedes continuar usando CTX_DOC; el procedimiento HIGHLIGHT puede distorsionarse ligeramente para hacer exactamente lo que está pidiendo.

Usando este ambiente:

create table docs ( id number, text clob, primary key (id) ); Table created. insert all into docs values (1, to_clob(''a dog and a dog'')) into docs values (2, to_clob(''a dog and a cat'')) into docs values (3, to_clob(''just a cat'')) select * from dual; 3 rows created. create index i_text_docs on docs(text) indextype is ctxsys.context; Index created.

CTX_DOC.HIGHLIGHT tiene un parámetro OUT de tipo CTX_DOC.HIGHLIGHT , que contiene el recuento de la cantidad de visitas dentro de un documento.

declare l_highlight ctx_doc.highlight_tab; begin ctx_doc.set_key_type(''PRIMARY_KEY''); for i in ( select * from docs where contains(text, ''dog'') > 0 ) loop ctx_doc.highlight(''I_TEXT_DOCS'', i.id, ''dog'', l_highlight); dbms_output.put_line(''id: '' || i.id || '' hits: '' || l_highlight.count); end loop; end; / id: 1 hits: 2 id: 2 hits: 1 PL/SQL procedure successfully completed.

Obviamente, si haces esto en una consulta, entonces un procedimiento no es lo mejor del mundo, pero puedes envolverlo en una función si lo deseas:

create or replace function docs_count ( Pid in docs.id%type, Ptext in varchar2 ) return integer is l_highlight ctx_doc.highlight_tab; begin ctx_doc.set_key_type(''PRIMARY_KEY''); ctx_doc.highlight(''I_TEXT_DOCS'', Pid, Ptext, l_highlight); return l_highlight.count; end;

Esto se puede llamar normalmente

select id , to_char(text) as text , docs_count(id, ''dog'') as dogs , docs_count(id, ''cat'') as cats from docs; ID TEXT DOGS CATS ---------- --------------- ---------- ---------- 1 a dog and a dog 2 0 2 a dog and a cat 1 1 3 just a cat 0 1

Si es posible, podría ser más sencillo reemplazar las palabras clave como dice Gordon. DBMS_LOB.GETLENGTH() función DBMS_LOB.GETLENGTH() lugar de simplemente LENGTH() para evitar posibles problemas, pero REPLACE() funciona en CLOB, así que esto no será un problema. Algo como lo siguiente (suponiendo que todavía estamos buscando perros)

select (dbms_lob.getlength(text) - dbms_lob.getlength(replace(text, ''dog''))) / length(''dog'') from docs

Vale la pena señalar que la búsqueda de cadenas se vuelve progresivamente más lenta a medida que las cadenas se hacen más grandes (de ahí la necesidad de indexación de texto), por lo que aunque funciona bien en el pequeño ejemplo, podría sufrir problemas de rendimiento en documentos más grandes.

Acabo de ver tu comentario :

... pero me requeriría revisar cada documento y hacer un recuento de los hits que francamente es computacionalmente costoso

No importa lo que haga, tendrá que revisar cada documento. Desea encontrar el número exacto de instancias de una cadena dentro de otra cadena y la única forma de hacerlo es mirar a través de la cadena completa. (Recomiendo leer la publicación de Joel en cadenas , hace un comentario sobre XML y las bases de datos relacionales, pero creo que también encaja muy bien aquí). Si buscabas una estimación, podrías calcular la cantidad de veces que aparece una palabra en la primera 100 caracteres y luego promedie sobre la longitud del LOB (algoritmo de mierda que conozco), pero quieres ser preciso.

Obviamente, no sabemos cómo Oracle ha implementado todas sus funciones internamente, pero hagamos algunas suposiciones. Para calcular la longitud de una cadena necesita contar literalmente el número de bytes en ella. Esto significa iterar sobre toda la cadena. Hay algunos algoritmos para mejorar esto , pero todavía implican iterar sobre la cadena. Si desea reemplazar una cadena por otra, debe iterar sobre la cadena original, buscando la cadena que desea reemplazar.

Teóricamente, dependiendo de cómo Oracle haya implementado todo, usar CTX_DOC.HIGHLIGHT debería ser más rápido que cualquier otra cosa, ya que solo tiene que iterar una vez sobre la cadena original, buscar la cadena que desea buscar y almacenar la compensación de bytes / caracteres desde el inicio de la cadena original.

La length(replace(<original string>, <new string>)) - length(<original string) sugerencia length(replace(<original string>, <new string>)) - length(<original string) puede tener que iterar tres veces separadas sobre la cadena original (o algo que está cerca de ella en longitud). Dudo que esto realmente lo haga, ya que todo puede almacenarse en caché y Oracle debe almacenar la longitud de bytes para hacer que LENGTH() eficiente. Esta es la razón por la que sugiero usar DBMS_LOB.GETLENGTH lugar de simplemente LENGTH() ; Oracle casi seguramente almacena la longitud del byte del documento.

Si no desea analizar el documento cada vez que ejecuta sus consultas, puede valer la pena realizar una única ejecución al cargar / actualizar datos y almacenar, por separado, las palabras y el número de apariciones por documento.