Like most Indexdata products, Metaproxy is an incredibly useful, although damn near impenetrable, application.  I have been using it to manage our Z39.50 access in the project I’ve been working for the last year or so (Talis Aspire Digitised Content, if you’re interested).  Its purpose is two-fold: most importantly, it makes the Z39.50 services available via SRU (so we don’t need Z39.50 support in our apps themselves), and it also allows us to federate a bunch of library catalogs in one target, so we can get a cross-section of major libraries in one query.

For the last nine months or so, I’ve been using Metaproxy quite successfully, albeit in a very low-volume and tightly scoped context, without really understanding in the slightest idea how it works (as one tends to do with Indexdata-produced software) or what the configuration settings really did.  Despite the fact that we were pointing at a little less than twenty five Z39.50 targets, it just worked (after some initial trial and error) even though these targets made up a diverse cross-section of ILMSes (Voyager, Symphony, Aleph, Prism).  Granted, we’re only searching on ISBN and ISSN right now, but none of the currently existing catalogs required any special configuration.

There was a notable vendor that wasn’t represented, however.

Recently, TADC has gone from ‘closed pilot’ to ‘available for any institution to request a demo’.  A university recently requested a demo and when I added their Z39.50 target (which you will not be surprised to learn was the vendor that we hadn’t dealt with) to Metaproxy, I noticed I kept getting ‘invalid combination of attributes for index’ errors when I would try to do ISBN and ISSN queries via SRU (although, interestingly, not via Z39.50).

If you’re not familiar with queries in Z39.50, they have an incredibly opaque construction where every query element takes (up to) 6 ‘attributes':

  1. use
    which field you want to search: title, author, etc.
  2. relation
    =, >, <, exact, etc.
  3. position
    first in field, first in subfield, anywhere in field, etc.
  4. structure
    word, phrase, keyword, date, etc.
  5. truncate
    left, right, no truncation, etc.
  6. completeness
    incomplete subfield, complete subfield, complete field

So a query for ISBN=1234567890 in Prefix Query Format (PQF – what Z39.50 uses) would look like:

@attr 1=7 @attr 2=3 @attr 3=2 @attr 4=1 @attr 5=100 @attr 6=1 1234567890

To translate this, you refer to the Bib-1 attribute set, but to break it down, it’s saying: search the ISBN field for strings that start with ‘1234567890’ followed by a space (and possibly more characters) or the end of the field. Servers will often have default behavior on fields so you don’t, in practice, always have to send all 6 attributes (often you only need to send the use attribute), but accepted attributes combinations are completely at the discretion of the server.  The servers we were pointing at up until now were happy with @attr 1=7 @attr 2=3 1234567890

Since this is horribly arcane search syntax, CQL was developed to replace it.  To do the above query in CQL, all you need is:

bath.isbn = 1234567890

Where bath defines the context set (the vocabulary of fields), and isbn is the field to search (yes, I realize that the Bath context set is deprecated, but the Bibliographic context set requires index modifiers, which nobody supports, as far as I can tell).

However, to make this work in Metaproxy, you need a mapping to translate the incoming CQL to PQF to send to the Z39.50 server.  And this is where our demo instance was breaking down. When I changed the mapping to work with the newly added catalog, some (but not all!) of the existing catalogs would stop returning results for ISBN/ISSN queries. I needed a different configuration for them, which meant that I actually had to figure out how Metaproxy works.

Metaproxy’s documentation explains that it is basically made up of three components:

  • Packages

    A package is request or response, encoded in some protocol, issued by a client, making its way through Metaproxy, send to or received from a server, or sent back to the client.

    The core of a package is the protocol unit – for example, a Z39.50 Init Request or Search Response, or an SRU searchRetrieve URL or Explain Response. In addition to this core, a package also carries some extra information added and used by Metaproxy itself.

    Um, ok.  To be honest, I still don’t really understand what packages are.  They don’t seem to exist in the example configurations or at least in not ones I care about.

  • Routes

    Packages make their way through routes, which can be thought of as programs that operate on the package data-type. Each incoming package initially makes its way through a default route, but may be switched to a different route based on various considerations.

    Well, this seems to make sense, at least. A requests can be routed through certain paths. Check.

  • Filters

    Filters provide the individual instructions within a route, and effect the necessary transformations on packages. A particular configuration of Metaproxy is essentially a set of filters, described by configuration details and arranged in order in one or more routes. There are many kinds of filter – about a dozen at the time of writing with more appearing all the time – each performing a specific function and configured by different information.

    The word “filter” is sometimes used rather loosely, in two different ways: it may be used to mean a particular type of filter, as when we speak of “the auth_simple filter” or “the multi filter”; or it may be used to be a specific instance of a filter within a Metaproxy configuration.

    Ugh, well that’s clear as mud, isn’t it? But, ok, so these are the things that do what you want to happen in the route. The documentation for these is pretty spartan, as well (considering they’re supposed to do the bulk of the work), but maybe through some trial and error we can figure it out.

All of this is declared in an XML configuration file, here’s an example that comes supplied with Metaproxy’s sources.  In this file you have a metaproxy root element and under that you have a start tag where you declare the default route that every request goes through to begin with.

Generally, this is also where you’d declare your global-level filters.  Filters can be defined in two ways: with an id attribute that can called one or more times from within routes, or you can put a filter element directly in the route (probably without an id attribute) which can be thought of as being scoped locally to that route.

For the global filters, you put a filters element under your metaproxy root element under which there are one or more filter elements. These filter elements should have id and type attributes (the types are available here).  You would also define the behavior of your filter here.  Here’s an example of how we define our two different CQL to PQF mappings:

<filters>
  <filter id="default-cql-rpn" type="cql_rpn">
    <conversion file="../etc/cql2pqf.txt" />
  </filter>
  <filter id="other-cql-rpn" type="cql_rpn">
    <conversion file="../etc/other-cql2pqf.txt" />
  </filter>
</filters>

To call these filters from your route, you use an empty element with the refid attribute:

<filter refid="default-cql-rpn" />

Also under the metaproxy element is a routes tag. The routes element can have one or more route blocks. One of these needs to have an id that matches the route attribute in your start tag (i.e. your default route). All of the examples (I think) use the id ‘start’.

In your default route, you can declare your common filters, such as the HTTP listener for the SRU service. You can also log the incoming requests. Here’s an example:

<routes>
  <route id="start">
    <filter type="log">
      <message>Something</message>
    </filter>
    <filter refid="id-declared-for-filter-in-your-filters-block" />
    ...
  </route>
</routes>

The first filter element in that route is locally scoped, it can’t be called again. The second one calls a filter that was defined in your filters section. That same filter could, in theory, also be called by a different route, keeping the configuration file (relatively) DRY.

The filters happen sequentially.

It is in one of the locally scoped filters within a route where you’d define the settings of the databases you are proxying. The filter type for these is ‘virt_db’.

<route id="start">
  ...
  <filter type="virt_db">
    <virtual>
      <database>lc</database>
      <target>z3950.loc.gov:7090/voyager</target>
    </virtual>
  </filter>
  ...
</route>

It is at this point that you can branch into different routes so different databases can have different configurations. It would look something like:

<routes>
  <route id="start">
    ...
    <filter type="virt_db">
      <virtual>
        <database>lc</database>
        <target>z3950.loc.gov:7090/voyager</target>
      </virtual>
      <virtual route="otherdbroute">
        <database>otherdb</database>
        <target>example.org:210/otherdb</target>
      </virtual>
    </filter>
    ...
  </route>
  <route id="otherdbroute">
    <filter type="log">
      <message>Other DB route</message>
    </filter>
    <filter refid="other-cql-rpn" />
    ...
  </route>

It’s important to note here that the branched route will return to route where it was initiated after it completes, so if there are more filters declared after this route is called, they will be applied to this route, as well.

It’s also important to note (at least this is how things appear to work for me) that if a filter of the same type is called more than once for a particular route, only the first one seems to get applied. In our example above, you could apply the cql_rpn filters like this:

<routes>
  <route id="start">
    ...
    <filter type="virt_db">
      <virtual>
        <database>lc</database>
        <target>z3950.loc.gov:7090/voyager</target>
      </virtual>
      <virtual route="otherdbroute">
        <database>otherdb</database>
        <target>example.org:210/otherdb</target>
      </virtual>      
    </filter>
    <filter refid="default-cql-rpn" />
    ...
  </route>
  <route id="otherdbroute">
    <filter type="log">
      <message>Other DB route</message>
    </filter>
    <filter refid="other-cql-rpn" />
    ...
  </route>

In this case, requests for “lc” would have “default-cql-rpn” applied to them. Requests for “otherdb” would have “other-cql-rpn” applied to them, but they seem to ignore the “default-cql-rpn” filter that comes later (I, for one, found this extremely counter-intuitive). So rather than having your edge cases overwrite your default configuration, you set your edge cases first and then set a default for anything that hasn’t already had a particular filter applied to it.

Also somewhat counter-intuitively, if you’re searching multiple databases with a single query and the databases require different configurations, you configure it like this:

<routes>
  <route id="start">
    ...
    <filter type="virt_db">
      <virtual>
        <database>lc</database>
        <target>z3950.loc.gov:7090/voyager</target>
      </virtual>
      <virtual route="otherdbroute">
        <database>otherdb</database>
        <target>example.org:210/otherdb</target>
      </virtual>
      <virtual>
        <database>all</database>
        <target>z3950.loc.gov:7090/voyager</target>
        <target>example.org:210/otherdb</target>
      </target>  
    </filter>
    <filter type="multi">
      <target route="otherdbroute">example.org:210/otherdb</target>
    </filter>
    <filter refid="default-cql-rpn" />

    ...
  </route>
  <route id="otherdbroute">
    <filter type="log">
      <message>Other DB route</message>
    </filter>
    <filter refid="other-cql-rpn" />
    ...
  </route>

Since the route can’t be applied to the whole aggregate of databases (the other databases would fail), you declare the route for a particular target in a ‘multi’ filter. Again, I think this route would have to appear before the default-cql-rpn filter is called to work.

I hope this helps somebody. If nothing, else, it will probably help myself when I need to eventually remember how all of this works.

Here the steps I just took to install metaproxy (which requires yaz and yaz++) on Red Hat Enterprise Linux 6.2.  The reason for this exercise is because Indexdata’s RPMs don’t work for 6.2 (the versions of boost-devel and icu-devel they require seem to only be available in 5.5).  Since I expect Indexdata to eventually release 6.2 compatible RPMs, I installed all of this into /opt/local (so it’s easy to remove — of course, if you’re already using /opt/local, you might want to try somewhere else).  Also, this assumes you’ll put a metaproxy.xml in /opt/local/etc/metaproxy/, so keep that in mind.

  1. yum install boost boost-devel icu icu-devel libxml2 libxml2-devel gnutls gnutls-devel libxslt libxslt-devel gcc-c++ libtool
  2. Install yaz:
    1. wget http://ftp.indexdata.dk/pub/yaz/yaz-4.2.33.tar.gz
    2. tar -zxvf yaz-4.2.33.tar.gz
    3. cd yaz-4.2.33
    4. ./configure –prefix=/opt/local
    5. make
    6. make install
  3. Install yaz++
    1. wget http://ftp.indexdata.dk/pub/yazpp/yazpp-1.3.0.tar.gz
    2. tar -zxvf yazpp-1.3.0.tar.gz
    3. cd yazpp-1.3.0
    4. ./configure –prefix=/opt/local/ –with-yaz=/opt/local/bin
    5. make
    6. make install
  4. Install metaproxy
    1. wget http://ftp.indexdata.dk/pub/metaproxy/metaproxy-1.3.36.tar.gz
    2. tar -zxvf metaproxy-1.3.36.tar.gz
    3. cd metaproxy-1.3.36
    4. ./configure –prefix=/opt/local –with-yazpp=/opt/local/bin/
    5. make
    6. make install
  5. cd /opt/local
  6. mkdir etc; mkdir etc/metaproxy; mkdir etc/sysconfig
  7. Copy this gist as /etc/rc.d/init.d/metaproxy
  8. chmod 744 /etc/rc.d/init.d/metaproxy
  9. Copy this gist as /opt/local/etc/sysconfig/metaproxy
  10. chkconfig –add /etc/rc.d/init.d/metaproxy
  11. /etc/init.d/metaproxy start

There has been a lot of buzz and general “yeah, what he said!” following Pinboard’s Maciej Ceglowski’s post “The Social Graph is Neither” inspiring posts more directly in my particular field, such as Audrey Watters’ “Is there an ‘Education Graph’?“. “The Social Graph is Neither” is a fantastic read and both raise extremely good points, but something was nagging at me the whole time I read Ceglowski’s post and finally struck me when I was reading Watters’.

The problems that they raise do not point to a failure of the graph (be it social or educational), but rather the expectation that the graph they are looking at is supposed to be comprehensive.

When you start digging into RDF (which is related by virtue of being graph based), one of the things you have to learn to accept is the open world assumption. It is an extremely difficult leap for some people to make, this notion that you cannot know everything about a particular resource, that there could always be another fact around the corner, but it’s also a very freeing one. When I model the relationships between resources, I have to limit the number of the edges between the nodes for a variety of reasons: scope, scale, limits of my knowledge, limits of my domain, limits of my requirements, etc. The insistence on modeling all aspects of the graph (take Ceglowski’s XFN example, and its omission of “negative” properties) is bound to fail. There are simply an infinite number of edges to that graph. You supply the edges you need for your case.

But this is exactly why, in RDF (and XFN, and schema.org, etc.), we have vocabularies: it gives us the context to narrow the lens to specific problem domains. That your use case (how do I differentiate my ‘teacher’ from the person who actually ‘taught’ me) doesn’t mesh unambiguously with the set of properties you’re trying to use doesn’t mean the original vocabulary is flawed, it means you need to define new properties. The graph still applies, you’re just looking at the wrong edges. If you want to model the relationship to your ex-wife, make a vocabulary that defines these more complicated relationships, but don’t hold up XFN as an example of how the graph doesn’t exist. It’s not a part of XFN (and likely never will be), but its absence doesn’t mean the relationship does not or cannot exist. It just doesn’t exist in the view of the graph that you’re looking at.

Admittedly, new vocabularies aren’t easy (they need to be well thought out, adoption is non-trivial, etc.), but that’s mostly because describing the universe in an interoperable way is mind-boggingly complex and likely biased by particular environments, needs and worldviews.

All this said, I actually completely agree with what both Ceglowski and Watters are saying: relationships are hard to model and extremely contextual, possibly even within the same domain. But just because somebody else’s graph isn’t modeled to your satisfaction, it doesn’t mean that they (or graph-based models in general) are wrong. It just means it’s time for you to start building.

Ever since the Functional Requirements for Bibliographic Resources (FRBR) first came out, there has been plenty of debate and disagreement over how to actually implement them. The boundary between Work and Expression has long been a disputed zone, without even bringing up the murkiness of adaptations, copies, derivatives, translations and their ilk. It’s complicated business and the fact that we’re just now dipping our toes in this water, the debate and disagreement are only bound to amplify once we are creating this data in earnest.

And I’m here to argue that we’re (mostly) wasting our time.

To be clear, I am not here to bury FRBR, I’m just asking that we pay less attention to the (Group 1) Entities behind the curtain and focus instead on why we are interested in the FRBR entity model at all (hint: it’s the relationships between things).

As we explore how our metadata might work in Linked Data/RDF model, there is a lot of hand-wringing over the fact that our legacy data (MARC/AACR2) does not contain a lot of fidelity when it comes to modeling it as FRBR. We know we usually have the makings of a Manifestation in there and there are probably pieces of a Work (since we likely have creators, contributors and subjects) and bits of Expression (language, medium). Since RDF is built on the open world assumption, we don’t have to know everything about the Work or Expression to identify them and make assertions about them (granted, the less we know, the harder it is to reconcile them later, but that’s a different issue).

So, by way of example, let’s take a MARC record:

000 01209cam a2200313 i 450
001 344918
005 20090410163635.0
008 760528s1976 nyua j 001 0 eng
906 __ |a 7 |b cbc |c orignew |d 1 |e ocip |f 19 |g y-gencatlg
010 __ |a 76019078
020 __ |a 0671328026 (lib. bdg.) : |c $6.64
035 __ |9 (DLC) 76019078
040 __ |a DLC |c DLC |d DLC
042 __ |a lcac
043 __ |a n-us-la
050 00 |a E356.N5 |b L86
082 00 |a 973.5/239/0924
100 1_ |a Lyons, Grant.
245 10 |a Andy Jackson and the battles for New Orleans / |c by Grant Lyons ; illustrated by Paul Frame.
260 __ |a New York : |b J. Messner, |c c1976.
300 __ |a 96 p. : |b ill. ; |c 22 cm.
500 __ |a Includes index.
520 __ |a Traces the events preceding and during the Battle of New Orleans where Andrew Jackson led the American troops to a decisive victory over the British.
650 _0 |a New Orleans, Battle of, New Orleans, La., 1815 |v Juvenile literature.
600 10 |a Jackson, Andrew, |d 1767-1845 |x Juvenile literature.
650 _1 |a New Orleans, Battle of, New Orleans, La., 1815.
600 11 |a Jackson, Andrew, |d 1767-1845.
700 1_ |a Frame, Paul, |d 1913-1994.
991 __ |b c-GenColl |h E356.N5 |i L86 |t Copy 1 |w BOOKS

(Andy Jackson and the Battle for New Orleans)

and let’s draw out the FRBR Entities in RDF:


@prefix dcterms: <http://purl.org/dc/terms/> .
@prefix frbr: <http://vocab.org/frbr/core#> .
@prefix rdagr1: <http://RDVocab.info/Elements/> .
@prefix bibo: <http://purl.org/ontology/bibo/> .

<http://lccn.loc.gov/76019078>
a frbr:Manifestation;
bibo:isbn “0671328026”;
bibo:lccn “76019078”;
bibo:pages “96”;
dcterms:extent “22 cm.”;
rdagr1:statementOfResponsibility “by Grant Lyons ; illustrated by Paul Frame”;
frbr:embodimentOf _:expression1 .

_:expression1
a frbr:Expression;
dcterms:language <http://id.loc.gov/vocabulary/languages/eng>;
dcterms:format “text”;
frbr:embodiment <http://lccn.loc.gov/76019078>;
frbr:realizationOf _:work1 .

_:work1
a frbr:Work;
dcterms:title “Andy Jackson and the battles for New Orleans”;
dcterms:creator <http://viaf.org/viaf/48006744>;
dcterms:subject <http://id.loc.gov/authorities/subjects/sh85091385>, <http://id.loc.gov/authorities/names/n79088888>;
frbr:realization _:expression .

Note that I’m leaving a lot of things out, some for simple brevity, others because I simply have no idea what entity they belong to (copyright date? contributor – in this case, an illustrator?). I am also using Ian Davis’ original interpretation of FRBR in RDF because I can’t figure out how to express the simple “_:ex isExpressionOf _:wo” type relationships in the RDA vocabularies (maybe you can figure it out and please leave an example in the comments) and if I could even find the IFLA FRBR vocabulary, the URIs are so obtuse nobody would understand what I’m trying to say anyway.

But this little exercise raises quite a few red flags. For one thing, spreading our properties across resources like this automatically increases the complexity in actually being able to construct a query to find it (although no matter how you cut it, you will have to have some JOINs: the author, for example, should be its own resource). It also requires the existence of all of these entities to be present or the chain breaks. Leave out the Expression and we have no way to link from the Manifestation (where our edition information is) to the Work (where are title, authors and subjects are). Another glaring omission is that we still don’t really know what the thing is that we’re describing (although, again, that’s most likely my ignorance of FRBR and RDA).

Now, I have been told that implementing a model like this isn’t being done (or not done) for the convenience of developers, and that’s fair enough, but there is a larger and more fundamental problem here.

If I’ve been working in or around libraries for over 15 years and, more specifically, libraries and RDF for 4 years, and I am completely stumped and overwhelmed by trying to model this, how on earth do we really expect anybody else, that hasn’t been trained as a cataloger, to figure it out? What compounds the problem is that there (currently) aren’t any really good ways to link from the FRBR vocabularies to other simpler and more common vocabularies (like Bibliontology).

And this gets to the heart of my question. Do we really care about the Manifestation or the Expression or do we just want to know about the thing (a book, say, or an article) and the relationships between things (adaptations, copies, derivations, translations and their ilk). To put it another way, do we really need to model out all of FRBR to benefit from the data model?

About a year ago, I made a set of properties on open.vocab.org to help work around some of the problems I was having implementing FRBR in some of the work I was doing (modeling the Open Library as RDF, LinkedLCCN, etc.). The background is that I wanted to model, say, a book as a bibo:Book, which could have dcterms:creator, bibo:isbn, dcterms:language, etc. as properties attached to it. But this meant I couldn’t say the book was a frbr:Manifestation, because it also had properties of the Expression and Work on it. At the same time, I wanted to be able relate different editions of the same work together.

So I came up with what is now referred to as the commonThing properties:

The idea being that we know that my bibo:Book contains WEMI information, so why can’t we just imply the existence of the FRBR entities and then create our relationships between resources based on that?

For example, if you had _:book1 <ov:commonWork> _:book2, you are saying that these two books both share a common FRBR Work (they may also share other common entities, but the point is that you might not know that). _:book1 and _:book2 can be modeled as anything, that doesn’t matter. And, if the WEMI hierarchy ever does get modeled, you can use commonThing to link from _:book1 to its corresponding Manifestation with ov:commonManifestation.

I am not arguing that this is a perfect workaround for the conundrums that FRBR gives us (and Jakob Voss has come up with an alternative that he calls SOBR), but it begins guide the conversation away from the supremacy of FRBR Group 1 entities (for the record, I’m gung-ho for Group 2 and Group 3 entities) as our primary focus and more towards what we’re actually intended for these entities to do and mean.

I have been slowly taking the MARC codes lists and modeling them as linked data. I released a handful of them several months ago (geographic area codes, countries and languages) and have added more as I get inspired or have some free time. Most recently, I’ve added the Form of Item, Target Audience and Instruments and Voices terms.

The motivation behind modeling these lists is that they are extremely low-hanging fruit: they are controlled vocabularies that (usually) appear in the MARC fixed (or, at any rate, controlled) fields. What this means is that they should be pretty easy to link to from our source data. The identifiers are based on the actual code values in an effort to not actually have to look anything up when converting MARC into RDF.

I’ll go over each code list and explain what their function and how to link to them from MARC:

Geographic Area Codes

The purpose of these is a little vague:  they’re hard to classify as to what exactly they are; there are states (Tennessee), countries (India), continents (Europe), geographic features (Andes, Congo River, Great Rift Valley), areas or regions (Tropics, “Southwest, New” –whatever that means–, “Africa, French-speaking Equatorial“), hemispheres (Southern hemisphere), planets (Uranus) and then there are entries for things like “Outer Space” and “French Community” (which, as I understand it, is sort of the French analog to the British Commonwealth); in short, they are all over the map (literally).

I have modeled these things as wgs84:SpatialThings.  I don’t know if that is 100% appropriate (e.g. “French Community”) and am open to recommendations for other classes.  Given that they are somewhat hierarchical and are used to define the geographic “subject” of a work, it might be more appropriate to model them using SKOS.

The geographic area code is found in the MARC 043$a (which is a repeatable subfield in a non-repeatable field) and should be a 7 character string (although this may vary based on local cataloging practices).  Most codes will be much shorter than this: the specification requires right padding hyphens (“-“) to seven characters (“aa—–“).  To turn this into a MARC Codes URI, you’ll drop the trailing hyphens and append “#location”:

http://purl.org/NET/marccodes/gacs/aa#location

http://purl.org/NET/marccodes/gacs/n-us-md#location

I’m not sure what is actually the “best” property to use to link to these resources, but I have been using <http://purl.org/dc/terms/spatial> (although, admittedly, not consistently).  This would entail that these resources are also a <http://purl.org/dc/terms/Location> which is something I can live with.

Not all of the geographic area codes are linked to anything, but some are linked to the authorities at http://id.loc.gov/authorities/, dbpedia, geonames, etc.

Country Codes

These are a little more consistent than the geographic area codes, but they are definitely not all “countries”.  With a few exceptions (United States Misc. Caribbean Islands) they are actual “political entities”, with countries (Guatemala), and states/provinces/territories (Indiana, Nova Scotia, Gibraltar, Gaza Strip).

Like the geographic area codes, I’ve modeled these as wgs84:SpatialThings.

They can appear in several places in the MARC record:  they will almost always appear in the 008 in positions 15-17 as the “country of publication”.  If one code isn’t enough to convey the full story of the production of a particular resource (!), the code may also appear in the 044$a (repeatable subfield, non-repeatable field).  There are a couple of fields that the country codes could appear in:  the 535$g, 775$f and the 851$g; I have no idea how common it would be to find them there (and they have a different meaning — the 535/851 define the location of the item, for example).

To generate the country code URI, take the value from the MARC 008[15-17] or 044$a, strip any leading or trailing spaces and append “#location”.  The URIs look like:

http://purl.org/NET/marccodes/countries/aw#location

http://purl.org/NET/marccodes/countries/sa#location

To link to these resources, I’ve been using the RDA:placeOfPublication property, although I’m sure there are plenty of others that are appropriate (seems like a logical property for BIBO, for example).

The original code lists are also grouped by region, but there are no actual codes for this.  I created some for the purposes of linked data:

http://purl.org/NET/marccodes/countries/regions/1#location

http://purl.org/NET/marccodes/countries/regions/2#location

etc. (until 12).

Since we only use the country codes in MARC to note the place of publication, these are far less valuable than the geographic area codes (which are much more ambiguous in meaning), since it’s much more interesting when you can say that all of these things:

http://api.talis.com/stores/rsinger-dev4/services/sparql?query=SELECT+%3Fs%0D%0AWHERE+{%0D%0A%3Fs+%3Fp+%3Chttp%3A%2F%2Fpurl.org%2FNET%2Fmarccodes%2Fgacs%2Fe-ie%23location%3E%0D%0A}&output=json

are referring to the same place as all of these things:

http://dbpedia.org/sparql?default-graph-uri=http%3A%2F%2Fdbpedia.org&should-sponge=&query=select+distinct+%3Fs+where+%0D%0A{%3Fs+%3Chttp%3A%2F%2Fdbpedia.org%2Fontology%2Fcountry%3E+%3Chttp%3A%2F%2Fdbpedia.org%2Fresource%2FIreland%3E}&debug=on&timeout=&format=text%2Fhtml

which, in turn, are referring to the same place as this:

http://www.freebase.com/view/en/ireland/-/book/book_subject/works

which, in my mind, has tremendous potential.

Language Codes

Unbeknownst to me prior to undertaking this project, the Library of Congress is actually the maintenance agency for ISO 639-2 and the ISO codes are actually a derivative of the MARC codes list.  They aren’t actually a 1:1 mapping (there are 22 codes that are different in the ISO list), but they’re extremely close.  What is particularly nice about this is that most locale/language libraries are aware of these codes so it’s fairly easy to map to other locales (notably ISO 639-1, which is used by xml:lang).

The Library of Congress publishes an XML version of the list which is what I used to model it as linked data.  One of the nice features of this list was that it has attributes on the name that denote whether or not there’s an authority record for it:

<name authorized=”yes”>Abkhaz</name>

which we can then take, tack the substring ” language” onto it and look it up in http://id.loc.gov/authorities:

http://id.loc.gov/authorities/sh85000169#concept

giving us a link between things created in a particular language and things created about that language.

To use the language codes, take the value of positions 35-37 of the 008 or the 041 (the different subfields all define a different place the text might have a different language, so check the spec on this one).  I doubt it hardly ever appears in actual data, but the 242$y might have the language of the translated title.

Take that value (be sure to strip any trailing/leading whitespace — it’s supposed to be 3 characters: no more, no less) and plug it into the following URI template:

http://purl.org/NET/marccodes/languages/{abc}#lang

for example:

http://purl.org/NET/marccodes/languages/tur#lang

http://purl.org/NET/marccodes/languages/myn#lang

etc.

The language resources link to id.loc.gov (as mentioned above) as well as Lingvoj/Lexvo (they link to both, where appropriate, since there are likely still many data sources out there still using the Lingvoj URIs).  There are a handful (for example, Swedish) that link to dbpedia, but since those links are available in Lexvo, it’s not essential they appear here.

Musical Composition Codes

There are two codes lists that are directly related to music-based resources (sound recordings, scores and video): the musical composition codes and the Instruments and Voices codes.  Given that there has been a lot of work put into modeling music data for the linked data cloud, I thought it would be most useful to orient both of these lists to be used with the Music Ontology.

The composition codes basically denote the “genre” of the music contained in the resource.  It’s extremely classical-centric and sometimes lumps a lot of different forms into one genre code (try Divertimentos, serenades, cassations, divertissements, and notturni on for size), but they are definitely a start for finding like resources.

They are modeled as mo:Genre resources and include links to id.loc.gov, dbpedia and wikipedia.  To get the code, either use positions 17-19 of the MARC 008 field or the 047$a (both a repeating field and subfield).  The normalized code should always be two alpha characters long, and downcased.

They go into a URI template like:

http://purl.org/NET/marccodes/muscomp/{ab}#genre

such as:

http://purl.org/NET/marccodes/muscomp/sy#genre

or

http://purl.org/NET/marccodes/muscomp/mz#genre

It would be really useful to find other datasources that use mo:Genre to link these to.

Form of Item Codes

This is a very small list that broadly describes the format of the resource being described.  This is probably most useful to use with dcterms:format, so they’ve all been modeled with the rdf:type dcterms:MediaType.  A full third of the codes describe microforms (granted, out of 9 total), which should give you some some sense of how relevant these are.

Getting the code from the MARC record is dependent on the kind of record you’re looking at.  For books, serials, sound recordings, scores, computer files and mixed materials, take the 23rd position from the 008.  For visual materials and maps use the 29th position.  They should be one, lowercase alpha character.

URIs look like:

http://purl.org/NET/forms/{a}#form

The resources link to http://id.loc.gov/authorities (think Genre/Form terms), http://id.loc.gov/vocabulary/graphicMaterials and (for a couple) dbpedia.

Ideally, these will eventually link to whatever is analogous is RDA (if somebody can point that out to me).

Frequency of Issue Codes

Unlike the previous code list, this one seems much more useful.  It is used to define how often a continuing resource is updated.  Unfortunately, it is extremely print-centric (the only term more frequent than “daily” is “Continuously updated” which is defined as “Updated more frequent than daily.”), but some of the terms would seem to hold value even outside of the library context (Annual, Biweekly, Quarterly, etc.).  It doesn’t take a tremendous leap of the imagination see how these might be useful for events calendars (Monthly, etc.) or for GoodRelations-type datasets (“Semi-annual Blowout Sale!”).

To get the code from the MARC record, check the 008[18] or the 853-855$w.  Presumably, this should only appear for continuing resources (SER).  It’s a one letter code, lower cased.

The URIs look like:

http://purl.org/NET/marccodes/frequency/{x}#term

They are modeled as dcterms:Frequency resources and link to dbpedia where available.

Target Audience Codes

This is another fairly short, extremely generalized list.  It is primarily useful to determining the age-level of children’s resources, most likely (5 of the 8 terms are for juvenile age groups).  They are of rdf:type dcterms:AgentClass.  Resources are linked (where appropriate — and maybe even a few that aren’t) to dbpedia and http://id.loc.gov/authorities/.

For books, music (scores, sound recordings), computer files and visual materials, get the code from the 008[22].  It is one letter, lower cased.  URIs follow the fairly consistent form we’ve seen thus far:

http://purl.org/NET/marccodes/target/{x}#term

http://purl.org/NET/marccodes/target/c#term

http://purl.org/NET/marccodes/target/f#term

Instruments and Voices Codes

The terms describe the instruments or vocal groups that either appear (for sound recordings, for example) or are intended (scores) for a particular resource.  Like many of the other codes lists, these are quite general and maddeningly biased towards classical music (Continuo, Celeste, Viola d’amore, but no banjo or sitar, for instance).  Like the form of musical composition terms, I modeled these to use with the Music Ontology, namely as the object of mo:instrumentmo:Instrument has this note:

Any taxonomy can be used to subsume this concept. The default one is one extracted by Ivan Herman
from the Musicbrainz instrument taxonomy, conforming to SKOS. This concept holds a seeAlso link
towards this taxonomy.

so these terms have been modeled as skos:Concepts.  There are skos:exactMatch relationships to the Musicbrainz taxonomy where appropriate (as well as links to id.loc.gov/authorities and dbpedia).  The original code lists had an implication of hierarchy (“Larger ensemble – Dance orchestra” should be thought of as “Dance orchestra” with broader term “Larger ensemble”), but that’s not actually used in MARC.  I broke these broader terms out on their own for this vocabulary, since it seemed useful in a linked data context and wouldn’t actually hurt anything (the codes are two letters, so the “broader terms” are just using the first letter).

To get the code, use the MARC 048 subfield a or b (for ensemble or solo parts, respectively) and take the first two characters (which must be letters).  This code may be followed by two digit number (left padded with zeroes) signifying how many parts.  Drop this number, if present.

URI template:

http://purl.org/NET/marccodes/musperf/{xx}#term

http://purl.org/NET/marccodes/musperf/cd#term

http://purl.org/NET/marccodes/musperf/ed#term

Other Codes

I am not sure when or if I will model any more codes lists.  Ideally, the Library of Congress should be doing these (they’ve done the relator codes, and preservation events lists).  The only other lists I can see much value in are the Specific Material Form Terms (the MARC 007) and the MARC Organization codes.

I have done a bit of work on the specific material forms list, but it’s fairly complicated.  My current approach is a hybrid of controlled vocabularies and RDF schema (after all, it makes sense for a globe to be rdf:type <http://purl.org/NET/marccodes/smd/terms/Globe> rather than that be some property set on an untyped resource).  For an RDF schema, though, I would prefer a “better” namespace than purl.org/NET/, although perhaps it doesn’t really matter much.

No matter what, it would certainly push the limits of my freebie Heroku account that this is currently running on.

I am definitely open to any ideas or recommendations people might have for these (and requests for other lists to be converted).  I’d also be interested to see if are able to use them with your data.

Note: to see the backstory and justification of this proposal, please see the preceding post.

MARC-in-JSON is a proposed JSON schema for representing MARC records as JSON. It is the outgrowth of working with MARC data in MongoDB and is intended to be both a faithful representation of MARC as well as a logical and useful model to work natively in JSON-centric environments. Ideally, this serialization could eventually replace binary MARC as the default format. The round trip of a MARC-in-JSON record from MARC to JSON back to MARC is lossless and preserves field/subfield order.

An example MARC bibliographic record, represented as text:

LEADER 01471cjm a2200349 a 4500
001 5674874
005 20030305110405.0
007 sdubsmennmplu
008 930331s1963 nyuppn eng d
035 $9 (DLC) 93707283
906 $a 7 $b cbc $c copycat $d 4 $e ncip $f 19 $g y-soundrec
010 $a 93707283
028 02 $a CS 8786 $b Columbia
035 $a (OCoLC)13083787
040 $a OClU $c DLC $d DLC
041 0 $d eng $g eng
042 $a lccopycat
050 00 $a Columbia CS 8786
100 1 $a Dylan, Bob, $d 1941-
245 14 $a The freewheelin' Bob Dylan $h [sound recording].
260 $a [New York, N.Y.] : $b Columbia, $c [1963]
300 $a 1 sound disc : $b analog, 33 1/3 rpm, stereo. ; $c 12 in.
500 $a Songs.
511 0 $a The composer accompanying himself on the guitar ; in part with instrumental ensemble.
500 $a Program notes by Nat Hentoff on container.
505 0 $a Blowin' in the wind -- Girl from the north country -- Masters of war -- Down the highway -- Bob Dylan's blues -- A hard rain's a-gonna fall -- Don't think twice, it's all right -- Bob Dylan's dream -- Oxford town -- Talking World War III blues -- Corrina, Corrina -- Honey, just allow me one more chance -- I shall be free.
650 0 $a Popular music $y 1961-1970.
650 0 $a Blues (Music) $y 1961-1970.
856 41 $3 Preservation copy (limited access) $u http://hdl.loc.gov/loc.mbrsrs/lp0001.dyln
952 $a New
953 $a TA28
991 $b c-RecSound $h Columbia CS 8786 $w MUSIC

The same bibliographic record serialized as MARC-in-JSON would appear as follows (pretty-printed with whitespace and line breaks for readability):

{
    "leader":"01471cjm a2200349 a 4500",
    "fields":
    [
        {
            "001":"5674874"
        },
        {
            "005":"20030305110405.0"
        },
        {
            "007":"sdubsmennmplu"
        },
        {
            "008":"930331s1963    nyuppn              eng d"
        },
        {
            "035":
            {
                "subfields":
                [
                    {
                        "9":"(DLC)   93707283"
                    }
                ],
                "ind1":" ",
                "ind2":" "
            }
        },
        {
            "906":
            {
                "subfields":
                [
                    {
                        "a":"7"
                    },
                    {
                        "b":"cbc"
                    },
                    {
                        "c":"copycat"
                    },
                    {
                        "d":"4"
                    },
                    {
                        "e":"ncip"
                    },
                    {
                        "f":"19"
                    },
                    {
                        "g":"y-soundrec"
                    }
                ],
                "ind1":" ",
                "ind2":" "
            }
        },
        {
            "010":
            {
                "subfields":
                [
                    {
                        "a":"   93707283 "
                    }
                ],
                "ind1":" ",
                "ind2":" "
            }
        },
        {
            "028":
            {
                "subfields":
                [
                    {
                        "a":"CS 8786"
                    },
                    {
                        "b":"Columbia"
                    }
                ],
                "ind1":"0",
                "ind2":"2"
            }
        },
        {
            "035":
            {
                "subfields":
                [
                    {
                        "a":"(OCoLC)13083787"
                    }
                ],
                "ind1":" ",
                "ind2":" "
            }
        },
        {
            "040":
            {
                "subfields":
                [
                    {
                        "a":"OClU"
                    },
                    {
                        "c":"DLC"
                    },
                    {
                        "d":"DLC"
                    }
                ],
                "ind1":" ",
                "ind2":" "
            }
        },
        {
            "041":
            {
                "subfields":
                [
                    {
                        "d":"eng"
                    },
                    {
                        "g":"eng"
                    }
                ],
                "ind1":"0",
                "ind2":" "
            }
        },
        {
            "042":
            {
                "subfields":
                [
                    {
                        "a":"lccopycat"
                    }
                ],
                "ind1":" ",
                "ind2":" "
            }
        },
        {
            "050":
            {
                "subfields":
                [
                    {
                        "a":"Columbia CS 8786"
                    }
                ],
                "ind1":"0",
                "ind2":"0"
            }
        },
        {
            "100":
            {
                "subfields":
                [
                    {
                        "a":"Dylan,
                         Bob,
                        "
                    },
                    {
                        "d":"1941-"
                    }
                ],
                "ind1":"1",
                "ind2":" "
            }
        },
        {
            "245":
            {
                "subfields":
                [
                    {
                        "a":"The freewheelin' Bob Dylan"
                    },
                    {
                        "h":"
                        [
                            sound recording
                        ]
                        ."
                    }
                ],
                "ind1":"1",
                "ind2":"4"
            }
        },
        {
            "260":
            {
                "subfields":
                [
                    {
                        "a":"
                        [
                            New York,
                             N.Y.
                        ]
                         :"
                    },
                    {
                        "b":"Columbia,
                        "
                    },
                    {
                        "c":"
                        [
                            1963
                        ]
                        "
                    }
                ],
                "ind1":" ",
                "ind2":" "
            }
        },
        {
            "300":
            {
                "subfields":
                [
                    {
                        "a":"1 sound disc :"
                    },
                    {
                        "b":"analog,
                         33 1/3 rpm,
                         stereo. ;"
                    },
                    {
                        "c":"12 in."
                    }
                ],
                "ind1":" ",
                "ind2":" "
            }
        },
        {
            "500":
            {
                "subfields":
                [
                    {
                        "a":"Songs."
                    }
                ],
                "ind1":" ",
                "ind2":" "
            }
        },
        {
            "511":
            {
                "subfields":
                [
                    {
                        "a":"The composer accompanying himself on the guitar ; in part with instrumental ensemble."
                    }
                ],
                "ind1":"0",
                "ind2":" "
            }
        },
        {
            "500":
            {
                "subfields":
                [
                    {
                        "a":"Program notes by Nat Hentoff on container."
                    }
                ],
                "ind1":" ",
                "ind2":" "
            }
        },
        {
            "505":
            {
                "subfields":
                [
                    {
                        "a":"Blowin' in the wind -- Girl from the north country -- Masters of war -- Down the highway -- Bob Dylan's blues -- A hard rain's a-gonna fall -- Don't think twice,
                         it's all right -- Bob Dylan's dream -- Oxford town -- Talking World War III blues -- Corrina,
                         Corrina -- Honey,
                         just allow me one more chance -- I shall be free."
                    }
                ],
                "ind1":"0",
                "ind2":" "
            }
        },
        {
            "650":
            {
                "subfields":
                [
                    {
                        "a":"Popular music"
                    },
                    {
                        "y":"1961-1970."
                    }
                ],
                "ind1":" ",
                "ind2":"0"
            }
        },
        {
            "650":
            {
                "subfields":
                [
                    {
                        "a":"Blues (Music)"
                    },
                    {
                        "y":"1961-1970."
                    }
                ],
                "ind1":" ",
                "ind2":"0"
            }
        },
        {
            "856":
            {
                "subfields":
                [
                    {
                        "3":"Preservation copy (limited access)"
                    },
                    {
                        "u":"http://hdl.loc.gov/loc.mbrsrs/lp0001.dyln"
                    }
                ],
                "ind1":"4",
                "ind2":"1"
            }
        },
        {
            "952":
            {
                "subfields":
                [
                    {
                        "a":"New"
                    }
                ],
                "ind1":" ",
                "ind2":" "
            }
        },
        {
            "953":
            {
                "subfields":
                [
                    {
                        "a":"TA28"
                    }
                ],
                "ind1":" ",
                "ind2":" "
            }
        },
        {
            "991":
            {
                "subfields":
                [
                    {
                        "b":"c-RecSound"
                    },
                    {
                        "h":"Columbia CS 8786"
                    },
                    {
                        "w":"MUSIC"
                    }
                ],
                "ind1":" ",
                "ind2":" "
            }
        }
    ]
}

The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in IETF RFC 2119.

MARC-in-JSON records MUST conform to the following JSON schema:

{
    "description":"A MARC Record",
    "type": "object",
    "properties": {
        "leader": {
            "type": "string",
            "minLength": 24,
            "maxLength": 24
        },
        "fields": {
            "type": "array",
            "items": {
                "type":[
                    {
                        "type": "object",
                        "description":"A MARC Control Field",
                        "additionalProperties":{
                            "type":"string"
                        }
                    },
                    {
                        "type": "object",
                        "additionalProperties":{
                            "type":"object",
                            "description":"A MARC Variable Field",
                            "properties":{
                                "ind1":{
                                    "type":"string",
                                    "minLength":1,
                                    "maxLength":1
                                },
                                "ind2":{
                                    "type":"string",
                                    "minLength":1,
                                    "maxLength":1
                                },
                                "subfields":{
                                    "type":"array",
                                    "items":{
                                        "type":"object",
                                        "description":"A MARC Subfield",
                                        "additionalProperties":{
                                            "type":"string"
                                        }
                                    }
                                }
                            }
                        }
                    }
                    ]
                },
            "additionalProperties": false
        }
    },
    "additionalProperties": false
}

Download this schema.

MARC-in-JSON consists of four (4) object types:

Record objects
The base representation of the MARC record. It MUST be a JSON object with two properties:

  • leader, which MUST be a string, exactly 24 characters in length.
  • fields, an array which MUST only contain control field and variable field objects.

Record objects MAY be contained in a JSON array.

Control field objects
MARC control fields MUST be represented as a JSON object with a single key/value pair. The key MUST be a string conforming to a valid MARC field tag value (generally three alphanumeric characters). The value of the object MUST be a string.
Variable field objects
Variable fields MUST be represented as JSON objects with a single key/value pair. The key MUST be a string conforming to a valid MARC field tag value (generally three alphanumeric characters). The value of the object MUST be a JSON object with three properties:

  • ind1: a one (1) character string representing the 1st MARC field indicator
  • ind2: a one (1) character string representing the 2nd MARC field indicator
  • subfields: an array containing at least one subfield object
Subfield objects
MARC subfields MUST be represented as JSON objects with a single key/value pair. The key MUST be a string conforming to a valid MARC subfield code value (generally a single alphanumeric character). The value MUST be a string representing the value of the subfield. A subfield object MUST only appear in a variable field object subfields array.

The content of a MARC-in-JSON object MUST be UTF-8 encoded or UTF-8 escaped according to the JSON standard (RFC 4627).  MARC-8, UTF-16 or UTF-32 SHALL NOT be permitted under MARC-in-JSON.

There are currently two implementations conforming to this specification for serialization:

Note: this post is broken into two parts. If you are just interested in the MARC-in-JSON technical specification proposal, look here. If you’re interested in the justification and history of it, read on.

The easy and obvious reaction to the suggestion of providing new serializations to MARC is to reach for Roy Tennant’s suggestion and ask for its head. Let’s face it, though, MARC is going nowhere soon and we have yet to produce a truly lossless alternative format. With the rise of JSON as the generally preferred means of communication between machines on the web, it was only a matter of time before the proposals for a standardized way to serialize MARC as JSON began to materialize.

So far we have two well-publicized suggestions: one by Bill Dueber, at the University of Michigan; and one by Andrew Houghton, who works at OCLC Research. They are quite different and each have their advantages and disadvantages. The tricky part of representing MARC in JSON is preserving field and subfield order: simply representing an object (hash, associative array, dictionary, map, hashtable, etc.) will not do the trick (despite being the most programmatically friendly) since it would be impossible to ensure a round trip from MARC to JSON back into an identical MARC record. Instead, we need to make some compromises (which both proposals do), which is not entirely unexpected with a 40 year old standard.

Let me explain a bit about each proposal, starting with Bill’s.

Bill takes the approach that JSON would more or less simply be used for transmission: it is optimized to serialize and parse very quickly. It is, however, not a a terribly friendly format to work with natively. A MARC-HASH record is basically a hash with arrays of arrays representing the fields and subfields, with the hash providing administrative data (version, type) and the leader. The fields key contains the array of arrays. These arrays either have two values (for control fields) or four (for data fields) with the last value being an array of subfields (which are also two value arrays). The first value in these arrays is always the MARC tag. For data fields, the second and third values are the indicators. For control fields the second value is the field value.

Here’s an example, provided by Bill:

{
    "type" : "marc-hash",
    "version" : [1, 0],

    "leader" : "leader string"
    "fields" : [
       ["001", "001 value"]
       ["002", "002 value"]
       ["010", " ", " ",
        [
          ["a", "68009499"]
        ]
      ],
      ["035", " ", " ",
        [
          ["a", "(RLIN)MIUG0000733-B"]
        ],
      ],
      ["035", " ", " ",
        [
          ["a", "(CaOTULAS)159818014"]
        ],
      ],
      ["245", "1", "0",
        [
          ["a", "Capitalism, primitive and modern;"],
          ["b", "some aspects of Tolai economic growth" ],
          ["c", "[by] T. Scarlett Epstein."]
        ]
      ]
    ]
  }

By putting all of the field data in nested arrays, a client would have to loop through every array to find specific fields. This isn’t difficult, of course, it’s just not terribly friendly.

Andrew’s approach is modeled after MARCXML. A record is represented by an object with three attributes: leader (string), controlfield (array), and datafield (array). The controlfields are represented as objects with two keys: tag (string) and data (string). Datafields have three keys: tag (string), ind (string for both indicators) and subfield (array). The subfield array contains objects with two keys: code (string) and data (string).

By replicating MARCXML, Andrew’s proposal should be pretty recognizable to anyone that’s familiar with MARC. Bill’s concept is going to be incredibly fast to serialize and parse. Unfortunately, I don’t think either of them is particularly good JSON (Andrew’s model is, of course, further hampered by the fact that MARCXML isn’t particularly good XML). As JSON becomes a first class citizen on the web, with libraries (JSONPath) and datastores (MongoDB, CouchDB, Persevere) specialized for it, it seems as though a MARC-in-JSON format should not only be good MARC, but good JSON, too.

This led to me to develop yet another way to serialize MARC as JSON. While JSONPath or MongoDB, by themselves, aren’t realistic functional requirements (since neither is “standard” in any way), they do represent how people that are seriously using JSON expect it work. If JSONPath is superceded by some other XPath-analogous-y means of traversing and searching a JSON data structure, it will likely contain many similarities to JSONPath, which is similar (although not identical) to XPath. These technologies indicate that people are looking at JSON as a first class data structure of its own and not just for simply passing data around that’s simple to serialize and parse into other forms.

And, so, with that backstory in place, proceed to my proposal to represent MARC in JSON.

There are any number of reasons that you can attribute to Solr‘s status as the standard bearer of faceted full-text searching:  it’s free, fast, works shockingly well out of the box without any tweaking, has a simple and intuitive HTTP API (making it available in the programming language of your choice) and is, by far, the easiest “enterprise-level” application to get up and running.  None of its “competitors” (Sphinx, Xapian, Endeca, etc.), despite any individual advantages they might have, can claim all of these features, which goes a long way towards explaining Solr’s popularity.

The library world has definitely taken a shine to Solr:  from discovery interfaces like VuFind and Primo, to repositories like Fedora, to full-text aggregators like Summon, you can find Solr under the hood of most of the hot products and services available right now.  The fact that a library can install VuFind and have a slick, jaw-droppingly powerful OPAC-replacement that puts their legacy interface to shame in about an hour is almost completely the by-product of Solr’s amazing simplicity to get up and running.  It’s no wonder why so many libraries are adopting it (compare it to SOPAC, also built in PHP and about as old, but uses Sphinx for the full-text indexing and is hardly ever seen in the wild).

Without a doubt, Solr is pretty much a no-brainer if you are able to run Jetty (or Tomcat or JBoss or Glassfish or whatever):  with enough hardware, Solr can scale up to pretty much whatever your need might be.  The problem (at least the problem in my mind) is that Solr doesn’t scale down terribly well.  If you host your content from a cheap, shared web hosting provider or a VPS, for example, Solr is not available or not practical (it doesn’t live in small memory environments well).  The hosted Solr options are fairly expensive and while there are cheap, shared web hosting providers that do provide Java Application Servers, switching vendors to provide faceted search for your mid-size Drupal or Omeka site might not be entirely practical or desirable.

I find myself proof-of-concept-ing a lot of hacks to projects like VuFind, Blacklight, Kochief and whatnot and run these things off of my shared web server.  It’s older, underpowered and only has 1GB of RAM.  Since I’m not running any of these projects in production (just really making things available for others to see), it was really annoying to have Solr gobbling up 20% of the available RAM for these little pet projects.  What I wanted was something that acted more or less like Solr when you pointed an application that expected Solr to be there, but I wanted it to have a small footprint that could run (almost) anywhere and more or less disappear when it was idle.

So it was for this scenario that I wrote CheapSkate: a Solr emulator written in Ruby.  It uses Ferret, the Ruby port of Lucene, as the full-text indexing engine and Sinatra to supply the HTTP API.  Ferret is fast, scales quite well and responds to the same search syntax as Solr, so I knew it could handle the search aspect pretty easily.  Faceting (as can be expected) proved the harder part.  Originally, I was storing the values of fields in an RDBMS and using that to provide the facets.  Read performance was ok, although anything over 5,000 results would start to bog down – the real problem was the write performance, which was simply woeful.  Part of the issue was that this design was completely schemaless:  you could send anything to CheapSkate and facet on any field, regardless of size.  It also tried to maintain the type of the incoming field value:  dates were stored as dates, numbers stored as integers and so on.  Basically the lack of constraints made it wildly inefficient.

Eventually, I dropped the RDBMS component, and started playing around Ferret’s terms capabilities.  If you set a particular field to be untokenized, your field values appear exactly as you put them in.  This is perfect for faceting (since you don’t want stemming and whatnot on your query filters and your strings aren’t normalized or downcased or anything so they look right in the UI) and is basically the same thing Solr itself does.  Instead of a schema.xml, CheapSkate has a schema.yml, but it works essentially the same way:  you define your fields, what should be tokenized (that is, which fields allow full-text search) or not (i.e. facet fields) and what datatype the field should be.

CheapSkate doesn’t support all of the field types that Solr does, but it supports strings, numbers, dates and booleans.

One neat thing about Ferret is that you can pass a Ruby Proc to the search method as a search option.  This proc then has access to the search results as Ferret is finding them.  CheapSkate uses this find the terms in the untokenized fields for each search hit, throws them in a Hash and generates a hit count for each term.  This is a lot faster than getting all the document ids from the search, looping them and generating your term hash after the search is completed.  That said, this is still definitely the bottleneck for CheapSkate.  If the search result has more than 10-15,000 hits, performance begins to get pretty heavily impacted by grabbing the facets.  I’m not terribly concerned by this, data sets with search results in the 20,000+ range start to creep into the “you would be better off just using Solr” domain.  For my proofs-of-concepts, this has only really raised its head in VuFind when filtering on something like “Book” (with no search terms) for a 50,000 record collection.  What I mean to say is, this happens for fairly non-useful searches.

Overall, I’ve been pretty happy with how CheapSkate is working.  For regular searching it does pretty well (although, like I said, I’m not trying to run a production discovery system that pleases both librarians and users).  There’s a very poorly designed “more like this” handler that really needs an overhaul and there is no “did you mean” (spellcheck).  This hasn’t been a huge priority, because I don’t really like the spellcheck in Solr all that much, anyway.  That said, if somebody really wanted this and had an idea of how it would be implemented in Ferret, I’d be happy to add it.

Ideally, I’d like to see something like CheapSkate in PHP using Zend_Search_Lucene, since that would be accessible to virtually everybody, but that’s a project for somebody else.

In the meantime, if you want to see some examples of CheapSkate in action:

One important caveat to projects like VuFind and Blacklight:  CheapSkate doesn’t work with Solrmarc, which requires Solr to return responses in the javabin format (which may be possible to hack out something that looks enough like javabin to fool Solrmarc, I just haven’t figured it out).   My workaround has been to populate a local Solr index with Solrmarc and then just dump all of the documents out of Solr into CheapSkate.

I’ve been accused of several things in the Linked Data community this week:  a circular reasoner, a defender of the status quo “just because that’s how we’ve always done it”, and (implicitly) an httpRange-14 apologist.  Quite frankly, none of these are true or quite what I mean (and I’m, of course, over dramatizing the accusations), but let’s focus on the last point for now (which may clear up some of the other points, as well).

Ed’s post (as he explains at the end) is a reference to me calling bullshit on his claim that “[he] think[s] httpRange-14 is an elaborate scholarly joke“.  Let me be clear from the outset that I am not particularly dogmatic on this issue.  That is, I don’t think the internet will break if the resource and carrier are conflated, but I also don’t think it’s that hard to keep them separated and that the value in doing so outweighs any perceived costs.

First off, let me explain what httpRange-14 is to the uninitiated (skip on ahead if you feel pretty comfortable with this).  In linked data (or semantic web, you can choose the words that feel best to you), we run into a problem with identifiers and what, exactly, they are identifying.  Let’s say I want to talk about Chattanooga.  Well, “Chattanooga” is not a web resource, but if I want talk about it unambiguously, it needs an identifier, preferably an HTTP URI, so other people can refer to it unambiguously and say things about it and discover it.  Ideally, this web representation would also have human readable (HTML) and machine readable (RDF, XML, etc.) versions.  But the important distinction here is that the city of Chattanooga cannot be retrieved on the web, only these HTML, RDF, XML surrogates.  If the surrogate has the same URI (identifier) as the resource it’s describing it starts to get difficult to figure out what we’re talking about.

So to try to make this a little clearer, let’s say I am making this representation of Chattanooga for people to use:

<http://dilettantes.code4lib.org/resources/Chattanooga_Tennessee.rdf>
    rdf:type <http://www.geonames.org/ontology#P.PPL> ;
    <http://www.geonames.org/ontology#population> "155554"^^xsd:integer.

But I also feel I need to let people know some administrative data about it, so they know when it was last modified and by whom, etc., so:

<http://dilettantes.code4lib.org/resources/Chattanooga_Tennessee.rdf>
    rdf:type <http://www.geonames.org/ontology#P.PPL> ;
    <http://www.geonames.org/ontology#population> "155554"^^xsd:integer ;
    dcterms:creator <http://dilettantes.code4lib.org/about#me> ;
    dcterms:created "2010-07-09"^^xsd:date ;
    dcterms:modified "2010-07-09T11:25:00-6"^^xsd:dateTime .

Now things get confusing.  My new assertions (dcterms:creator/created/modified) are being applied to the same resource as my city, so I am saying that I created a city of 155,554 people today (what have you done today, chump?).

The way we get around this is through a layer of indirection, basically we just use two URIs: you request an RDF document from http://dilettantes.code4lib.org/resources/Chattanooga_Tennessee.rdf and it has something like:

<http://dilettantes.code4lib.org/resources/Chattanooga_Tennessee#place>
  rdf:type <http://www.geonames.org/ontology#P.PPL> ;
  <http://www.geonames.org/ontology#population> "155554"^^xsd:integer.
<http://dilettantes.code4lib.org/resources/Chattanooga_Tennessee.rdf>
    rdf:type <http://xmlns.com/foaf/0.1/Document> ;
    <http://xmlns.com/foaf/0.1/primaryTopic> <http://dilettantes.code4lib.org/resources/Chattanooga_Tennessee#place> ;
    dcterms:creator <http://dilettantes.code4lib.org/about#me> ;
    dcterms:created "2010-07-09"^^xsd:date ;
    dcterms:modified "2010-07-09T11:25:00-6"^^xsd:dateTime .

And this keeps things a little clearer.  I created the document you’re looking at today, not the resource that the document is describing.  So this way when you say that my RDF is terrible (fair accusation) you’re not necessarily saying that about the city of Chattanooga (and vice versa).  You can read more about this at Cool URIs for the Semantic Web (by the way, I tend to favor the “hash URI” approach, for simplicity’s sake).

Now back to Ed’s post.  His argument is that if he uses http://en.wikipedia.org/wiki/William_Shakespeare as his identifier (referent, really) we should be smart enough to know when we say that this URI is a foaf:Person and that it was dcterms:created on “2001-10-14″ that we’re referring to two different things.

The first comment is from Ian (full disclosure: my boss, fuller disclosure: this doesn’t mean I agree with him) who simultaneously “completely agrees” with Ed and yet supplies an argument that punches a gigantic hole in the side of Ed’s thesis.

To put it another way, sure, maybe we can tell that dcterms:created is a strange assertion for a foaf:Person and we have other ways to tell that Shakespeare was born in 1564 (via a bio:Birth resource or something), but this breaks down for books and all sorts of other entities.  So you have dcterms:created “2003-09-04″ and dcterms:creator <http://en.wikipedia.org/wiki/Douglas_Coupland> on http://en.wikipedia.org/wiki/Girlfriend_in_a_Coma_%28novel%29 and we’ve now sown some confusion.  This ambiguity becomes more problematic down the road when the context changes (that is, assumptions I can make about wikipedia and wikipedia’s model don’t necessarily apply elsewhere).

Right around the time I graduated from high school, the guitarist in my band at the time made me a cassette copy of Jimi Hendrix’s “Jimi Plays Monterey“.  The sound quality was pretty terrible and, as I recall, my tape player ate it once making it even worse.  Still, I loved that album (Jimi, while playing Dylan’s “Like a Rolling Stone” says “I know I missed a verse, it’s alright, baby.”): I love the songs, I love the playing, I love the energy of the performance.  The medium that album came to me on, however, was subpar.  There are general attributes of “cassette tapes” and then there was “this particular recording on this particular cassette”.

At the same time in my life, I had a compact disc of the BulletBoys’ eponymous album.  Fidelity-wise, the sound of this album was orders of magnitude better than my copy of “Jimi Plays Monterey”, but pretty much everything else about it sucked.

The carrier is not the content.  Being able to refer to the quality of my dilapidated cassette without dragging the Jimi Hendrix Experience into it is useful.  I should be able to say that my BulletBoys CD sounded better than my Hendrix tape without that being a staggering example of bad taste.

In libraries, we have a long history of data ambiguity.  We have struggled enough to figure out the semantics in our AACR2/ISBD data that when we have the chance to easily and concretely identify the things we are talking about, we should take it.  I am not proposing abstracting things into oblivion with resources on top of resources – just sensibly being sure you’re talking about what you say you are.

Unfortunately, one of my problems with the new RDA vocabularies is that in several instances it schmushes multiple statements together to avoid the modeling the “hard parts” (this is precisely the same issue I have with Ian’s later comment).  For example, RDA has a bunch of properties that are intended to “hand wave” around the complexities of FRBR, such as http://RDVocab.info/Elements/otherDistinguishingCharacteristicOfTheExpression.  So you’d have something like:

<http://example.org/1>
    <http://RDVocab.info/Elements/title> "Something: a something something" ;
    <http://RDVocab.info/Elements/titleOfTheWork> "Something" .

What you’ve done here with “titleOfTheWork” is say that <http://example.org/1> has a work, is itself not a work and the work’s title is “Something”.   That’s some attribute!  But if we can say all of that, why would we not just model the work?! Even if we don’t know where in the WEMI chain <http://example.org/1> falls, if we did something like this:

<http://example.org/1>
    dcterms:title "Something: a something something" ;
    ex:hasWork <http://example.org/works/1234> .

<http://example.org/works/1234>
    a <http://RDVocab.info/uri/schema/FRBRentitiesRDA/Work>;
    dcterms:title "Something" .

we’ve now done something useful, unambiguous and reusable (and not ignoring FRBR while simultaneously defining it).  The closed nature of IFLA’s development of these vocabularies don’t lead to me have much hope, though.

But, again, back to Ed.  Like I said, I really don’t think the internet will fall apart and satellites will come crashing to the earth if we don’t adhere consistently to httpRange-14.  No, the reason why I call bullshit on Ed’s statement is because he finds the use of owl:sameAs on resources such as http://purl.org/NET/marccodes/muscomp/sn#genre to be inappropriate.  While in his post he claims it’s fine that we conflate the resource of William Shakespeare as a foaf:Person and foaf:Document that was modified on “2010-06-28T17:02:41-04:00″, he on the other hand questions the appropriateness of <http://purl.org/NET/marccodes/muscomp/sn#genre> owl:sameAs <http://dbpedia.org/resource/Sonatas> because by doing so it infers that <http://purl.org/NET/marccodes/muscomp/sn#genre> has a photo collection at <http://www4.wiwiss.fu-berlin.de/flickrwrappr/photos/Sonata> (which, in fact, has little to do with the musical genre and actually has a lot of pictures of Hyundais, among other things).

This is a perfectly fair, valid and important point (and one that absolutely needs to be addressed), but doesn’t this also mean he actually cares that we say what we really mean?

A couple of months ago, I hacked up a really simple proof-of-concept Sinatra that took an LCCN, called the Library of Congress’ LCCN Permalink service’s MARCXML output for that particular LCCN and tried to model it into linked data. It was really basic: it only returned RDF/XML and had no persistence layer to it, so I ran it using Heroku’s free hosting plan.

It worked pretty well but as I applied more and more functionality to it (looking for matches in Musicbrainz, LinkedMDB, DBpedia, Freebase, etc. — especially inefficient SPARQL regex queries), I kept running into execution timeout errors on Heroku. These are the exact same sorts of problems that the Umlaut ran into years ago and the solution required complicated threading and, eventually, AJAX requests to offload some of the response time of waiting for synchronous web services requests to return (or timeout or fail).

One thing I began doing with LinkedLCCN was persisting the graph into a Platform store, so once stored, any subsequent request for a resource was quite speedy. The problem was the initial request, the one that gathered all of the data to fill out the graph before it stored. Quite often this would timeout or throw an error (which, given that this was still very much a work in progress, would result a 500 error) meaning the resource was never saved to the Platform meaning all of the following requests would have to go through the same process until one of them finally succeeded. Since the freebie access on Heroku lets you run one process at a time, these long running (and timing out) requests would cause a backlog which would throw more errors.

It was becoming the embodiment of the phrase I used during my Code4Lib presentation: “Amateur Hour on the Internet”.

What was obviously needed was some asynchronous mechanism for giving back part of the graph, indicating to the requester that this was a partial response, and firing off a background task to complete the rest of the processing. Because there was no HTML interface, AJAX wasn’t an option. Even if there was an HTML interface (as there is now), AJAX still wouldn’t have been an option, because this was a service intended for web agents following their nose, not human surfers, so even if the agent is satisfied with the HTML response (for instance, when it eventually gets RDFa), curl (and its ilk) don’t have javascript, so the background process would never even have a chance to be called, anyway.

This meant the only viable solution to this problem was going to be via multiple processes. This also meant that Heroku wasn’t an option anymore (at least, not without a price), so I was going to migrate to my personal web host. In Ruby web frameworks, asynchronous processing comes in one of two forms:

  1. Threads/forks/etc.
  2. Queue schedulers

Based on my experience with the Umlaut, I wanted to avoid #1, if at all possible, or at the very least, use an existing, packaged solution that could drop fairly painlessly into Sinatra. I found a port of Merb’s run_later, but I could only ever get it to run once. Any succeeding request never seemed to fire off the process.

The queue schedulers generally required their own set of baggage: namely their own running daemon and a RDBMS. Since almost all of these projects originally started out as Rails plugins, they expect the application to have ActiveRecord and an RDBMS to store their jobs in. I didn’t have either.

I had settled on using Delayed Job, since there was, again, a Sinatra port. It took quite a bit of hacking to get this to work right (mainly around marshaling/unmarshaling objects), and I never could get the job logging to work very well, but it was successfully queuing and executing jobs in the background.

It was hard to manage, though. I use Capistrano for deployment and it was very difficult to control the Delayed Job daemon so that it would stop and start with the regular webservice. Again, it worked, but it felt very fragile. The sort of thing I could see breaking and having to spend hours trying to figure out how to fix it.

Last night, while I was trying to pull together my thoughts and links and whatnot for this post, I ran across Spork, which is a Sinatra port of Spawn. A couple hours later, LinkedLCCN was refactored to use Spork instead, and that’s how it’s running now.

So, LinkedLCCN now works like this:
$ curl -v -H “accept: application/rdf+xml” http://lccn.lcsubjects.org/93707283#i

* About to connect() to lccn.lcsubjects.org port 80 (#0)
*   Trying 208.83.140.6... connected
* Connected to lccn.lcsubjects.org (208.83.140.6) port 80 (#0)
> GET /93707283#i HTTP/1.1
> User-Agent: curl/7.19.6 (i386-apple-darwin9.8.0) libcurl/7.19.6 zlib/1.2.3
> Host: lccn.lcsubjects.org
> accept: application/rdf+xml
>
< HTTP/1.1 206 Partial Content
< Date: Fri, 12 Mar 2010 20:19:50 GMT
< Server: Apache/2.2.12 (Ubuntu)
< X-Powered-By: Phusion Passenger (mod_rails/mod_rack) 2.2.11
< Content-Length: 6472
< Status: 206
< Content-Type: application/rdf+xml
<
<rdf:RDF xmlns:dcterms="http://purl.org/dc/terms/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:foaf="http://xmlns.com/foaf/0.1/" xmlns:skos="http://www.w3.org/2004/02/skos/core#" xmlns:bibo="http://purl.org/ontology/bibo/" xmlns:owl="http://www.w3.org/2002/07/owl#" xmlns:umbel="http://umbel.org/umbel#" xmlns:rda="http://RDVocab.info/Elements/"><rdf:Description rdf:about="http://purl.org/NET/lccn/93707283#i"><rda:placeOfPublication><rdf:Description rdf:about="http://purl.org/NET/marccodes/countries/nyu#location"></rdf:Description></rda:placeOfPublication><rda:titleProper>The freewheelin' Bob Dylan</rda:titleProper><foaf:isPrimaryTopicOf><rdf:Description rdf:about="http://lccn.loc.gov/93707283"></rdf:Description></foaf:isPrimaryTopicOf><bibo:uri>http://hdl.loc.gov/loc.mbrsrs/lp0001.dyln</bibo:uri><bibo:lccn>93707283</bibo:lccn><dcterms:title>The freewheelin' Bob Dylan</dcterms:title><dcterms:creator><rdf:Description rdf:about="http://purl.org/NET/lccn/people/n50030190#i"><owl:sameAs><rdf:Description rdf:about="http://dbpedia.org/resource/Bob_Dylan"></rdf:Description></owl:sameAs><foaf:name>Dylan, Bob, 1941-</foaf:name><umbel:isAbout><rdf:Description rdf:about="http://viaf.org/viaf/46946176.rwo"><foaf:name>Dylan, Bob, pseud</foaf:name><foaf:name>Dylan, Bob, 1941-</foaf:name><foaf:page rdf:resource="http://dbpedia.org/page/Wikipedia:WikiProject_Bob_Dylan" /><foaf:page rdf:resource="http://www.worldcat.org/wcidentities/lccn-n50-030190" /><foaf:page rdf:resource="http://en.wikipedia.org/wiki/Wikipedia:WikiProject_Bob_Dylan" /><skos:altLabel>Thomas, Robert Milkwood,</skos:altLabel><skos:altLabel>Dylan, B.</skos:altLabel><skos:altLabel>Thomas, Robert Milkwood</skos:altLabel><skos:altLabel>Landy, Bob,</skos:altLabel><skos:altLabel>Landy, Bob</skos:altLabel><skos:altLabel>Zimmermann, Robert Allen</skos:altLabel><skos:altLabel>Zimmerman, Roberto Allen</skos:altLabel><skos:altLabel>Zimmerman, Robert,</skos:altLabel><skos:altLabel>Porterhouse, Tedham,</skos:altLabel><skos:altLabel>Petrov, Sergei</skos:altLabel><skos:altLabel>Zimmerman, Robert Allen,</skos:altLabel><skos:altLabel>Blind Boy Grunt,</skos:altLabel><skos:altLabel>Gook, Roosevelt,</skos:altLabel><skos:altLabel>Dylan, Bob, 1941-</skos:altLabel><skos:altLabel>Zimmerman, Robert</skos:altLabel><skos:altLabel>Alias,</skos:altLabel><skos:altLabel>Zimmerman, Roberto Allen,</skos:altLabel><skos:altLabel>Dylan, Bob, pseud</skos:altLabel><skos:altLabel>Zimmerman, Robert Allen</skos:altLabel><skos:inScheme rdf:resource="http://viaf.org/viaf-scheme/#personalNames" /><skos:inScheme rdf:resource="http://viaf.org/viaf-scheme/#concept" /><skos:changeNote xml:lang="en">Modified by agency: OCoLC</skos:changeNote><skos:changeNote xml:lang="en">Transcribed by agency: OCoLC</skos:changeNote><skos:exactMatch rdf:resource="http://viaf.org/viaf/46946176.viaf" /><skos:exactMatch rdf:resource="http://libris.kb.se/auth/184248" /><skos:exactMatch rdf:resource="http://viaf.org/viaf/46946176.m21" /><skos:exactMatch rdf:resource="http://id.loc.gov/authorities/n50030190#concept" /><skos:exactMatch rdf:resource="http://en.wikipedia.org/wiki/Wikipedia:WikiProject_Bob_Dylan" /><skos:exactMatch rdf:resource="http://viaf.org/viaf/46946176.unimarc" /><skos:exactMatch rdf:resource="http://viaf.org/processed/BNF%7C13893566" /><skos:exactMatch rdf:resource="http://viaf.org/processed/NKC%7Cjn20000700458" /><skos:exactMatch rdf:resource="http://d-nb.info/gnd/118528408" /><skos:exactMatch rdf:resource="http://catalogo.bne.es/uhtbin/authoritybrowse.cgi?action=display&amp;authority_id=XX821701" /><skos:exactMatch rdf:resource="http://viaf.org/processed/NLA%7C000035052711" /><skos:exactMatch rdf:resource="http://viaf.org/processed/NLIlat%7C000041704" /><skos:exactMatch rdf:resource="http://dbpedia.org/page/Wikipedia:WikiProject_Bob_Dylan" /><skos:exactMatch rdf:resource="http://viaf.org/processed/LAC%7C0008D6165" /><skos:exactMatch rdf:resource="http://viaf.org/processed/PTBNP%7C1270067" /><rdf:type rdf:resource="http://www.w3.org/2004/02/skos/core#Concept" /><dcterms:modified rdf:datatype="http://www.w3.org/2001/XMLSchema#dateTime">2010-02-22T06:44:10+00:00</dcterms:modified><dcterms:type>person</dcterms:type><dcterms:identitifer>46946176</dcterms:identitifer><dcterms:created rdf:datatype="http://www.w3.org/2001/XMLSchema#dateTime">2009-03-03T12:03:19+00:00</dcterms:created></rdf:Description></umbel:isAbout><rdf:type><rdf:Description rdf:about="http://xmlns.com/foaf/0.1/Person"></rdf:Description></rdf:type></rdf:Description></dcterms:creator><dcterms:language><rdf:Description rdf:about="http://purl.org/NET/marccodes/languages/eng#lang"></rdf:Description></dcterms:language><dcterms:subject><rdf:Description rdf:about="http://id.loc.gov/authorities/sh87003307#concept"><owl:sameAs><rdf:Description rdf:about="info:lc/authorities/sh87003307"></rdf:Description></owl:sameAs><skos:inScheme><rdf:Description rdf:about="http://id.loc.gov/authorities#topicalTerms"></rdf:Description></skos:inScheme><skos:inScheme><rdf:Description rdf:about="http://id.loc.gov/authorities#conceptScheme"></rdf:Description></skos:inScheme><skos:prefLabel>Popular music--1961-1970</skos:prefLabel><rdf:type><rdf:Description rdf:about="http://www.w3.org/2004/02/skos/core#Concept"></rdf:Description></rdf:type><dcterms:modified rdf:datatype="http://www.w3.org/2001/XMLSchema#dateTime">1987-07-14T11:37:03-04:00</dcterms:modified><dcterms:created rdf:datatype="http://www.w3.org/2001/XMLSchema#dateTime">1987-05-22T00:00:00-04:00</dcterms:created></rdf:Description></dcterms:subject><dcterms:subject><rdf:Description rdf:about="http://id.loc.gov/authorities/sh87003285#concept"><owl:sameAs><rdf:Description rdf:about="info:lc/authorities/sh87003285"></rdf:Description></owl:sameAs><skos:inScheme><rdf:Description rdf:about="http://id.loc.gov/authorities#topicalTerms"></rdf:Description></skos:inScheme><skos:inScheme><rdf:Description rdf:about="http://id.loc.gov/authorities#conceptScheme"></rdf:Description></skos:inScheme><skos:prefLabel>Blues (Music)--1961-1970</skos:prefLabel><rdf:type><rdf:Description rdf:about="http://www.w3.org/2004/02/skos/core#Concept"></rdf:Description></rdf:type><dcterms:modified rdf:datatype="http://www.w3.org/2001/XMLSchema#dateTime">1987-07-14T16:41:41-04:00</dcterms:modified><dcterms:created rdf:datatype="http://www.w3.org/2001/XMLSchema#dateTime">1987-05-22T00:00:00-04:00</dcterms:created></rdf:Description></dcterms:subject></rdf:Description></rdf:RDF>
* Connection #0 to host lccn.lcsubjects.org left intact
* Closing connection #0

The important thing to note here is the HTTP status code sent back. LinkedLCCN sends back a 206, partial content because it wants the agent to try again later. “Thank you for waiting, here is some data to get you started. If you come back, it’s possible I might have some more.”

And, indeed, if the agent came back:
$ curl -v -H “accept: application/rdf+xml” http://lccn.lcsubjects.org/93707283#i

* About to connect() to lccn.lcsubjects.org port 80 (#0)
*   Trying 208.83.140.6... connected
* Connected to lccn.lcsubjects.org (208.83.140.6) port 80 (#0)
> GET /93707283#i HTTP/1.1
> User-Agent: curl/7.19.6 (i386-apple-darwin9.8.0) libcurl/7.19.6 zlib/1.2.3
> Host: lccn.lcsubjects.org
> accept: application/rdf+xml
>
< HTTP/1.1 200 OK
< Date: Fri, 12 Mar 2010 20:26:18 GMT
< Server: Apache/2.2.12 (Ubuntu)
< X-Powered-By: Phusion Passenger (mod_rails/mod_rack) 2.2.11
< Content-Length: 40807
< Status: 200
< Content-Type: application/rdf+xml
<
<rdf:RDF xmlns:n0="http://dbtune.org/musicbrainz/resource/vocab/" xmlns:mo="http://purl.org/ontology/mo/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:n1="http://www.holygoat.co.uk/owl/redwood/0.1/tags/" xmlns:n2="http://purl.org/vocab/bio/0.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:foaf="http://xmlns.com/foaf/0.1/" xmlns:skos="http://www.w3.org/2004/02/skos/core#" xmlns:bibo="http://purl.org/ontology/bibo/" xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:owl="http://www.w3.org/2002/07/owl#" xmlns:umbel="http://umbel.org/umbel#" xmlns:rda="http://RDVocab.info/Elements/"><rdf:Description rdf:about="http://purl.org/NET/lccn/93707283#i"><mo:label><rdf:Description rdf:about="http://dbtune.org/musicbrainz/resource/label/011d1192-6f65-45bd-85c4-0400dd45693e"><n0:label_sortname>Columbia Records</n0:label_sortname><n0:label_name>Columbia Records</n0:label_name><n0:label_labelcode>162</n0:label_labelcode><n0:tag_count>1</n0:tag_count><n0:label_type>4</n0:label_type><n0:alias>Columbia Phonograph Company</n0:alias><n0:alias>Columbia</n0:alias><n0:alias>Colombia Records</n0:alias><n0:alias>Columbia d (Sony BMG)</n0:alias><n0:alias>Columbia Records</n0:alias><n0:alias>Columbia US</n0:alias><rdfs:label>Columbia Records</rdfs:label><n1:taggedWithTag><rdf:Description rdf:about="http://dbtune.org/musicbrainz/resource/tag/20"></rdf:Description></n1:taggedWithTag><n1:taggedWithTag><rdf:Description rdf:about="http://dbtune.org/musicbrainz/resource/tag/748"></rdf:Description></n1:taggedWithTag><n1:taggedWithTag><rdf:Description rdf:about="http://dbtune.org/musicbrainz/resource/tag/1584"></rdf:Description></n1:taggedWithTag><n1:taggedWithTag><rdf:Description rdf:about="http://dbtune.org/musicbrainz/resource/tag/111"></rdf:Description></n1:taggedWithTag><n1:taggedWithTag><rdf:Description rdf:about="http://dbtune.org/musicbrainz/resource/tag/273"></rdf:Description></n1:taggedWithTag><n1:taggedWithTag><rdf:Description rdf:about="http://dbtune.org/musicbrainz/resource/tag/343"></rdf:Description></n1:taggedWithTag><n1:taggedWithTag><rdf:Description rdf:about="http://dbtune.org/musicbrainz/resource/tag/7179"></rdf:Description></n1:taggedWithTag><n1:taggedWithTag><rdf:Description rdf:about="http://dbtune.org/musicbrainz/resource/tag/284"></rdf:Description></n1:taggedWithTag><n2:event><rdf:Description rdf:about="http://dbtune.org/musicbrainz/resource/label/011d1192-6f65-45bd-85c4-0400dd45693e/birth"></rdf:Description></n2:event><foaf:based_near><rdf:Description rdf:about="http://dbtune.org/musicbrainz/resource/country/US"></rdf:Description></foaf:based_near><dc:description>1931-1990: only USA, Canada&amp;Japan. 1990 to present: worldwide</dc:description><rdf:type><rdf:Description rdf:about="http://purl.org/ontology/mo/Label"></rdf:Description></rdf:type></rdf:Description></mo:label><mo:catalogue_number>CS 8786</mo:catalogue_number><mo:track><rdf:Description rdf:about="http://dbtune.org/musicbrainz/resource/track/5857b092-93ae-434d-b3f1-3f959396732b"></rdf:Description></mo:track><mo:track><rdf:Description rdf:about="http://dbtune.org/musicbrainz/resource/track/98846b10-8951-43bc-ab24-c960e330cec8"></rdf:Description></mo:track><mo:track><rdf:Description rdf:about="http://dbtune.org/musicbrainz/resource/track/88621637-8f03-427e-855f-4f52f712e80e"></rdf:Description></mo:track><mo:track><rdf:Description rdf:about="http://dbtune.org/musicbrainz/resource/track/6d2b3714-478f-4fb1-9dfb-4a70c266453e"></rdf:Description></mo:track><mo:track><rdf:Description rdf:about="http://dbtune.org/musicbrainz/resource/track/b654f8ad-071a-41c1-a1f7-1134de178ee8"></rdf:Description></mo:track><mo:track><rdf:Description rdf:about="http://dbtune.org/musicbrainz/resource/track/9b08a5da-da77-4df8-b3ad-dcb481959013"></rdf:Description></mo:track><mo:track><rdf:Description rdf:about="http://dbtune.org/musicbrainz/resource/track/f96f9b50-959d-4ef0-adc0-2995d179e6c8"></rdf:Description></mo:track><mo:track><rdf:Description rdf:about="http://dbtune.org/musicbrainz/resource/track/2160818f-ce54-4502-a480-535389abef61"></rdf:Description></mo:track><mo:track><rdf:Description rdf:about="http://dbtune.org/musicbrainz/resource/track/2f528602-ea36-480a-b1df-f7a5af36598e"></rdf:Description></mo:track><mo:track><rdf:Description rdf:about="http://dbtune.org/musicbrainz/resource/track/19f571b4-b396-4113-9858-ab032074a3c7"></rdf:Description></mo:track><mo:track><rdf:Description rdf:about="http://dbtune.org/musicbrainz/resource/track/00e37446-2e4c-409a-a8a1-ed94f1b01a57"></rdf:Description></mo:track><mo:track><rdf:Description rdf:about="http://dbtune.org/musicbrainz/resource/track/536247b1-a87a-40c7-93e8-dd02fe3f3d54"></rdf:Description></mo:track><mo:track><rdf:Description rdf:about="http://dbtune.org/musicbrainz/resource/track/67a68273-fa05-4ecf-aa85-648868a91b01"></rdf:Description></mo:track><rda:placeOfPublication><rdf:Description rdf:about="http://purl.org/NET/marccodes/countries/nyu#location"></rdf:Description></rda:placeOfPublication><rda:titleProper>The freewheelin' Bob Dylan</rda:titleProper><foaf:isPrimaryTopicOf><rdf:Description rdf:about="http://lccn.loc.gov/93707283"></rdf:Description></foaf:isPrimaryTopicOf><bibo:uri>http://hdl.loc.gov/loc.mbrsrs/lp0001.dyln</bibo:uri><bibo:lccn>93707283</bibo:lccn><rdf:type><rdf:Description rdf:about="http://purl.org/ontology/mo/Recording"></rdf:Description></rdf:type><dcterms:title>The freewheelin' Bob Dylan</dcterms:title><dcterms:creator><rdf:Description rdf:about="http://purl.org/NET/lccn/people/n50030190#i"><owl:sameAs><rdf:Description rdf:about="http://dbpedia.org/resource/Bob_Dylan"></rdf:Description></owl:sameAs><foaf:name>Dylan, Bob, 1941-</foaf:name><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/r64001976#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007568523#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007700813#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007700816#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/unk84175336#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/95769390#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/99567433#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2002560219#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2002603175#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/72343809#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/78762560#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007700762#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007700760#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/r64001986#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2001036739#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007700847#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/76762320#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/93727595#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/93726950#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/00536083#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/unk84158135#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/93727467#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2003636870#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/93723725#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/88753098#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2008640899#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007700841#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/r65000579#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/93705362#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007700812#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007700817#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007642887#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/93711197#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007700805#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007700771#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007700763#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/72762075#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2002042823#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007700818#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007700774#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/72763265#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/00717921#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/72761611#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/93707558#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2002578760#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2010616561#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/r68000463#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007657614#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/00725480#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/95776698#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2004304721#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/77760065#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007700843#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007700775#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/94771432#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007700807#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/r65001916#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/91759862#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2004593548#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/74217252#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/68128332#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007700811#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2003696014#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/91762191#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007700770#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007657624#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/71224759#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/71763700#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/74760392#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007659104#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/93726958#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/98028826#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/74760100#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007700748#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/unk84196471#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/93712912#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/94023183#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007700777#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/91759844#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/91759501#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/74762095#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2005045677#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/93712878#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2009602196#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/85161136#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/99580439#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007700758#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2001536938#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/93703756#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007700751#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007700806#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007700756#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007700819#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/90750957#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/95701312#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2005434462#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/unk84219598#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/95786124#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/93703149#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/99573938#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/79761946#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2002572371#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007700804#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/66041425#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/93710188#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/78056239#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/93712977#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/r67001398#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007700244#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/66025502#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/86463558#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007700815#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007700768#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/93727732#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/72002339#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/93703465#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007700844#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2005560717#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007700753#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/91759880#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2008643295#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/unk84085959#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/76013692#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007700800#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/92776389#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/93711016#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/93851416#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007657612#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/95129257#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007700801#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007700840#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007700761#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/76760788#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007656198#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/70761002#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2003385743#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007700765#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007700755#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2008655199#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/73762412#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007700242#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/92755348#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/r64000162#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007700846#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/77275475#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007700769#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/80760343#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/97751545#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2006656398#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2008038164#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/93715284#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007700837#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007700764#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007700752#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007700759#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2006657054#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/94770754#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/93712995#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/00584949#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2004590181#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/93729841#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/00717773#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2004592553#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2010616562#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2008300626#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/79761354#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/93707283#i"><mo:label rdf:resource="http://dbtune.org/musicbrainz/resource/label/011d1192-6f65-45bd-85c4-0400dd45693e" /><mo:catalogue_number>CS 8786</mo:catalogue_number><mo:track rdf:resource="http://dbtune.org/musicbrainz/resource/track/5857b092-93ae-434d-b3f1-3f959396732b" /><mo:track rdf:resource="http://dbtune.org/musicbrainz/resource/track/98846b10-8951-43bc-ab24-c960e330cec8" /><mo:track rdf:resource="http://dbtune.org/musicbrainz/resource/track/88621637-8f03-427e-855f-4f52f712e80e" /><mo:track rdf:resource="http://dbtune.org/musicbrainz/resource/track/6d2b3714-478f-4fb1-9dfb-4a70c266453e" /><mo:track rdf:resource="http://dbtune.org/musicbrainz/resource/track/b654f8ad-071a-41c1-a1f7-1134de178ee8" /><mo:track rdf:resource="http://dbtune.org/musicbrainz/resource/track/9b08a5da-da77-4df8-b3ad-dcb481959013" /><mo:track rdf:resource="http://dbtune.org/musicbrainz/resource/track/f96f9b50-959d-4ef0-adc0-2995d179e6c8" /><mo:track rdf:resource="http://dbtune.org/musicbrainz/resource/track/2160818f-ce54-4502-a480-535389abef61" /><mo:track rdf:resource="http://dbtune.org/musicbrainz/resource/track/2f528602-ea36-480a-b1df-f7a5af36598e" /><mo:track rdf:resource="http://dbtune.org/musicbrainz/resource/track/19f571b4-b396-4113-9858-ab032074a3c7" /><mo:track rdf:resource="http://dbtune.org/musicbrainz/resource/track/00e37446-2e4c-409a-a8a1-ed94f1b01a57" /><mo:track rdf:resource="http://dbtune.org/musicbrainz/resource/track/536247b1-a87a-40c7-93e8-dd02fe3f3d54" /><mo:track rdf:resource="http://dbtune.org/musicbrainz/resource/track/67a68273-fa05-4ecf-aa85-648868a91b01" /><rda:placeOfPublication rdf:resource="http://purl.org/NET/marccodes/countries/nyu#location" /><rda:titleProper>The freewheelin' Bob Dylan</rda:titleProper><foaf:isPrimaryTopicOf rdf:resource="http://lccn.loc.gov/93707283" /><bibo:uri>http://hdl.loc.gov/loc.mbrsrs/lp0001.dyln</bibo:uri><bibo:lccn>93707283</bibo:lccn><rdf:type rdf:resource="http://purl.org/ontology/mo/Recording" /><dcterms:title>The freewheelin' Bob Dylan</dcterms:title><dcterms:creator rdf:resource="http://purl.org/NET/lccn/people/n50030190#i" /><dcterms:language rdf:resource="http://purl.org/NET/marccodes/languages/eng#lang" /><dcterms:subject rdf:resource="http://id.loc.gov/authorities/sh87003307#concept" /><dcterms:subject rdf:resource="http://id.loc.gov/authorities/sh87003285#concept" /><dcterms:isVersionOf rdf:resource="http://dbtune.org/musicbrainz/resource/record/942be4b0-12a2-4264-93a3-b45fa94c95c0" /></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/99583697#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/93724609#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/75766013#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/66041424#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2008273503#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/96789283#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007700776#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007700820#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/93711987#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007700839#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2004585875#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/94162315#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007700808#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/80772269#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/r68000263#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007700754#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2010616563#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2004577731#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/94770756#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2004571741#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/97109960#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/r62000368#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/76353124#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/93711249#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/93037274#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/86753728#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/72760404#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007700749#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007700772#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/77018965#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007700809#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/75762080#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/r67001399#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2003643362#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/78531019#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2010617063#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/93701439#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/r68000262#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2003577486#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007700766#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/76762851#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/unk84126692#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/94762678#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007657649#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007700243#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/93728350#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/92750713#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/94762887#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/95769054#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/72373613#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/99571326#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/91755140#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/92774846#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/77761257#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/93711137#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2003643131#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2009015567#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/76770532#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/91761855#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/93721323#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007700803#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007700810#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2010615421#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/94746592#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/72373606#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/92757783#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2002603171#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/93712772#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007700767#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2004056454#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/r65000580#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/91759726#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/93712861#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/81047774#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2005048013#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/93702899#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/unk84096809#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007700245#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/85040408#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/92754060#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/66052234#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/72251264#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007700757#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007700845#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/91761627#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007700814#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2002556777#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007700750#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/87754788#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/94770755#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007700773#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/91760389#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/r62000369#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2004560796#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/94750639#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2006571042#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/r65001917#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/92754813#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007700802#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2003574417#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/93707133#i"></rdf:Description></foaf:made><foaf:made>
<rdf:Description rdf:about="http://purl.org/NET/lccn/2007700842#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/95769314#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/r67001260#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2003573910#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/87752098#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2004462312#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/r64000161#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/unk85066726#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/71763246#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/99567232#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2006530396#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2001545149#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/91761930#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/2007700799#i"></rdf:Description></foaf:made><foaf:made><rdf:Description rdf:about="http://purl.org/NET/lccn/93709800#i"></rdf:Description></foaf:made><umbel:isAbout><rdf:Description rdf:about="http://viaf.org/viaf/46946176.rwo"></rdf:Description></umbel:isAbout><rdf:type><rdf:Description rdf:about="http://xmlns.com/foaf/0.1/Person"></rdf:Description></rdf:type></rdf:Description></dcterms:creator><dcterms:language><rdf:Description rdf:about="http://purl.org/NET/marccodes/languages/eng#lang"></rdf:Description></dcterms:language><dcterms:subject><rdf:Description rdf:about="http://id.loc.gov/authorities/sh87003307#concept"><owl:sameAs><rdf:Description rdf:about="info:lc/authorities/sh87003307"></rdf:Description></owl:sameAs><skos:inScheme><rdf:Description rdf:about="http://id.loc.gov/authorities#conceptScheme"></rdf:Description></skos:inScheme><skos:inScheme><rdf:Description rdf:about="http://id.loc.gov/authorities#topicalTerms"></rdf:Description></skos:inScheme><skos:prefLabel>Popular music--1961-1970</skos:prefLabel><rdf:type><rdf:Description rdf:about="http://www.w3.org/2004/02/skos/core#Concept"></rdf:Description></rdf:type><dcterms:modified rdf:datatype="http://www.w3.org/2001/XMLSchema#dateTime">1987-07-14T11:37:03-04:00</dcterms:modified><dcterms:created rdf:datatype="http://www.w3.org/2001/XMLSchema#dateTime">1987-05-22T00:00:00-04:00</dcterms:created></rdf:Description></dcterms:subject><dcterms:subject><rdf:Description rdf:about="http://id.loc.gov/authorities/sh87003285#concept"><owl:sameAs><rdf:Description rdf:about="info:lc/authorities/sh87003285"></rdf:Description></owl:sameAs><skos:inScheme><rdf:Description rdf:about="http://id.loc.gov/authorities#conceptScheme"></rdf:Description></skos:inScheme><skos:inScheme><rdf:Description rdf:about="http://id.loc.gov/authorities#topicalTerms"></rdf:Description></skos:inScheme><skos:prefLabel>Blues (Music)--1961-1970</skos:prefLabel><rdf:type><rdf:Description rdf:about="http://www.w3.org/2004/02/skos/core#Concept"></rdf:Description></rdf:type><dcterms:modified rdf:datatype="http://www.w3.org/2001/XMLSchema#dateTime">1987-07-14T16:41:41-04:00</dcterms:modified><dcterms:created rdf:datatype="http://www.w3.org/2001/XMLSchema#dateTime">1987-05-22T00:00:00-04:00</dcterms:created></rdf:Description></dcterms:subject><dcterms:isVersionOf><rdf:Description rdf:about="http://dbtune.org/musicbrainz/resource/record/942be4b0-12a2-4264-93a3-b45fa94c95c0"></rdf:Description></dcterms:isVersionOf></rdf:Description></rdf:RDF>
* Connection #0 to host lccn.lcsubjects.org left intact
* Closing connection #0

There is a much richer graph waiting for it.

Now, I have no idea if this is a valid application of the 206 response. The only references I see to it on the web deal with either cache proxies or range requests, but this seems like best way to alert the client that they aren’t getting the entire graph on this request.

So try it out and enjoy the new (and very basic) HTML interface.

Any comments, suggestions or criticisms on this approach are extremely welcome.