Record groups? We got your record groups!


While we don’t have the many millions of records that OCLC does (what, 60M+?), we do have a local database to play with, an extensible ILS, and the desire to do fun stuff like OCLC does. So, I wrote an xISBN clone while working on the open-ils.supercat OpenSRF application. Instead of grouping records into FRBR work-sets, we group records into OpenILS/Evergreen metarecords. That is the algorithm that works best for PINES, but the metarecord fingerprinting algorithm will soon be scriptable via server-side JavaScript (complete with DOM and XPath for processing MARCXML records), and we plan on creating a FRBR-ish version at some point based on that work.

One big advantage of our version is that it works using the live data we already have indexed, so there’s no need to create a specialized database that can get stale over time. In fact, every extension we write will work that way if at all possible.

I think it’s a pretty good example of an OpenSRF extension to OpenILS that a developer with a mild familiarity with the open-ils.storage server could create. I’ll be posting the code for the mod_perl handler that creates the XML version soon — all 10 lines that I expect it will take. Anyway, here’s the code:

sub oISBN {
	my $self = shift;
	my $client = shift;
	my $isbn = shift;

	throw OpenSRF::EX::InvalidArg ('I need an ISBN please')
		unless (length($isbn) >= 10);

	# Create a storage session, since we'll be making multiple requests.
	$_storage->connect;

	# Find the record that has that ISBN.
	my $bibrec = $_storage->request(
		'open-ils.storage.direct.metabib.full_rec.search_where.atomic',
		{ tag => '020', subfield => 'a', value => { like => $isbn.'%'} }
	)->gather(1);

	# Go away if we don't have one.
	return {} unless (@$bibrec);

	# Find the metarecord for that bib record.
	my $mr = $_storage->request(
		'open-ils.storage.direct.metabib.metarecord_source_map.search.source.atomic',
		$bibrec->[0]->record
	)->gather(1);

	# Find the other records for that metarecord.
	my $records = $_storage->request(
		'open-ils.storage.direct.metabib.metarecord_source_map.search.metarecord.atomic',
		$mr->[0]->metarecord
	)->gather(1);

	# Just to be safe.  There's currently no unique constraint on sources...
	my %unique_recs = map { ($_->source, 1) } @$records;
	my @rec_list = sort keys %unique_recs;

	# And now fetch the ISBNs for those records.
	my $recs = $_storage->request(
		'open-ils.storage.direct.metabib.full_rec.search_where.atomic',
		{ tag => '020', subfield => 'a', record => \@rec_list }
	)->gather(1);

	# We're done with the storage server session.
	$_storage->disconnect;

	# Return the oISBN data structure.  This will be XMLized at a higher layer.
	return
		{ metarecord => $mr->[0]->metarecord,
		  record_list => { map { ($_->record, $_->value) } @$recs } };
}
__PACKAGE__->register_method(
	method    => 'oISBN',
	api_name  => 'open-ils.supercat.oisbn',
	api_level => 1,
	argc      => 1,
	signature =>
		{ desc     => < <"		  DESC",
Returns the ISBN list for the metarecord of the requested isbn
		  DESC
		  params   =>
		  	[
				{ name => 'isbn',
				  desc => 'An ISBN.  Duh.',
				  type => 'string' },
			],
		  'return' =>
		  	{ desc => 'record to isbn map',
			  type => 'object' }
		}
);