Search by an inputstream property - full-text-search

I have a question about making a xpath expression for filtering resources by a property of type inputStream called data.
How can I do a text search, for example this is working:
String xpath1 = "<my app path>//element(*, nt:resource) [jcr:contains(#jcr:mimeType,'*plain*')]";
String xpath2 = "<my app path>//element(*, nt:resource) [jcr:contains(#jcr:encoding,'*utf*')]";
But this is not working.
String xpath3 = "<my app path>//element(*, nt:resource) [jcr:contains(#jcr:data,'*plain*')]";
The really fact is that we use some custom nodes, let's explain the properties definitions:
In Java Terms...
public class Resource extends BaseNode {
/** Encoding media type. It cannot be null or empty. */
#Field(jcrName = "jcr:encoding", jcrDefaultValue = "")
private String encoding;
/** Resource's MIME type. It cannot be null or empty. */
#Field(jcrName="jcr:mimeType", jcrDefaultValue = "")
private String mimeType;
/** Resource's size (bytes). */
#Field(jcrName="skl:size")
private long size;
/** Resource's content data as stream. It cannot be null. */
#Field(jcrName="jcr:data")
private InputStream data;
...
}
#Node(jcrType = "baseNode", isAbstract = true)
public abstract class BaseNode {
#Field(jcrName = "name", id = true)
protected String name;
#Field(jcrName = "creationDate")
protected Date creationDate;
...
}
And in JackRabbit Terms...
<!-- Base node type definition -->
<nodeType name="docs:baseNode"
isMixin="false"
hasOrderableChildNodes="false" >
<supertypes>
<supertype>nt:hierarchyNode</supertype>
</supertypes>
<propertyDefinition name="docs:name"
requiredType="String"
autoCreated="false"
mandatory="true"
onParentVersion="COPY"
protected="false"
multiple="false" />
<propertyDefinition name="docs:searchPath"
requiredType="String"
autoCreated="false"
mandatory="false"
onParentVersion="COPY"
protected="false"
multiple="false" />
<propertyDefinition name="docs:creationDate"
requiredType="Date"
autoCreated="false"
mandatory="true"
onParentVersion="COPY"
protected="false"
multiple="false" />
<propertyDefinition name="docs:lastModified"
requiredType="Date"
autoCreated="false"
mandatory="true"
onParentVersion="COPY"
protected="false"
multiple="false" />
<childNodeDefinition name="*"
defaultPrimaryType="docs:baseNode"
autoCreated="false"
mandatory="false"
onParentVersion="COPY"
protected="false"
sameNameSiblings="false">
<requiredPrimaryTypes>
<requiredPrimaryType>docs:baseNode</requiredPrimaryType>
</requiredPrimaryTypes>
</childNodeDefinition>
</nodeType>
<!-- Resource node type definition -->
<nodeType name="skl:resource"
isMixin="false"
hasOrderableChildNodes="false" >
<supertypes>
<supertype>docs:baseNode</supertype>
<supertype>nt:resource</supertype>
</supertypes>
<propertyDefinition name="skl:size"
requiredType="Long"
autoCreated="false"
mandatory="true"
onParentVersion="COPY"
protected="false"
multiple="false" />
<propertyDefinition name="skl:externalUri"
requiredType="String"
autoCreated="false"
mandatory="false"
onParentVersion="COPY"
protected="false"
multiple="false" />
</nodeType>
The point is, how do I do this query in order to filter by the jcr:data property.

I think you have to turn on text extraction so that the searchable text from your "jcr:data" property will be indexed. See this email thread on the Jackrabbit discussion list.
BTW, the JCR CND format is a much more compact way of describing your node types.

Related

Solr Sort Hybris

I have a provider, wich index stock for product for every unit, this way:
for (Map.Entry<B2BUnitModel, Integer> unit : stockByUnit.entrySet() )
{
document.addField(indexedProperty, hasStock(unit.getValue()), unitUid(unit.getKey()));
}
so this is result after index in solr:
"localStockForUnt_001_boolean": true,
"localStockForUnt_002_boolean": true,
where localStockForUnt is SolrIndexedProperty, 001 and 002 are the units and true or false are the indexed value.
this is the impex to create it:
INSERT_UPDATE SolrIndexedProperty;solrIndexedType(identifier)`[unique=true];name[unique=true];type(code);sortableType(code);currency[default=false];localized[default=false];multiValue[default=false];useForSpellchecking[default=false];useForAutocomplete[default=false];fieldValueProvider;valueProviderParameter`
;$solrIndexedType; localStockForUnt ;boolean ; ; ; ; ; ; ;myResolver;
so I added it inside the 'sort' called 'relevance' in hmc, this 'sort' just have this field in hmc.
My doubt is, how can I set to it sort my result using for example localStockForUnt_002_boolean?
I did set sort in controller manually to test, I did set it to "relevance", but since the provider of field used in relevance (localStockForUnt) index two diferent informations, how can I select which one to use?
Actually what you are trying to do here was already been initiated and used in several cases by Hybris, for example:
localized properties like the name, indexed as name_en_string.
properties with currency like price is indexed as priceValue_eur_double and also used for Sort.
For :priceValue_eur_double | For : localStockForUnt_001_boolean.
priceValue is the field's name | localStockForUnt is the field's name.
euris the field qualifier | 001 is the field qualifier.
double is the field type | boolean is the field type.
So your case here is not different than these two examples, hence you need just to know how to use what's already exists.
Actually nothing magical about how these two examples works!
First of all, add new boolean attribute to SolrIndexedPropertyModel let's call it isB2bUnit :
<!-- add this to your *-items.xml -->
<itemtype code="SolrIndexedProperty" autocreate="false" generate="false">
<attributes>
<attribute qualifier="isB2bUnit" type="java.lang.boolean">
<persistence type="property" />
<!-- i would prefer to add a default value here : FALSE -->
</attribute>
</attributes>
</itemtype>
Next you have to add the same boolean attribute in the IndexedProperty dto :
<!-- add this to your *-beans.xml -->
<bean class="de.hybris.platform.solrfacetsearch.config.IndexedProperty">
<property name="isB2bUnit" type="boolean"/>
</bean>
Then you need to override DefaultIndexedPropertyPopulator it's the responsible for converting from SolrIndexedProperty to IndexedProperty:
public class MyIndexedPropertyPopulator extends DefaultIndexedPropertyPopulator {
#Override
public void populate(SolrIndexedPropertyModel source, IndexedProperty target) throws ConversionException {
super.populate(source, target);
//add this line
target.setIsB2bUnit(source.getIsB2bUnit());
}
}
Register the propulator into spring.
<!-- add this to your *-spring.xml -->
<alias name="myIndexedPropertyPopulator" alias="indexedPropertyPopulator" />
<bean id="myIndexedPropertyPopulator" class="com.foo.bar.MyIndexedPropertyPopulator" parent="defaultIndexedPropertyPopulator" />
The idea is to hook into this method DefaultFieldNameTranslator.translateFromProperty(...) and force it to add your specific fieldQualifier which is b2bUnit.code to the fieldName if the isB2bUnit of the Indexedproperty is TRUE.
The original DefaultFieldNameTranslator.translateFromProperty(...) is like this :
protected String translateFromProperty(SearchQuery searchQuery, IndexedProperty indexedProperty, FieldType fieldType) {
//...
if(qualifierProvider != null && qualifierProvider.canApply(indexedProperty)) {
Qualifier qualifier = qualifierProvider.getCurrentQualifier();
fieldQualifier = qualifier != null?qualifier.toFieldQualifier():null;
} else if(indexedProperty.isLocalized()) {
fieldQualifier = searchQuery.getLanguage();
} else if(indexedProperty.isCurrency()) {
fieldQualifier = searchQuery.getCurrency();
}
//you have to add your else if here!!!
return this.fieldNameProvider.getFieldName(indexedProperty, fieldQualifier, fieldType);
}
So create MyFieldNameTranslator that extends from DefaultFieldNameTranslator and override translateFromProperty(...).
Note: SomeB2bUnitService this service is not real but it should be able to return the current b2bUnit.
public class MyFieldNameTranslator extends DefaultFieldNameTranslator {
//To be injected!!
private SomeB2bUnitService someB2bUnitService;
#Override
protected String translateFromProperty(SearchQuery searchQuery, IndexedProperty indexedProperty, FieldType fieldType) {
//...
//...
else if(indexedProperty.getIsB2bUnit()) {
fieldQualifier = someB2bUnitService.getCurrentB2bUnit().getCode();
}
return this.fieldNameProvider.getFieldName(indexedProperty, fieldQualifier, fieldType);
}
}
Register the Translator into Spring :
<!-- add this to your *-spring.xml -->
<alias name="myfieldNameTranslator" alias="fieldNameTranslator" />
<bean id="myfieldNameTranslator" class="com.foo.bar.MyFieldNameTranslator" parent="defaultfieldNameTranslator">
<property name="someB2bUnitService" ref="someB2bUnitService" />
</bean>
Edit : now all what you have to do is to set isB2bUnit to true for localStockForUnt:
INSERT_UPDATE SolrIndexedProperty;solrIndexedType(identifier)[unique=true] ;name[unique=true] ;type(code) ;isB2bUnit
;$solrIndexedType ;localStockForUnt ;boolean ;true
Note : that some classes and beans may have been changed between Hybris versions but the concept will remains the same.

No ValidatorAction named number found for field JDeveloper 12c

I am trying to migrate an application from Jdeveloper 11g to 12c. I am using Java 8. I am getting following error:
org.apache.struts.validator.ValidatorForm ValidatorForm validate No >ValidatorAction named number found for field searchStnId
org.apache.commons.validator.ValidatorException: No ValidatorAction named >number found for field searchStnId
It is working on 11g, hence all the file entries viz. Validation.xml and entry in Struts-config.xml is there, and I am using struts-1.2.9.jar and Commons-Validator-1.1.3.jar. Can somebody give some suggestion to solve this ?
Code in Files is as follow :-
**/* _______________________________________________
**Validation.xml**
_______________________________________________*/**
<form name="searchForm">
<field property="searchValue" depends="required">
<arg key="prompt.searchStnValue"/>
</field>
<field property="searchStnId" depends="number">
<arg key="prompt.searchStnNumValue" />
</field>
</form>
**/* _______________________________________________
**Struts-config.xml**
_______________________________________________*/**
<plug-in className="org.apache.struts.validator.ValidatorPlugIn">
<set-property property="pathnames"
value="/WEB-INF/validator-rules.xml, /WEB-INF/validation.xml"/>
</plug-in>
**/* _______________________________________________
SearchForm.java
_______________________________________________*/**
public class SearchForm extends ValidatorForm
{
public ActionErrors validate(ActionMapping mapping,HttpServletRequest request)
{
StationLog.debug("Class: SearchForm : Method : ActionForward validate() ");
String actionType = request.getParameter("actionType");
if("deleteStation".equals(actionType)) {
return new ActionErrors();
}
else if("stnId".equals(request.getParameter("searchCriteria")))
{
searchStnId = request.getParameter("searchValue");
searchStnId = searchStnId.trim();
StationLog.error("Class: SearchForm : Method: validate() :: stnId: "+searchStnId);
}
> return super.validate(mapping, request); //THIS IS THE LINE WHICH THROWS EXCEPTION
}
}
**/* _______________________________________________
ApplicationResources.properties
_______________________________________________*/**
prompt.searchStnValue = Search Value
prompt.searchStnNumValue = Entered Value

Golang XML parsing

This is my XML data:
<disk type='file' device='disk'>
<driver name='qemu' type='qcow2'/>
<source file='/var/lib/libvirt/images/generic.qcow2'/>
<backingStore/>
<target dev='hda' bus='ide'/>
<alias name='ide0-0-0'/>
<address type='drive' controller='0' bus='0' target='0' unit='0'/>
</disk>
and my struct is:
// struct for get device details from xml
type DiskXmlInfo struct {
Devices []Disk `xml:"devices>disk"`
}
type Disk struct {
Type string `xml:"device,attr"`
// Name string `xml:"target>dev,attr"`
Name string `xml:"target>dev,attr"`
}
I cannot get the target attribute name. How to get the target attribute name?
Thanks in advance.
You can't read attributes with path, like "target> dev,attr". One option is to use separate type for the target, as you already use for the disk:
type Target struct {
Dev string `xml:"dev,attr"`
Bus string `xml:"bus,attr"`
}
type Disk struct {
...
Target Target `xml:"target"`
}
Another option is to use custom unmarshaller.

Solr boost query by field value and inside newest date

We have the following setup in our schema.xml:
<field name="last_modified" type="date" indexed="true" stored="true" multiValued="false" omitTermFreqAndPositions="true"/>
...
<field name="prefix" type="string" indexed="true" stored="true" omitTermFreqAndPositions="true"/>
Our goal is to sort the docs by
prefix=9999 with newest docs (last modified) first
prefix=1004 or prefix=1005 with newest docs (last modified) first
Our code:
{!boost b=recip(ms(NOW,last_modified),3.16e11,1,1)}prefix:9999^1000000 OR {!boost b=recip(ms(NOW,last_modified),3.16e-11,1,1)}prefix:1004^600000 OR {!boost b=recip(ms(NOW,last_modified),3.16e-11,1,1)}prefix:1005^600000
Result:
The query above does not work as expected!
We thought that omitTermFreqAndPositions=true will force to prevent ITF and the scoring should work. But it does not seem so!
Please help us with this :-)
So we found a solution!
Create your own Similarity (a simple java class)
For a better and simpler descriptions how, please read How to compile a custom similarity class for SOLR / Lucene using Eclipse
The class we used
package com.luxactive;
import org.apache.lucene.index.FieldInvertState;
import org.apache.lucene.search.similarities.DefaultSimilarity;
public class MyNewSimilarityClass extends DefaultSimilarity {
#Override
public float coord(int overlap, int maxOverlap) {
return 1.0f;
}
#Override
public float idf(long docFreq, long numDocs) {
return 1.0f;
}
#Override
public float lengthNorm(FieldInvertState arg0) {
return 1.0f;
}
#Override
public float tf(float freq) {
return 1.0f;
}
}
Create a simple jar with your Similarity
Copy the jar to any folder into your solr server, we used:
SOLRFOLDER/solr-4.8.0/example/solr/dih
The next steps need to be done to every collection you have!
Edit the solrconfig.xml at: SOLRFOLDER/solr-4.8.0/example/solr/collection/conf/solrconfig.xml
Add <lib dir="../dih" regex=".*\.jar" /> to import the custom jar
Edit the schema.xml in the same folder
Add the following
<!-- DEFAULT Factory for custom com.luxactive.MyNewSimilarityClass -->
<similarity class="solr.SchemaSimilarityFactory"/>
<!-- TYPE String -->
<fieldType name="no_term_frequency_string" class="solr.StrField" sortMissingLast="true" >
<similarity class="com.luxactive.MyNewSimilarityClass"/>
</fieldType>
<!-- TYPE Date -->
<fieldType name="no_term_frequency_date" class="solr.TrieDateField" sortMissingLast="true" >
<similarity class="com.luxactive.MyNewSimilarityClass"/>
</fieldType>
<!-- TYPE Int-->
<fieldType name="no_term_frequency_int" class="solr.TrieIntField" sortMissingLast="true" >
<similarity class="com.luxactive.MyNewSimilarityClass"/>
</fieldType>
Here you define your own field types (int, string and date) that use the new Similarity class which will return a boost value like defined in the MyNewSimilarityClass.
Now edit the fields you want to use your custom Similaritry by setting theyr type to one you created.
From: <field name="last_modified" type="date" indexed="true" stored="true" multiValued="false" />
To: <field name="last_modified" type="no_term_frequency_date" indexed="true" stored="true" multiValued="false" />
Restart the solr server and enjoy your boosting :)

xpath - condition expression

I have the below document:
<Ships>
<Class name = "Kongo" >
<Ship name "Kongo" launched = "1913" />
<Ship name = "Hiei" launched = "1914"/>
<Ship name = "Haruna" launched = "1915" />
</Class>
<Class name = "North Carolina">
<Ship name = "Washington" launched= "1941"/>
</Class>
</Ships>
I need to find the years in which ships having the same name as their class were
launched. Which should be
/Ships/Class/Ship[..]/#launched
the '...' part has been omitted as it should be a condition that specifies where the ship name equals to its class name. Does anyone know how to refer to a higher level element's attribute? The query should return '1913'
Ships/Class/Ship[#name = ../#name]/#launched

Resources