Metadata subproperties


Looking for some help on a module that I’m working on. Basically, what I want to achieve is the ability to add an additional subproperty to a metadata property. From what I understand about Omeka-S, it is flat in this regard, and the most you can do is add a language subproperty but not really anything else (or is this considered an attribute? sorry if my terminology confuses json and xml).

Basically, my primary goal is to add a ‘relator’ subproperty to the dc creator property or the mods name property. We want to be able to indicate that this creator is a designer or an illustrator or an author, etc. The actual subproperty for mods is ‘role’, which if you import the mods vocabulary can be added as a property to items. However, there’s no way to have the ‘role’ property actually be linked to the creator/name that it refers to, e.g. if you have multiple creators/role its not clear which is linked to which.

So, I’ve been playing around with developing a module, and I think there are several different approaches that could be taken to cheat my way to this functionality. This is where I’m looking for some help/advice about which route seems less bad:

1st. Because I don’t anticipate much use by us for the language subproperty/attribute in the Value entity class, I can use the module to change all the built-in data types (literal, uri, and resource) so that it dumps relator data into the otherwise unused ‘lang’. Then, update the rendering and the json ld, and also modify the data-type partials so this can be inputted/displayed in the interface, all through the module. This is pretty straightforward, and I’ve gotten it to work, but seems wrong because I’m misusing ‘lang’ and I feel like there might be unintended consequences down the line. But clearly the easiest approach I’ve considered. I even think that I could go further with this approach and dump multiple subproperties there if needed.

2nd. Creating an entirely new relator entity through the module, which would then be tied to the value entity. This approach I haven’t exactly gotten to work. I’ve been able to add the entity, doctrine proxies, api adapter and representation through the module, but have only been able to make Omeka\Entity\Item the target entity, where it works but is useless. I need to be able to make Omeka\Entity\Value the target of this new relator entity. That I can’t exactly figure out. I would imagine this is done using each value’s id but I haven’t seen any methods to get a value’s id in the documentation/core code. This seems like it would be the most ‘true’ way to go about this, but I’m not sure if I understand how to do it/if it is possible.

3rd. Change the core code. I could update the Value entity class to include the additional ‘relator’ subproperty and update the data model. However, I’m very adverse to changing the core code. I did that before with Omeka Classic and it was always a hassle to upgrade. But am I wrong that I can’t change the Value entity class through the module. I tried playing around with this and couldn’t manage to do it that way. It seems that too many other classes rely on the Value entity class that I would practically need to have copies of everything in the module to get it to work.

4th. Just add the relator in parentheses after the name as part of the value/label itself, i.e. Chanel, Coco, 1883-1971 (designer). This is a very unsatisfying approach. Also I worry that it could cause problems with searching in cases where Chanel plays different functions.

Apologies for the rambling post. Really appreciate any help.


Joseph Anderson

A much simpler option that doesn’t require a new module is using vocabularies that include the specific properties you want. BIBO (which ships with Omeka S) includes a handful of agent properties, like bibo:organizer and bibo:interviewer. You may have more luck with, which includes quite a few agent properties, like schema:illustrator and schema::artist. Take a look at Linked Open Vocabularies for vocabularies that include exactly what you’re looking for.

If you still can’t find a specific property, you could always create your own vocabulary and import it into Omeka. Something like the following (ttl format):

@prefix : <http://your-namespace-uri/#> .
@prefix dcterms: <> .
@prefix rdf: <> .
@prefix rdfs: <> .

:illustrator a rdf:Property ;
    rdfs:label "illustrator"@en ;
    rdfs:comment "An illustrator"@en ;
    rdfs:subPropertyOf dcterms:creator .

1 Like

Thanks Jim.

Yeah, that’s also an option. We’re actually coming out of a system where we were creating a property for each different creator role and were hoping to move away from that somewhat and simplify/consolidate our metadata.

My concern with going this route is searching/faceting. If we have a few dozen different properties for different creator roles, how does a user know what property they would need to select when conducting an advanced search? Ideally, a user could just search the creator property and the search would include all these subproperties too. But from what I can tell, this isn’t the case. Is that correct? Then, I think something like the metadata browse module would also be an issue because it wouldn’t link the person playing different role for separate items.

I guess there’s always a tension with the granularity of metadata, always advantages and disadvantages to choosing one approach or the other.

That said, let’s say I wanted to be stubborn about the module I wanted to create in my original post. Do you think there’s a best route to take there?

Thanks for your help!

Ideally, a user could just search the creator property and the search would include all these subproperties too. But from what I can tell, this isn’t the case. Is that correct?

Yes, Omeka does not respect rdfs:subPropertyOf in the way you describe. The software simulates the RDF model in a relational database, so there are some necessary compromises it has to make for performance and ease of use. The granularity of metadata is indeed a tension that we struggle with.

When it comes to searching, Omeka does have a feature that simulates subproperties. When editing a resource template, you can provide an alternate label to any assigned property. For example, “Illustrator” could be the alternate label for “Creator”. Then, in site settings under “Templates”, you can apply the template to the advanced search form. Once this is done, your site’s advanced search form will include “Creator (Illustrator)” under “Search by value”. This is typically what we recommend our users do when they need to qualify their properties.

I recognize, however, that this will not solve your specific needs, since it simulates only one subproperty for every property. We once had a pull request that added a way to add multiple fields for one property, requiring different data types for for each additional label. Unfortunately the issuer removed the request and I cannot find it.

As for your module ideas, it’s hard for me to get a sense of how they will solve every data entry, storage, display, and search issue that is required to implement RDF-compliant subproperties, but the let’s take them one at a time.

  1. I don’t recommend using the lang column to store non-language data. I’m surprised it hasn’t broken your record form. But if it works for you, and you plan to never assign a language to a value, I suppose it’s an acceptable approach.
  2. I’m don’t completely follow this idea.
  3. While it is impossible to change the Value class using a module, you can establish a parallel data structure that updates every time a resource is saved. For an example of this approach, see the Numeric Data Type module, specifically Module::saveNumericData().
  4. Certainly not an ideal approach, it does provide a temporary solution until you come up with a better one.

@jimsafley Thanks again, Jim.

I don’t think I did a good job explaining myself in #2, but I was actually thinking about doing something like what you’re describing in #3. I’ll take a closer look at how that’s all handled in the Numeric Data Types module.

@jimsafley Hello again,

I was looking at the Numeric Data Type module that you shared and had a question. I see how you’ve created a parallel data structure, but I’m wondering how you could go about actually rendering that data from within the data type class. That is, I see how you’re taking a value and are also saving it in a parallel number table in a different format, but it seems like for the purposes of this module that that parallel table is only being used for search and sorting. Is that correct?

Within each data type class, it is rendered using the data from the original value table, not the parallel one. So basically what I would need to do for my purposes is during the rendering of the data type, use the original value but then also grab additional data (the role) from the parallel table. But I can’t figure how to make that match or lookup.

Thanks again for any help.

You’ll have to find some way to map the value to your parallel data structure. Typically you’d use unique identifiers, but, in Omeka, value IDs are opaque because they are ephemeral - they’re often overwritten during write operations. You could try storing the value’s resource ID and property ID alongside the parallel data and using them to fetch the corresponding value when rendering. Omeka representations do have a back door to the service locator via $value->getServiceLocator(), so you can make queries using the entity manager. Good luck.