Queremos organizar el display de una lista de registros bibliográficos asociados a un encabezamiento (pensemos por ahora en nombres personales), de manera tal que queden separados en bloques los registros donde la persona aparece como “autor”, de aquellos donde desempeña otra función. A su vez, sería deseable subclasificar estos últimos de acuerdo al tipo de función.
Un ejemplo sencillo puede verse en este mensaje del grupo Catalis.
Consideremos, para simplificar, que “autor” corresponde a un 100 o un 700 sin código de relación (subcampo $4), y “otra función” corresponde a un 700 con $4.
Si —tal como sucede actualmente— al invertido de la base BIBLIO mandamos los puntos de acceso sin hacer distinción según la relación (700$4), entonces al recuperar usando un punto de acceso obtendremos indiscriminadamente todos los registros asociados, y la clasificación en base a la relación habrá que hacerla analizando cada uno de los registros recuperados. Esto agrega un costo a cada búsqueda, proporcional al número de registros recuperados.
Si en cambio mandamos al invertido de forma diferenciada los “autores” y los “otra-función”, entonces podemos hacer dos búsquedas separadas: con una recuperamos los registros donde Fulano aparece como “autor”, y con otra aquellos donde Fulano aparece en “otra-función”. Luego ordenamos cada uno de esos dos conjuntos por el criterio que corresponda. Para aplicar esa distinción a nivel del invertido podemos usar diferentes tags en la FST, e.g. 9100 para “autor” y 9101 para “otra-función”.
Pero, ¿y si queremos ser más específicos y poder recuperar solamente registros donde Fulano es editor, o director de tesis, en vez de juntar todos los casos de “otra-función” en una misma bolsa? Tal vez deberíamos añadir nuevas claves al diccionario, de la forma _NAME_<id>_<relación>
:
_NAME_1234_--- <= "autor" (i.e., relación no especificada) _NAME_1234_EDT <= editor _NAME_1234_AUI <= prologuista _NAME_1234_TRL <= traductor
Si la persona tiene más de un código de relación (p.ej. aui
y trl
):
_NAME_1234_AUI_TRL <= traductor y prologuista
aunque quizás sea mejor enviarlos al invertido en forma separada, así lo recuperamos al buscar por una cualquiera de las relaciones:
_NAME_1234_AUI <= prologuista _NAME_1234_TRL <= traductor
Actualmente, sólo estamos usando esta clave:
_NAME_1234 <= no discrimina relaciones
Parece que sería redundante conservarla si vamos a utilizar las propuestas arriba, pero… ¡Atención! Si bien para una búsqueda general podríamos usar _NAME_1234_$
(que agrupa todos los casos), para determinar de manera sencilla el número de postings (registros asociados al encabezamiento) conviene tener también una clave “limpia” _NAME_1234
, aunque esto resulte redundante. Actualmente se usa algo así para encontrar los postings asociados al encabezamiento v9:
f(npost(['biblio']'_NAME_'v9),1,0)
y no podemos usar npost()
con un término que incluya el sufijo $
.
Actualmente sólo usamos las claves _NAME_<id> para poder averiguar fácilmente la cantidad de postings asociados a un encabezamiento (hacer un wcgrep de “_NAME_” y de “_%s_”), pero no para las búsquedas por encabezamiento en la base BIBLIO, que siguen dependiendo de la forma *textual* del encabezamiento (con los consiguientes problemas asociados al límite en la longitud de las claves, ver heading-match-in-bib-record.xis
). Si bien es conveniente que la URL de una búsqueda de este tipo tenga como query el encabezamiento, y no un identificador numérico (que podría llegar a variar), podríamos introducir un paso intermedio que mapee el encabezamiento, recibido vía URL, a su identificador, y luego hacer la búsqueda en biblio de manera precisa, usando sólo el identificador. No importa que el identificador sea inestable (i.e., que pueda cambiar en una futura generación de las bases del OPAC), ya que no lo estaríamos exponiendo públicamente. (¿Por qué no habremos hecho esto antes?)
Cómo hacer el mapeo encabezamiento ⇒ id (on the fly, con cada petición):
Este procedimiento sería similar (pero más fácil y limpio) al actualmente empleado, que hace la búsqueda directamente en BIBLIO, sin pasar por el id. Si hacemos esto, ¿podemos omitir los encabezamientos completos en el invertido de BIBLIO?
Modificar las líneas 9100 que generan claves de la forma _NAME_<id>
:
if p(v700) then proc('d1000', 'd1001'), /* limpiamos campos auxiliares */ proc( /*'d1000',*/ (, 'a1000¦', replace(v700*3,'^','¦a1000¦'), '¦', 'a1000¦##¦', ) ), /* loop sobre v1000 */ ,(, if v1000 = '##' then /, proc('d1001'), /* almacena los $4 de una ocurrencia del v700 */ else if 'abcdq' : v1000.1 then '~'v1000*1, /* ATENCION! esto sólo funciona si 700$4 aparece *ANTES* que 700$9 */ else if '4' = v1000.1 then proc('d1001','a1001|',v1001[1],'_',v1000*1,'|'), else if '9' = v1000.1 then /, '_NAME_', /* sin sufijo */ v1000*1, /, '_NAME_', /* con sufijo para indicar la relación */ v1000*1, if v1001[1] = '' then '_---' else v1001[1], fi, / fi,fi,fi,fi, ,), fi,
El algoritmo sería algo como esto:
query
para convertirlo en la expresión de búsqueda expr
(esto es, aplicar a query las transformaciones necesarias para que pueda ser utilizado como clave de búsqueda)expr
matches
← {}
H
encontrado:H
coincide con query
: matches
← matches + {encabezamiento}
matches
tiene cero o más de un elemento: error, abortarID
← id del único encabezamiento en matches
relations
← {}
k
del diccionario BIBLIO entre _NAME_<ID>_---
y _NAME_<ID>_zzz
:relations
← relations
+ {los 3 caracteres finales de k
}rel
en relations
:_NAME_<ID>_<rel>
<!-- Encontrar ID del encabezamiento --> <!-- Primero, normalizar query. Ver cómo aparecen los encabezamientos en el diccionario de las bases NAME, SUBJ. Notar que no coincide con el diccionario de BIBLIO. --> <field tag="3001" action="replace"><pft>hacer algo a v2001</pft></field> <!-- Búsqueda --> <do task="search"> <parm name="db"><pft>v2003</pft></parm> <!-- v2003: NAME / SUBJ --> <parm name="expression"><pft>v3001</pft></parm> <!-- v2001 normalizado --> <define>1002 Isis_Total</define> <loop> <field action="import" tag="list">2001</field> <flow action=""><pft>if val(v1002) <> 1 then 'Quit' fi</pft></flow> <field tag="9" action="replace"><pft>if v1 = v2001 then v9 fi</pft></field> <field tag="9" action="export">9</field> </loop> </do> <!-- Encontrar relaciones asociadas al encabezamiento --> <do task="keyrange"> <parm name="db">BIBLIO</parm> <parm name="from"><pft>'_'v2003'_', v9, '_'</pft></parm> <parm name="to"><pft>'_'v2003'_', v9, '_ZZZ'</pft></parm> <define>1 Isis_Key</define> <loop> <list action="load" type="list"><pft>v1</pft></list> </loop> </do> <!-- Encontrar y procesar los registros bibliográficos --> <!-- La lista contiene las relaciones (claves para las búsquedas) --> <do task="list"> <define>1 Isis_Item</define> <!-- Una búsqueda por cada clave --> <!-- FIXME - Vamos a tener un problema con la limitación de wxis a una única lista; en cada búsqueda necesitamos una lista para almacenar los resultados antes de presentarlos, pero todas las búsquedas viven dentro de un ''do task=list'' exterior. El script agrep-multi.xis parece que resuelve un problema similar (usa un <do> + iocc) --> <display><pft>'<h3>Relación: ', right(v1, 3),'</h3>'</pft></display> <do task="search"> <parm name="db">BIBLIO</parm> <parm name="expression"><pft>v1</pft></parm> <define>1002 Isis_Total</define> <loop> <!-- procesar cada registro bibliográfico --> <display><pft>'Total: ',v1002,'<br>'</pft></display> </loop> </do> </do>
Debemos prestar atención a la diferencia entre estas dos maneras de enviar encabezamientos a los diccionarios, según la base.
mx name gizmo=REMOVE-CHARS,1 <= elimina apóstrofes y otros caracteres equivalentes fst=@HEADINGS.FST <= 2 0 '~',@HEADSORT.PFT, actab=AC-ANSI.TAB uctab=UC-ANSI.TAB fullinv=name ---------------------------- ~ABREGU MARTIN <= 1 "~aAbregú, Martín." ~ADERINWALE AYODELE ~ADLER GLENN 1958 <= 1 "~aAdler, Glenn,~d1958-" ~AFRICA INSTITUTE OF SOUTH AFR ~AFRICA LEADERSHIP FORUM ~AGUERO FELIPE ~ALBERT EINSTEIN INSTITUTION C ~ALEN ANDRE ~ALFONSIN RAUL ~ARMSTRONG CHARLES K
Estas claves se utilizan en browse-headings.xis
, mediante un keyrange
(y no un search
). El input es browseTerm
, el término inicial a partir del cual se desea recorrer el índice de encabezamientos. Este término (ingresado por el usuario, potencialmente una cadena arbitraria de caracteres) se normaliza eliminando espacios iniciales y el carácter \
, anteponiendo ~a
, aplicando HEADSORT.PFT
, y finalmente eliminando el carácter final (si es punto, coma o espacio). El propósito de esta normalización es lograr que la cadena resultante sea consistente con las claves del diccionario de NAME.
EXPLICAR las razones para usar HEADSORT; relación entre el ordenamiento del archivo maestro de NAME y el ordenamiento de su diccionario. ¿Cómo se relaciona la forma en que distinguimos/confundimos encabezamientos usando normalización para el diccionario, con la generación de la base NAME?
mx biblio gizmo=DICTGIZ,100,110,111,130,700,710,711,730,800,810,811,830 gizmo=DICTGIZ,240,245,246,440,740,600,610,611,630,650,651,653,655,656 fst=@BIBLIO.FST <= 9100 0 if p(v700) then proc('d1000',(,'a1000¦',replace(v700*3,'^','¦a1000¦'),'¦','a1000¦##¦',) ), ,(,if v1000 = '##' then / else if 'abcdq' : v1000.1 then '~'v1000*1, else if '9'=v1000.1 then /'_NAME_',v1000*1/ fi,fi,fi ,), fi, actab=AC-ANSI.TAB uctab=UC-ANSI.TAB stw=@BIBLIO.STW fullinv=biblio ---------------------------- ~ABREGU_MARTIN <= 700 "1#^aAbregú, Martín.^9000676" ~ADERINWALE_AYODELE ~ADLER_GLENN~1958- <= 700 "1#^aAdler, Glenn,^d1958-^9001507" ~AFRICA_INSTITUTE_OF_SOUTH_AFR ~AFRICA_LEADERSHIP_FORUM ~AGUERO_FELIPE ~ALBERT_EINSTEIN_INSTITUTION_[ ~ALEN_ANDRE ~ALFONSIN_RAUL ~ARMSTRONG_CHARLES_K
Estas claves se utilizan en heading-match-in-bib-record.xis
, mediante un search
. El input es query
, el encabezamiento para el cual queremos encontrar registros bibliográficos asociados. En condiciones “normales”, query
ha sido generado automáticamente a partir de un encabezamiento existente, y no ingresado por el usuario. La normalización consiste en: reemplazar ^x
por ~
(para cualquier x
), y aplicar DICTGIZ.PFT
. El propósito de esta normalización es lograr que la cadena resultante sea consistente con las claves del diccionario de BIBLIO.
¿A qué viene este DICTGIZ? El propósito de este gizmo era normalizar los encabezamientos de acuerdo con estos criterios:
+
(OR) y *
(AND), son reemplazados por caracteres “seguros”. AVERIGUAR: ¿encerrar entre comillas una clave no la vuelve segura?A diferencia de la base NAME, donde solamente estábamos interesados en utilizar las claves asociadas a encabezamientos en forma aislada, para identificar el MFN del registro correspondiente, en la base BIBLIO debíamos considerar la posibilidad de que las claves fueran parte de expresiones de búsqueda más complejas —es decir, con operadores—, de ahí la importancia del segundo criterio. Posiblemente esta haya sido la razón para aplicar diferentes tratamientos.
Podríamos considerar la aplicación de un procedimiento de normalización bien conocido: NACO Normalization (también disponible como servicio en línea), quizás con alguna leve modificación para adaptarlo a necesidades propias del OpacMarc. Ver también el paper de OCLC (pdf).
Si bien en OpacMarc podríamos prescindir de estas claves en el diccionario de BIBLIO (si pasamos a basar las búsquedas por encabezamiento en el uso del ID), no olvidemos que en Catalis esta es la única forma de “ver los encabezamientos” en el diccionario; Catalis ofrece (o puede ofrecer) acceso crudo al diccionario.
¿Qué pasa si un nombre aparece como “autor” y como “otra función” en un mismo registro? Creo que no debería suceder que un nombre se repitiera en campos 100/700.
¿Qué hacemos con la mezcla que puede llegar a haber dentro del conjunto de registros correspondientes a “otra función”? Quizás ahora sí podríamos analizar registro por registro, una vez que nos acotamos a este conjunto. Tendremos un problema si un nombre tiene más de un $4 en un mismo registro.
¡Ojo con los puntos de acceso de nombre-título, 700$a$t (con o sin $4)!
Ver la relación entre esta organización del listado y la paginación.
Algunos detalles podrán depender del tipo de relaciones que sean más importantes (i.e., que nos interese destacar) en cada catálogo particular. Por ejemplo, los roles “fotógrafo” o “ilustrador” podrían ser más relevantes en una colección de arte que en una general.
Preguntas que deberían ser fáciles de responder:
keyrange
en BIBLIO, from=_NAME_<H>_ to=_NAME_<H>_
(¿y si quisiéramos averiguarlo sólo mirando NAME?)npost(['BIBLIO']'_NAME_<H>_<f>')
; ejemplo: npost(['BIBLIO']'_NAME_12345_EDT')
(función: editor)Para permitir la organización de registros aquí planteada, es fundamental que los puntos de acceso incluyan información (normalizada) acerca de la relación. No siempre esta información ha sido registrada, de manera que antes de considerar la implementación de esta funcionalidad para una determinada base bibliográfica, analicemos el uso de los subcampos de relación (7xx$4, 7xx$e), y hagamos las modificaciones apropiadas.
mxtb biblio create=v700_e "30:(v700^e/)" mx v700_e "pft=v999,c6,v1/" now mxtb biblio create=v700_4 "30:(v700^4/)" mx v700_4 "pft=v999,c6,v1/" now
Los 700$e deberían convertirse en 700$4. TAREA: escribir script.
(Repetir para otros 7xx.)
mx biblio "pft=if v245^c:'edit' and not v700^e:'edit' and not v700^4:'edt' then mfn/v245/(v700/)# fi" now lw=300