Taxonomy Plugin Automatic Ancestor Key Storage

Default Taxonomy Field Stores Ancestor Keys

Starting with version 15.3, the Taxonomy field type is available in the Document Type Editor. When you add a Taxonomy field to a document type, taxonomy keys selected in the Taxonomy Picker are stored in a JCR property defined in the document type configuration.

When a user selects categories using the Taxonomy Picker, the selected keys are saved in the configured multi-valued JCR property.

Info: The taxonomy plugin also stores all ancestor keys in a separate multi-valued property. This property uses the same base name as the original, with the suffix "__with_ancestors".

Storing ancestor keys enables you to query documents by higher-level taxonomy categories efficiently.

For example, if a document has a geography taxonomy field with two selected categories, the stored properties look like this:

/content/documents/myproject/content/example-doc/example-doc: myproject:mytaxonomy: [san-francisco, london] myproject:mytaxonomy__with_ancestors: [northamerica, usa, california, san-francisco, europe, uk, london]

Configuring the Legacy Taxonomy Mixin Field to Store Ancestor Keys

Legacy Configuration (Taxonomy Mixin Field)

The following applies to the legacy Taxonomy Mixin Field, available since version 15.3.0.

The legacy mixin-based taxonomy field can be configured to store ancestor keys in addition to the default hippotaxonomy:keys property (or a custom path defined by the fieldPath property; see Extra Taxonomy Field).

To enable ancestor key storage:

  1. Set the storeKeysWithAncestors flag to true in the DAO service configuration.
  2. By default, ancestor keys are stored in the hippotaxonomy:keyswithancestors property. You can override this by setting the fieldWithAncestorsPath property.

Example configuration:

/hippo:configuration/hippo:frontend/cms/cms-services/classificationDaoService: storeKeysWithAncestors: true # Optional: defaults to hippotaxonomy:keyswithancestors fieldWithAncestorsPath: myproject:mycategories_withancestors

Populating Ancestor Keys for Existing Documents

When you save a document, taxonomy keys and ancestor keys are updated automatically. To update existing documents without manually opening and saving each one, use an updater script.

The following Groovy script provides an example for populating ancestor keys based on existing taxonomy key properties.

package org.hippoecm.frontend.plugins.cms.admin.updater import org.hippoecm.repository.util.JcrUtils import org.onehippo.repository.update.BaseNodeUpdateVisitor import javax.jcr.Node import javax.jcr.NodeIterator import javax.jcr.RepositoryException import javax.jcr.Session import javax.jcr.query.Query import org.onehippo.taxonomy.api.TaxonomyNodeTypes /** * Groovy script to populate a taxonomy property for storing all ancestor keys, based on an existing taxonomy property. * * XPath query: //element(*, myproject:contentdocument) * Parameters: { "keysProperty" : "hippotaxonomy:keys", * "keysWithAncestorsProperty" : "hippotaxonomy:keyswithancestors" } */ class PopulateTaxonomyKeysWithAncestors extends BaseNodeUpdateVisitor { boolean logSkippedNodePaths() { return false } boolean skipCheckoutNodes() { return false } Node firstNode(final Session session) throws RepositoryException { return null } Node nextNode() throws RepositoryException { return null } boolean doUpdate(Node node) { def keysProperty = parametersMap["keysProperty"] def keysWithAncestorsProperty = parametersMap["keysWithAncestorsProperty"] String[] keys = JcrUtils.getMultipleStringProperty(node, keysProperty, null) if (keys == null) { log.debug "Not recreating ${keysWithAncestorsProperty}: no ${keysProperty} on node ${node.path}" return false } log.debug "Recreating ${keysWithAncestorsProperty} based on ${keysProperty}=${keys} on node ${node.path}" final def keysWithAncestors = new LinkedHashSet<>(); def queryMgr = node.getSession().getWorkspace().getQueryManager() for (def key : keys) { def ancestors = getKeyWithAncestors(key, queryMgr) log.debug " adding values ${ancestors}" keysWithAncestors.addAll(ancestors) } String[] values = keysWithAncestors.toArray(new String[0]) node.setProperty(keysWithAncestorsProperty, values) return true } boolean undoUpdate(Node node) { throw new UnsupportedOperationException('Updater does not implement undoUpdate method') } def getKeyWithAncestors(def key, def queryMgr) { def keyWithAncestors = new LinkedList() def statement = "content/taxonomies//element(*, hippotaxonomy:category)[hippotaxonomy:key = '" + key + "']" def query = queryMgr.createQuery(statement, Query.XPATH) final NodeIterator nodes = query.execute().nodes // there should be only one (unique key) if (nodes.hasNext()) { def cat = nodes.nextNode() // only category nodes up the tree have the key property while (cat.hasProperty(TaxonomyNodeTypes.HIPPOTAXONOMY_KEY)) { keyWithAncestors.add(cat.getProperty(TaxonomyNodeTypes.HIPPOTAXONOMY_KEY).string) cat = cat.parent } } else { log.debug("No category node found by key ${key}") } // same order as MixinClassificationDaoPlugin Collections.reverse(keyWithAncestors) return keyWithAncestors; } }
Share Feedback
Page: /build/plugins/taxonomy/store-ancestor-keys-automatically
Section: Build
Category *
Taxonomy Plugin Store Ancestor Keys Automatically | Bloomreach Content Documentation