cancel
Showing results for 
Search instead for 
Did you mean: 

How to model a key/value multivalued property?

franco_valente
Champ in-the-making
Champ in-the-making
Hi,

I need to model a key/value "multivalued" property.I.e:
What I need is to tag contents by giving a weight to each tag, for example:

Psychology => 5
sport => 2
personal => 6

So, I can get my own taggable aspect by implementing this

<aspect name="l4a:TT1taggable">
   <title>Tassonomia TT-1</title>
   <parent>cm:classifiable</parent>
   <properties>
      <property name="l4a:TT1categories">
         <title>Categories</title>
         <type>d:category</type>
         <mandatory>false</mandatory>
         <multiple>true</multiple>
         <index enabled="true">
            <atomic>true</atomic>
            <stored>true</stored>
            <tokenised>true</tokenised>
         </index>
      </property>
   </properties>
</aspect>

But I want my "l4a:TT1categories" property to be a list of key/value items.
I know this kind of question is not specific for categories only. This is a  general modeling question.
How can I model this context? How do you suggest to continue?
10 REPLIES 10

franco_valente
Champ in-the-making
Champ in-the-making
Any idea or suggestion?
Thinking about creating a custom datatype for a Map<String, int> property… But somewhere in developer forum I read that people discourages of doing this, because it's a very low level hack.
Can you suggest some workaround? The numeric value should be searchable too…

soulpower
Champ in-the-making
Champ in-the-making
I don't know if what I'm writing is right but… try  Smiley Very Happy

Create an aspect called l4a:TT1rankable which inherits from your aspect l4a:TT1taggable. It must have an int property (for ranking).
Then in form definition (share-config-custom.xml) you should specify a custom ftl control template which lets you select both the category and the int value.

Hope this helps,
Roberto

franco_valente
Champ in-the-making
Champ in-the-making
Inheritance between aspect is not possible into Alfresco

mrogers
Star Contributor
Star Contributor
So you want to be able to search for a document given a label or a number,  the "simple and stupid" solution would just be to store two separate properties.

I think how you model this depends upon your other requirements,  for example I can see that you want to mark your documents with "Sport", "Psychology" and "Personal".    However its not clear to me what you intend to do with the related number.

franco_valente
Champ in-the-making
Champ in-the-making
However its not clear to me what you intend to do with the related number.

I need to tag contents by giving a weight to each tag. The weight of the tag should represent the importance that the tag has in relation to the content. For example I upload on alfresco an interview or a survey, taken from students of a school (obviously the interview contains questions about more than one discipline or argument), and I want to be able to say: "This interview is MORE about Psicology, and LESS about Sport", so I will tag the content inserting the tag "psicology" with weight 8, and the tag "sport" with weight 3 (min=0, max=10). And so on for all my interview.
At a certain time, a teacher or a psicology researcher will log in to alfresco, and He will performs a sort of query in the advanced search by saying: "Dear Alfresco, give me all interviews that have tag "psicology" greather than 7, and tag "sociology" lesser than 3".

The number related to the tag must be treated as a number, in this way I can perform a lucen query using > or < or a range.

Hope this explains better the scenario, Thanks

soulpower
Champ in-the-making
Champ in-the-making
I think it's a reasonable scenario. A feature like this could be a lot useful for finding interesting items during searches, which would have been excluded in simple searches.
For example one can tags the Mona Lisa with "Virtuous woman" category and weight 9 (an high score because it's the main character inside the paint), and "Chinese landscape" with tag 3 (because it's usually less considered). In this way, if a user searches landscapes with a given level of importance into the repository, he can find the Mona Lisa and admire the beautiful landscape.
Sure it could be a good functionality to have.

afaust
Legendary Innovator
Legendary Innovator
Hello Francesco,

one idea that comes to mind is to use a two-level category to classify your content. The first level might define the actual tag while the second level provides subcategories for the specific range of weights (since it is finite in your case with relatively few values). The content would be classified using the second level categories according to the weight chosen by the user. The Lucene search would then query by category path, ORing all weight subcategories for a specific tag that fall within the range specified in the search parameters by the user.

You could also use a custom property type - like ContentData was before 3.2 -, which would evaluate to a specific String representation for Lucene (I think either via toString or a specific Tokenizer you would have to register). At the moment I do not know what would be required to provide range query capabilities for such a property type in Lucene, but this is what I would aim for in this case to simplify the search query.

For the last option bear in mind though, that I am a developer who's proficient in Java and the extension possibilities of both Alfresco and the included libraries. Customizing Alfresco on such a low level is not for the fainthearted, and can significantly impact stability and performance when done improperly. On the other hand, I would disagree with most people who flat-out discourage doing this or consider this to be a hack - it depends on your proficiency, the "cleanliness" of the solution and your willingness to accept additional long-term maintenance costs (which IMHO can be negligible, if done properly).

In your case I would opt for the category approach. It uses standard content types and only requires some custom logic to prepare queries as well as one or two custom form controls to make it work.

Regards
Axel Faust

franco_valente
Champ in-the-making
Champ in-the-making
Thanks for your advices Axel,

I will try the first option. Only one thing: you said
The Lucene search would then query by category path, ORing all weight subcategories for a specific tag that fall within the range specified in the search parameters by the user.
But I read in the Alfresco Lucene wiki http://wiki.alfresco.com/wiki/Lucene that Multi-valued fields are treated as if they were tokenised in phrase searches.
Can I perform range queries on lucene using [6 TO 10] as in http://wiki.alfresco.com/wiki/Full_Text_Search_Query_Syntax#Ranges is said:
… if the d:text property is tokenised then you may get unexpected results (unless the property is both tokenised and untokenised in the index) …
Can you explain me what does It means in the case I choose your first suggestion?

Thanks again,
Francesco

afaust
Legendary Innovator
Legendary Innovator
Hello Francesco,

the multi-valued part in the wiki means that if you have a property that has both the value 1 and 2, you can then find that value by either query "@preSmiley Tonguerop:"1"" or "@preSmiley Tonguerop:"2"". The same goes for categories, but instead of a property selector you use a path selector, so your queries are either
PATH:"/pre:aspectQName/cm:category1Name/cm:subcategory1_1Name//*"
or
PATH:"/pre:aspectQName/cm:category2Name/cm:subcategory2_1Name//*"
if both subcategory1_1 and subcategory2_1 have been applied on a multi-valued category property field.

The problem is that you can not perform range queries on categories as you would on regular properties with supported data types (date, number …). So in order to get a content item with a specific tag and weight less than X, you would have to create a query with a couple of PATH selectors that check if the item has either weight from 0 to X-1 (thus OR-relation between selectors). E.g.
(PATH:"/pre:aspectQName/cm:category1Name/cm:subcategory1_1Name//*" OR PATH:"/pre:aspectQName/cm:category1Name/cm:subcategory1_2Name//*")