SolrJ nested documents - solr

I have is this:
public class Product {
#Field("object_id")
private String objectId;
private List<MyObject> listOfMyObjects;
}
I use SolrJ to save the info. How can I make listOfMyObjects look like list of nested documents in Solr response. I can make the field multivalued, but I need the list to be list of documents.
I can see that this question is asked few times(e.g. Solrj Block Join Bean support ) but no answer. Solr supports nested documents, but how to make it happen using SolrJ with annotations and schema.xml.

Related

Is there a way to boost based on value of an index property in Hybris solr?

We have a requirement wherein we need to make boosting for a field dynamic. Let's say that we have an indexed property foo, we need to perform a mathematical calculation on foo to determine its boost value which would be different for every product.
Is this doable in Hybris Solr?
Note: I'm using SAP CX 2105 and Solr 8.9.0 with Dismax Query Parse.
And above requirement can be done in standalone Solr application as following.
#Resource
private SolrQuery solrQuery;
private void addBoosts()
{
solrQuery.add("boost", "sub(20, sqrt(field(foo)))");
}
In Hybris, I have tried following
#Resource
private SearchQuery searchQuery;
private void addBoosts()
{
searchQuery.addQuery("boost", "sub(20, sqrt(field(foo)))");
}
And also this
#Resource
private SearchQuery searchQuery;
private void addBoosts()
{
searchQuery.addQuery("boost", "sub(20, sqrt(field(foo)))");
}
Both don't affect search order of the result.

Hybris Solr - how to exclude certain facet values when creating SearchQueryData

I am searching in Hybris using Solr. There are certain facet values for category that I want to exclude from that specific(those categories need to be visible to other searches) search. My Solr query is as following:
q=*:*&spellcheck=true&spellcheck.dictionary=en&spellcheck.collate=true&spellcheck.q=&fq={!tag=fk6}(type\-facet_string:ANSI)&fq=(((catalogId:"ProductCatalog") AND (catalogVersion:Online)))&start=0&rows=100&facet=true&facet.field=allCategories_string_mv&facet.field={!ex=fk0}productLine_string_mv&facet.field={!ex=fk8}style-facet_string&facet.field={!ex=fk5}price_usd_string&facet.field={!ex=fk4}allPromotions_string_mv&facet.field={!ex=fk6}type-facet_string&facet.field={!ex=fk1}size-facet_string&facet.field=categoryPath_string_mv&facet.field={!ex=fk9}availableInStores_string_mv&facet.field=category_string_mv&sort=name_sortable_en_sortabletext asc,score desc&facet.mincount=1&facet.limit=-1&facet.sort=count
I don't have the ability to use raw query. All I can use is Hybris native SearchStateData and SearchQueryData. Category facet can be included in the search but I need to exclude from it i.e CategoryA and CategoryB. Right now my code just sets the value in SearchQueryData as a String in a following way:
":type-facet:" + type; or ":category:" + category
I have tried :category:(-\"CategoryA\"); but it does not end up in the final Solr query. Can anyone point me in the right direction?
In the backoffice of hybris you can install the Commerce Search Perspective with the extension backofficesolrsearch.
In this perspecetive you can enable or disable facets for searching in frontend. Is this what you are looking for?
Here is the belongig hybris wiki page to it.
Refer SearchResponseFacetsPopulator and you can override its method by creating custom populator
MySearchResponseFacetsPopulator :
public class MySearchResponseFacetsPopulator<FACET_SEARCH_CONFIG_TYPE, INDEXED_TYPE_TYPE, INDEXED_PROPERTY_TYPE, INDEXED_TYPE_SORT_TYPE, ITEM>
extends
SearchResponseFacetsPopulator<FACET_SEARCH_CONFIG_TYPE, INDEXED_TYPE_TYPE, INDEXED_PROPERTY_TYPE, INDEXED_TYPE_SORT_TYPE, ITEM>
{
#Override
public void populate(
final SolrSearchResponse<FACET_SEARCH_CONFIG_TYPE, INDEXED_TYPE_TYPE, INDEXED_PROPERTY_TYPE, SearchQuery, INDEXED_TYPE_SORT_TYPE, SearchResult> source,
final FacetSearchPageData<SolrSearchQueryData, ITEM> target)
{
super.populate(source, target);
}
#Override
protected List<FacetData<SolrSearchQueryData>> buildFacets(final SearchResult solrSearchResult,
final SolrSearchQueryData searchQueryData, final IndexedType indexedType)
{
// Do your stuff here
}
}
xml :
<alias name="defaultMyCommerceSearchResponseFacetsPopulator" alias="commerceSearchResponseFacetsPopulator" />
<bean id="defaultMyCommerceSearchResponseFacetsPopulator" class="com.my.facades.populators.MySearchResponseFacetsPopulator"
parent="defaultCommerceSearchResponseFacetsPopulator" />

Queries with Objectify: UmbrellaException

I am using Objectify to manage GAE Datastore for my GWT app. The problem is that I am not using queries properly and I get UmbrellaExceptions as per below:
Caused by: java.lang.RuntimeException: Server Error: java.lang.String cannot be cast to java.lang.Number
at com.google.web.bindery.requestfactory.shared.Receiver.onFailure(Receiver.java:44)
Say that I have a class Box with a unique field String id. I want to get the Box object whose id == "cHVQP6zZiUjM"
This is how I do it now:
public Box getBox(String boxId)
{
Objectify ofy = ObjectifyService.begin();
Query<Box> q=ofy.query(Box.class).filter("id",boxId);
Box targetBox = q.get();
return targetBox;
}
#Entity
public class Box extends DatastoreObject{
private String id;
private String title;
}
I tried doing this with ofy.load() but that method is not defined in my class Objectify (I don't know why).
Your key is encoded. Try using:
Box targetBox = ofy.get(Box.class, KeyFactory.stringToKey(boxId));
To decode your key.
The short answer: You are missing the #Id annotation in your entity.
The long answer: Id fields are special in the datastore. The id is not a real property, but rather a part of the Key that identifies the entity. You can't really filter on id fields, but you can filter on a special field called __key__. Objectify is somewhat clever about letting you filter by the id field and converting this to a __key__ filter under the covers, but it can't do it if you don't annotate the entity properly!
Actually I'm a little confused because Objectify shouldn't let you register the entity without an #Id field.
By the way, there are two sections of the documentation: Objectify4 (release coming soon) and Objectify3. Since you're using Ofy3, there is no load() method.
Another thing: Get-by-key operations are strongly preferred to queries when the operations are equivalent (as they are in your example).

How do Solrj pojo Java types map to Solr types?

I'm new to Solr, and I'm trying to use Solrj pojo's to create my documents.
Is there a mapping of Solr types to Java I should adhere to in my pojo's? is everything in the pojo a String? is there a magical mapping from Java basic types to Solr and it's transparent?
This seems like a basic question but I can't find an answer.
TIA.
You can map pojo with solr types using #Field annotation of solrj
below is the example code
import org.apache.solr.client.solrj.beans.Field;
public class Person {
#Field
private int id;
#Field("first_name")
private String firstName;
#Field("last_name")
private String lastName;
#Field
private String age;
// Getters & setters
}
your schema.xml should contain the fields id, first_name, last_name, age.
The answer to this question appears to be that for Solrj beans (using #Field) the Java type of the field is a Java OBJECT that corresponds to the solr.*Field type.
For instance solr.BoolField maps to java.lang.Boolean.
Same follows for Long, Integer, Float, ...
I hope this helps the next poor soul :-)
Solrj can stream the document as XML or Binary using the RequestWriter. The document.addField method does take an object, so it is ok to pass Java datatypes, but I have not seen a mapping. If there is one it probably assumes the basic data types. If you look at the example code it is so.
If I remember correctly (this was from a while back), we just had an issue with dates, and wrote our own formatter for it. This was from the Solr 1.2 days and that code worked fine and is still in production
http://lucene.apache.org/solr/api-4_0_0-BETA/org/apache/solr/common/SolrInputDocument.html
Here is the JavaDoc for the InputType. http://lucene.apache.org/solr/api-4_0_0-BETA/org/apache/solr/common/SolrInputField.html

Limiting terms in Solr's TermsComponent to terms originating from certain documents

I am using Solrs TermsComponent to implement an autocomplete feature. My documents contain tags which I have indexed in a "tags" field. Now I can use TermsComponent to find out which tags are used in all the stored documents. This works pretty well so far.
However there is some additional requirement: Every document has an owner field which contains the ID of the user who owns it. The autocomplete list should only contain tags from documents, that the user who is requesting the autocomplete is actually owning.
I have tried to set the query parameter, however this seems to be ignored by the TermsComponent:
public static List<String> findUniqueTags(String beginningWith, User owner) throws IOException {
SolrParams q = new SolrQuery().setQueryType("/terms")
.setQuery("owner:" + owner.id.toString())
.set(TermsParams.TERMS, true).set(TermsParams.TERMS_FIELD, "tags")
.set(TermsParams.TERMS_LOWER, beginningWith)
.set(TermsParams.TERMS_LOWER_INCLUSIVE, false)
.set(TermsParams.TERMS_PREFIX_STR, beginningWith);
QueryResponse queryResponse;
try {
queryResponse = getSolrServer().query(q);
} catch (SolrServerException e) {
Logger.error(e, "Error when querying server.");
throw new IOException(e);
}
NamedList tags = (NamedList) ((NamedList)queryResponse.getResponse().get("terms")).get("tags");
List<String> result = new ArrayList<String>();
for (Iterator iterator = tags.iterator(); iterator.hasNext();) {
Map.Entry tag = (Map.Entry) iterator.next();
result.add(tag.getKey().toString());
}
return result;
}
So is there a way of limiting the tags returned by TermsComponent, or do I manually have to query all the tags of the user and filter them myself?
According to this and that post on the Solr mailing list, filtering on the terms component is not possible because it operates on raw index data.
Apparently, the Solr developers are working on a real autosuggest component that supports your filtering.
Depending on your requirements you might be able to use the faceting component for autocomplete instead of the terms component. It fully supports filter queries for reducing the set of eligible tags to a subset of the documents in the index.

Resources