############################################################################### ## ## ## ALEXANDRIA DIGITAL LIBRARY ## ## University of California at Santa Barbara ## ## ## ## ------------------------------------------------------------------------- ## ## ## ## Copyright (c) 2004 by the Regents of the University of California ## ## All rights reserved ## ## ## ## Redistribution and use in source and binary forms, with or without ## ## modification, are permitted provided that the following conditions are ## ## met: ## ## ## ## 1. Redistributions of source code must retain the above copyright ## ## notice, this list of conditions, and the following disclaimer. ## ## ## ## 2. Redistributions in binary form must reproduce the above copyright ## ## notice, this list of conditions, and the following disclaimer in ## ## the documentation and/or other materials provided with the ## ## distribution. ## ## ## ## 3. All advertising materials mentioning features or use of this ## ## software must display the following acknowledgement: This product ## ## includes software developed by the Alexandria Digital Library, ## ## University of California at Santa Barbara, and its contributors. ## ## ## ## 4. Neither the name of the University nor the names of its ## ## contributors may be used to endorse or promote products derived ## ## from this software without specific prior written permission. ## ## ## ## THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" AND ANY ## ## EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ## ## WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE ## ## DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ## ## ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ## ## DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ## ## OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ## ## HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, ## ## STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ## ## ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ## ## POSSIBILITY OF SUCH DAMAGE. ## ## ## ############################################################################### # $Header: /export/home/gjanee/bucket99/paradigms/RCS/Adaptor_TermMapping.py,v 1.2 2004/02/25 00:17:19 gjanee Exp $ # SYNOPSIS # # Adaptor_TermMapping (vocabulary, newVocabulary, dictionary, paradigm, # defaultMapping=None) # # vocabulary # The vocabulary whose terms are to be mapped, e.g., "ADL # Object Type Thesaurus". # # newVocabulary # The new vocabulary, e.g., "INTERNAL". # # dictionary # A dictionary that maps zero or more terms from # 'vocabulary' to terms from 'newVocabulary'. The target # of a mapping may be a single term from 'newVocabulary', # as in: # # { "Aerial photographs" : "AIRPHOTO", # "Maps" : "MAP", # ... } # # Or, the target of a mapping may be a boolean combination # of terms from 'newVocabulary'. A combination is # described by a list consisting of a boolean operator # followed by two or more operands (in the case of # operators "AND" and "OR") or exactly two operands (in # the case of operator "AND NOT"); each operand may be a # single term or, recursively, a list describing a # sub-combination. For example: # # { "Images" : ["AND NOT", ["OR", "DCMI:Image", # "DCMI:StillImage"], # "DCMI:MovingImage"], # ... } # # paradigm # The underlying hierarchical paradigm. # # defaultMapping # If not None, the common mapping of terms from # 'vocabulary' that are not present in 'dictionary', e.g., # "OTHER". # # DESCRIPTION # # An adaptor that translates a hierarchical constraint by mapping # the vocabulary and term in the constraint to a new vocabulary # and term, and then passing the modified constraint to another # hierarchical paradigm (the "underlying" paradigm). Multiple # instances of this adaptor may be nested to perform multiple # mappings. # # This adaptor performs the following mappings: # # (vocabulary, T) --> (newVocabulary, dictionary[T]) # If term T is present in 'dictionary'. # # (vocabulary, T) --> (newVocabulary, defaultMapping) # If term T is not present in 'dictionary' and # 'defaultMapping' is not None. # # (vocabulary, T) --> (newVocabulary, T) # Otherwise. # # (V, T) --> (V, T) # For any other vocabulary, the constraint is unchanged. # # A mapping whose target is a boolean combination of terms is # translated by passing separately each single (i.e., atomic) term # in the combination to the underlying paradigm and then combining # the resulting queries using the SQL set operator corresponding # to the combination's boolean operator. For example, suppose # that term S maps to combination ["AND", T1, T2], and suppose # that the underlying paradigm returns queries Q1 and Q2 for terms # T1 and T2, respectively. Then this adaptor returns the query # T1 INTERSECT T2. # # This adaptor can be used to map from one vocabulary to another, # as in: # # P.Adaptor_TermMapping( # "ADL Object Type Thesaurus", # "INTERNAL", # { "Aerial photographs" : "AIRPHOTO", # "Maps" : "MAP", # ... }, # P.some_underlying_hierarchical_paradigm(...), # "OTHER") # # It can also be used to collapse hierarchical thesauri. For # example, suppose term "Aerial photographs" is a narrower term of # "Photographs" which in turn is a narrower term of "Images". # These terms can be collapsed to just "Aerial photographs" as # follows: # # P.Adaptor_TermMapping( # "ADL Object Type Thesaurus", # "ADL Object Type Thesaurus", # { "Images" : "Aerial photographs", # "Photographs" : "Aerial photographs" }, # P.some_underlying_hierarchical_paradigm(...)) # # And multiple, nested instances of this adaptor can be used to # map multiple vocabularies into one, as in: # # P.Adaptor_TermMapping( # "ADL Object Type Thesaurus", # "INTERNAL", # { "Images" : "AIRPHOTO", # "Photographs" : "AIRPHOTO", # "Aerial photographs" : "AIRPHOTO", # "Cartographic works" : "MAP", # "Maps" : "MAP" }, # P.Adaptor_TermMapping( # "DLESE Resource Types", # "INTERNAL", # { "Visual" : ["OR", "AIRPHOTO", "MAP"], # "Visual:Map" : "MAP" }, # P.some_underlying_hierarchical_paradigm(...), # "OTHER"), # "OTHER") # # Exceptions thrown: # # none # # AUTHOR # # Greg Janee # gjanee@alexandria.ucsb.edu # # HISTORY # # $Log: Adaptor_TermMapping.py,v $ # Revision 1.2 2004/02/25 00:17:19 gjanee # Minor documentation fix. # # Revision 1.1 2004/01/30 20:24:00 gjanee # Initial revision # import types import edu.ucsb.adl.middleware M = edu.ucsb.adl.middleware import UniversalTranslator UT = UniversalTranslator def _validateMappingTarget (target): UT.assertPolytype(target, [types.StringType, types.ListType]) if __debug__: if isinstance(target, types.ListType): UT.assertListNonempty(target) UT.assertBooleanOperator(target[0]) UT.assertBooleanOperatorOperandConsistency(target[0], target[1:]) for item in target[1:]: _validateMappingTarget(item) class Adaptor_TermMapping (UT.Paradigm): def __init__ (self, vocabulary, newVocabulary, dictionary, paradigm, defaultMapping=None): UT.assertType(vocabulary, types.StringType) UT.assertType(newVocabulary, types.StringType) UT.assertType(dictionary, types.DictionaryType) UT.assertListElementType(dictionary.keys(), types.StringType) if __debug__: for target in dictionary.values(): _validateMappingTarget(target) UT.assertType(paradigm, UT.Paradigm) UT.assertPolytype(defaultMapping, [types.StringType, types.NoneType]) self.vocabulary = vocabulary self.newVocabulary = newVocabulary self.dictionary = dictionary self.paradigm = paradigm self.defaultMapping = defaultMapping def translateBucketAtomic (self, constraint, vocabularies): UT.assertType(constraint, M.Query.HierarchicalConstraint) newConstraint = self._map(constraint) if isinstance(newConstraint, M.Query.HierarchicalConstraint): return self.paradigm.translateBucketAtomic(newConstraint, vocabularies) else: return self._processBooleanCombination(constraint, newConstraint, vocabularies) def translateBucketBoolean (self, operator, constraints, vocabularies): UT.assertBooleanOperator(operator) UT.assertType(constraints, types.ListType) UT.assertListElementType(constraints, M.Query.HierarchicalConstraint) UT.assertBooleanOperatorOperandConsistency(operator, constraints) UT.assertListElementCommonValue(constraints, lambda c: c.getBucket()) newConstraints = [] for constraint in constraints: newConstraint = self._map(constraint) if not isinstance(newConstraint, M.Query.HierarchicalConstraint): return None newConstraints += [newConstraint] return self.paradigm.translateBucketBoolean(operator, newConstraints, vocabularies) def _map (self, constraint): if constraint.getVocabulary() == self.vocabulary: if self.dictionary.has_key(constraint.getTerm()): newTerm = self.dictionary[constraint.getTerm()] if isinstance(newTerm, types.ListType): # i.e., a boolean combination return newTerm elif self.defaultMapping != None: newTerm = self.defaultMapping else: newTerm = constraint.getTerm() return M.Query.HierarchicalConstraint( constraint.getBucket(), constraint.getField(), constraint.getOperator(), newTerm, self.newVocabulary) else: return constraint def _processBooleanCombination (self, originalConstraint, combination, vocabularies): operator = combination[0] operands = combination[1:] allSimpleTerms = 1 for o in operands: if not isinstance(o, types.StringType): allSimpleTerms = 0 break if allSimpleTerms: constraints = [] for term in operands: constraints += [M.Query.HierarchicalConstraint( originalConstraint.getBucket(), originalConstraint.getField(), originalConstraint.getOperator(), term, self.newVocabulary)] query = self.paradigm.translateBucketBoolean(operator, constraints, vocabularies) UT.assertPolytype(query, [types.NoneType, UT.Select, UT.Query]) if query != None: return query queries = [] for item in operands: if isinstance(item, types.StringType): query = self.paradigm.translateBucketAtomic( M.Query.HierarchicalConstraint( originalConstraint.getBucket(), originalConstraint.getField(), originalConstraint.getOperator(), item, self.newVocabulary), vocabularies) UT.assertPolytype(query, [UT.Select, UT.Query]) queries += [query] elif isinstance(item, types.ListType): queries += [self._processBooleanCombination( originalConstraint, item, vocabularies)] else: UT.UnhandledCase() return UT._unify(operator, queries)