====== OpacMarc: Organización de registros en base a códigos de relación ======
Estas notas fueron motivadas por [[http://groups.google.com/group/catalis/browse_thread/thread/92ddb8ce670ddd6b|una consulta de Gabriela Cirelli (IB-CAB), en el grupo de Catalis]] (febrero 2009).
===== Introducción =====
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 [[http://groups.google.com/group/catalis/msg/f2560841be417f56|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.
===== Implementación =====
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__'':
_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 ''$''.
==== Encabezamientos versus identificadores numéricos ====
Actualmente sólo usamos las claves _NAME_ 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):
* Normalizar el encabezamiento (headsort.pft?)
* Buscar registros de la base NAME mediante la forma normalizada del encabezamiento
* 0 hits: mensaje de error
* 1 o más hits: hacer loop sobre los registros recuperados, para verificar exactitud del match
* 0 matches: mensaje de error
* 1 match: obtener id
* 2 o más matches: error?
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?
==== Archivos a modificar ====
=== biblio.fst ===
Modificar las líneas 9100 que generan claves de la forma ''_NAME_'':
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,
=== heading-match-in-bib-record.xis ===
El algoritmo sería algo como esto:
- Encontrar ID del encabezamiento
* Normalizar ''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)
* Ejecutar una búsqueda en la base de encabezamientos correspondiente (NAME, SUBJ), usando la expresión ''expr''
* Si no hay hits: error, abortar
* ''matches'' <- ''{}''
* Para cada encabezamiento ''H'' encontrado:
* si ''H'' coincide con ''query'': ''matches'' <- ''matches + {encabezamiento}''
* Si ''matches'' tiene cero o más de un elemento: error, abortar
* ''ID'' <- id del único encabezamiento en ''matches''
- Encontrar relaciones asociadas al encabezamiento
* ''relations'' <- ''{}''
* Para cada clave ''k'' del diccionario BIBLIO entre ''_NAME__---'' y ''_NAME__zzz'':
* ''relations'' <- ''relations'' + {los 3 caracteres finales de ''k''}
- Encontrar y procesar los registros bibliográficos
* Para cada relación ''rel'' en ''relations'':
* Ejecutar una búsqueda en BIBLIO, usando como expresión ''_NAME__''
* Mostrar un encabezado con la relación, e.g. 'Editor' (excepto para "autor") (Para esto necesitamos una tabla que mapee códigos de relación a términos en el idioma de la interfaz)
* Mostrar los registros asociados a esa relación
== script ==
hacer algo a v2001
v2003
v3001
1002 Isis_Total
2001
if val(v1002) <> 1 then 'Quit' fi
if v1 = v2001 then v9 fi
9
BIBLIO
'_'v2003'_', v9, '_'
'_'v2003'_', v9, '_ZZZ'
1 Isis_Key
v1
1 Isis_Item
'Relación: ', right(v1, 3),'
'
BIBLIO
v1
1002 Isis_Total
'Total: ',v1002,'
'
==== Encabezamientos en el diccionario ====
Debemos prestar atención a la diferencia entre estas dos maneras de enviar encabezamientos a los diccionarios, según la base.
* ¿Por qué reciben tratamientos diferentes?
* ¿Qué uso damos a las claves en cada caso?
* ¿Podrían unificarse? Mejor aún: ¿para qué necesitaríamos seguir usando estas claves en la base BIBLIO, si vamos a recuperar por encabezamientos usando IDs?
=== NAME / SUBJ ===
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?
=== BIBLIO ===
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:
- Acortar: debido a la limitación que impone el diccionario de CDS/ISIS a la longitud de las claves, necesitamos quitarnos de encima caracteres no esenciales, como puntuación y algunos espacios
- Evitar conflictos con la sintaxis de búsqueda: espacios, paréntesis, símbolos ''+'' (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: [[http://www.loc.gov/catdir/pcc/naco/normrule.html|NACO Normalization]] (también disponible como [[http://www.oclc.org/research/researchworks/naco/default.htm|servicio en línea]]), quizás con alguna leve modificación para adaptarlo a necesidades propias del OpacMarc. Ver también el [[http://www.oclc.org/research/publications/archive/2006/naco-lrts.pdf|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.
===== Asuntos varios =====
¿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:
* ¿En qué funciones aparece el encabezamiento H? Hacer un ''keyrange'' en BIBLIO, ''from=_NAME__ to=_NAME__'' (¿y si quisiéramos averiguarlo sólo mirando NAME?)
* ¿En cuántos registros aparece el encabezamiento H desempeñando la función f? ''npost(['BIBLIO']'_NAME__')''; ejemplo: ''npost(['BIBLIO']'_NAME_12345_EDT')'' (función: editor)
===== Análisis de la base =====
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.
* Uso de subcampos para indicar relación:
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.)
* Detección de registros donde se ha omitido el uso de subcampos para indicar relación (ejemplo típico, resultados sólo aproximadamente válidos):
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
{{tag>opacmarc desarrollo}}