Lucene facet request on list - missing elements - solr

Let's say that we have entity which have a list of other subentity.
If there is more than one element in list, facet request doesnt count all of them for each group but only for random(probably there is some mechanism) property.
FacetingRequest categoryFacetingRequest = qBuilder.facet()
.name("districtFaceting").onField("address.districtId")
.discrete().orderedBy(FacetSortOrder.COUNT_DESC)
.includeZeroCounts(true).createFacetingRequest();
class Base {
List<Address> adresses = ...
}
class Address {
#Field(analyze = Analyze.NO, store = Store.YES, index = Index.YES)
public String getDistrictId() {
return this.districtId;
}
}
In case of Base will have more than one address, facet request will return only one count for random district id. Other are no incremented.
Is there any solution to have correct results ?

To use faceting requests, the fields on which you want to use faceting should be annotated accordingly with #Facet.
Your code snippet is missing this annotation, which could explain the issue. Could you try adding a #Facet annotation on getDiscritctId?
If you already have one, could you please expand your code sample to include all the relevant annotations that are present in your code? (#Facet, #Indexed, #IndexedEmbedded, ...)
See https://docs.jboss.org/hibernate/stable/search/reference/en-US/html_single/#example-faceting-entity

Related

How to check if records related to fields in custom metadata are changed

I have a scenario where I need to check in opportunity update if particular field values of opportunity which are mentioned in metadata are changed or not, if these values are changed meaning that that record would be considered for update. I have done this with field sets but not sure how we can achieve the same using custom metadata. Attaching the code used for field sets here
Public static boolean isValuesChanged(List<Opportunity> newOpportunitiesList, Map<id,Opportunity> oldOpportunityMap)
{
for(Opportunity oppRecord : newOpportunitiesList)
{
for(Schema.FieldSetMember fieldSetMemberObj : SObjectType.Opportunity.FieldSets.Opportunity_Comparision_FieldSet.getFields())
{
if(oppRecord.get(fieldSetMemberObj.getFieldPath()) != oldOpportunityMap.get(oppRecord.id).get(fieldSetMemberObj.getFieldPath()) && oppRecord.Amount > 0)
{
return true;
}
}
}
return false;
}
This is what I have done when I used field sets. The same I want to do using custom metadata.How can I check changes in Apex ?
Thanks in Advance
Cut it into 2 problems.
Given a set of strings with field api names - how to detect changes
Set<String> fields = new Set<String>{'Name', 'CloseDate', 'StageName'};
Set<Id> oppsToProcess = new Set<Id>();
for(Opportunity opp: newList){
Opportunity old = oldMap.get(opp.Id);
for(String field : fields){
if(opp.get(field) != old.get(field)){
oppsToProcess.add(opp.Id);
break;
}
}
}
Given a custom metadata with field names - how do I make a set of strings out of it.
Solution for this one depends what exactly you have in custom meta:
list with multiple records, each with single field's name?
1 record with field names saved in columns like Field1__c, Field2__c, Field3__c
1 record with list of fields stored comma-separated, like Fields__c = 'Name,CloseDate,StageName'
You'll have to do it yourself, query and loop through first one or call String.split(','); on the last one or...

Return first n element from array in elasticsearch query

I have an array field in document named as IP which contains above 10000 ips as element.
for e.g.
IP:["192.168.a:A","192.168.a:B","192.168.a:C","192.168.A:b"...........]
Now i made a search query with some filter and i got the results but the problem is size of result very huge because of above field.
Now I want to fetch only N ips from array let say only 10 order doesn't matters.
So How do i do that...
update:
Apart from IP field there are others fields also and i applied filter on that field not on IP .I want whole document which satisfies filters .I just want to limit the number of elements in single IP fields.(Let me know if there is any other way apart from using script also ).
This kind of request could solve your problem :
GET ips/_search
{
"query": {
"match_all": {}
},
"script_fields": {
"truncate_ip": {
"script": {
"source": """
String[] trunc_ip = new String[10];
for (int i = 0; i < 10; ++i) {
trunc_ip[i]= params['_source']['IP'][i];
}
return trunc_ip;
"""
}
}
}
}
You can use scriptedFields for generating a new field from existing fields in Elastic Search. Details added as comments.
GET indexName/_search
{
"_source": {
"excludes": "ips" //<======= Exclude from source the IP field (change the name based on your document)
},
"query": {
"match_all": {} // <========== Define relevant filters
},
"script_fields": {
"limited_ips": { // <========= add a new scipted field
"script": {
"source": "params['_source'].ips.stream().limit(2).collect(Collectors.toList())" // <==== Replace 2 with the number of i.ps you want in result.
}
}
}
}
Note:
If you remove _source then only the scripted field will be the part of the result.
Apart from accessing the value of the field, the rest of the syntax is Java. Change as it suits you.
Apart from non-analyzed text fields, use doc['fieldName'] to access the field with-in script. It is faster. See the below excerpt from E.S docs :
By far the fastest most efficient way to access a field value from a
script is to use the doc['field_name'] syntax, which retrieves the
field value from doc values. Doc values are a columnar field value
store, enabled by default on all fields except for analyzed text
fields
By default ES returns only 10 matching results so I am not sure what is your search query and what exactly you want to restrict
no of elements in single ip field
No of ip fields matching your search results
Please clarify above and provide your search query to help further.

Ordering the solr search results based on the indexed fields

I have to order the search results from solr based on some fields which are already indexed.
My current api request is like this without sorting.
http://127.0.0.1:8000/api/v1/search/facets/?page=1&gender=Male&age__gte=19
And it gives the search results based on the indexed order. But I have to reorder this results based on the filed 'last_login' which is already indexed DateTimeField.
Here is my viewset
class ProfileSearchView(FacetMixin, HaystackViewSet):
index_models = [Profile]
serializer_class = ProfileSearchSerializer
pagination_class = PageNumberPagination
facet_serializer_class = ProfileFacetSerializer
filter_backends = [HaystackFilter]
facet_filter_backends = [HaystackFilter, HaystackFacetFilter]
def get_queryset(self, index_models=None):
if not index_models:
index_models = []
queryset = super(ProfileSearchView, self).get_queryset(index_models)
queryset = queryset.order_by('-created_at')
return queryset`
Here I have changed the default search order by 'created_at' value. But for the next request I have order based on the 'last_login' value. I have added a new parameter in my request like this
http://127.0.0.1:8000/api/v1/search/facets/?page=1&gender=Male&age__gte=19&sort='last_login'
but it gives me an error
SolrError: Solr responded with an error (HTTP 400): [Reason: undefined field sort]
How can I achieve this ordering possible? Please help me with a solution.
The URL you provided http://127.0.0.1:8000/api/v1/search/facets/ is not direct SOLR URL. It must be your middle-ware. Since you have tried the query directly against Solr and it works, the problem must be somewhere in middle-ware layer.
Try to print or monitor or check logs to see what URL the midde-ware actually generates and compare it to the valid URL you know works.

How to create complex query parameters in Restangular

I need to create a fairly complex query string in Restangular.
http://vdmta.rd.mycompany.net//people?anr=Smith&attrs=givenName,displayName,name,cn
How do I do this?
So far I am OK getting as far as ?anr=Smith using this:
return Restangular.all('/people').getList({anr:searchTerm});
The last part attrs=x,y,x lets me control which attributes I want back in the search and could change per request I make.
Any advice appreciated.
Regards
i
You should be able to simply add another query parameter where the value is your comma separated list of attributes.
var attributes = ['givenName' , 'displayName']; // attributes you require for the request
var attributesAsString = attributes.join();
return Restangular.all('/people').getList({
anr : searchTerm,
attrs: attributesAsString
});

How to add items to an array one by one in groovy language

I´m developing a grails app, and I already have a domain class "ExtendedUser" wich has info about users like: "name", "bio", "birthDate". Now I´m planning to do statistics about user´s age so I have created another controller "StatisticsController" and the idea is to store all the birthDates in a local array so I can manage multiple calculations with it
class StatisticsController {
// #Secured(["ROLE_COMPANY"])
def teststat(){
def user = ExtendedUser.findAll() //A list with all of the users
def emptyList = [] //AN empty list to store all the birthdates
def k = 0
while (k<=user.size()){
emptyList.add(user[k].birthDate) //Add a new birthdate to the emptyList (The Error)
k++
}
[age: user]
}
}
When I test, it shows me this error message: Cannot get property 'birthDate' on null object
So my question is how is the best way to store all the birthdates in an single array or list, so I can make calculations with it. Thank you
I prefer to .each() in groovy as much as possible. Read about groovy looping here.
For this try something like:
user.each() {
emptylist.push(it.birthdate) //'it' is the name of the default iterator created by the .each()
}
I don't have a grails environment set up on this computer so that is right off the top of my head without being tested but give it a shot.
I would use this approach:
def birthDates = ExtendedUser.findAll().collect { it.birthDate }
The collect method transforms each element of the collection and returns the transformed collection. In this case, users are being transformed into their birth dates.
Can you try:
List dates = ExtendedUser.findAll().birthDate

Resources