In solr, there is parameter "fl", which provides projection in query. How can I achieve same feature in liferay?
Thank you in advance for your help and suggestions.
fl is not a projection in a SOLR query, it simply selects the result fields.
First of all: Liferay is using Lucene as search engine - not SOLR.
If "in liferay" means "in the UI": You can't select the result fields in the UI. The results are objects from the database that were filtered by Lucene (for some of the search forms and some configurations the result is retrieved even without Lucene directly from the database using SQL).
If "in liferay" means "in the API": You can select the result fields, if you access the Lucene indexer in low level (the ...ServiceUtil.search methods won't help) and use a FieldSelector:
IndexSearcher indexSearcher = LuceneHelperUtil.getIndexSearcher(companyId);
IndexReader indexReader = indexSearcher.getIndexReader();
FieldSelector fieldSelector = new FieldSelector() {
public FieldSelectorResult accept(String fieldName) {
// Only return "my-field"
if ("my-field".equals(fieldName)) {
return FieldSelectorResult.LOAD_AND_BREAK;
}
return FieldSelectorResult.NO_LOAD;
}
};
TopDocs topDocs = indexSearcher.query(luceneQuery, maxDocuments);
// Retrieve only the selected fields for the hits
List<Document> results = new ArrayList<Document>();
for (int i = 0; i < topDocs.scoreDocs.length; i++) {
results.add(indexReader.document(topDocs.scoreDocs[i].doc, fieldSelector));
}
You can use any of the other query methods as well.
Have a look at com.liferay.portal.search.lucene.LuceneIndexSearcher to find out how to build your query correctly.
Related
I have my data in Azure Search. In my structure there are a lot of fields and I have to filter or search using two of them.
One is Type defined as Edm.String and the other one is memberOf defined as Collection(Edm.String).
Type has values like private:Text, memberOf has values like my.com/field/F001.
I want apply a filter:
filter=Type:'private:Text' AND memberOf:'my.com/field/F001'
as result I receive all records. I read Microsoft's documentation but I can't find a solution.
In my code I have
SearchParameters sp = new SearchParameters()
{
SearchMode = SearchMode.Any,
Skip = currentPage - 1,
IncludeTotalResultCount = true
};
if (!string.IsNullOrEmpty(searchQuery))
sp.Filter = searchQuery;
DocumentSearchResult<VuSearchData> result =
await client.Documents.SearchAsync<VuSearchData>(searchText, sp);
Thanks.
The syntax for filters is different than for full-text search. Filters use OData syntax. The subset of OData supported by Azure Search is documented here.
The filter you want to execute looks like this in OData syntax:
Type eq 'private:Text' and memberOf/any(m: m eq 'my.com/field/F001')
Note the use of any and a lambda expression since memberOf is a collection field.
i want to sort the top 100documents of a solr using a specific field but it sort the whole result set and then display result the following is my code.
query1.setQuery(" Natural Language ");
query1.setStart(0);
query1.setRows(100);
int i=0;
query1.set("df","Text");
query1.setFields("PaperID","TotalPageRank");
query1.setSort("customrank", SolrQuery.ORDER.desc);
Is it possible using solr query to sort the top 100 documents using customrank field?
You can try to use the Query Re-Ranking feature. This allows you to issue one query, retrieve the top N entries and then re-rank these entries according to a second query. This is usually used to have one simple query limit the total number of documents before applying an expensive query to those entries for re-ranking, but the use case seems similar enough.
An adapted version of the example on the documentation page would probably be something like (I haven't been able to test this, so add a comment with adjustments for your use case):
rq={!rerank reRankQuery=$rqq reRankDocs=100 reRankWeight=3}&rqq=_val_=customrank
You might have to tune the rerankweight to get your customrank to contribute more to the final score, as I don't think you can sort explicitly
It is very simple..
SolrQuery query1 = new SolrQuery();
CommonsHttpSolrServer server = new CommonsHttpSolrServer("Your server url");
server.getHttpClient().getParams();
query1.setQuery("Natural Language");
query1.setFields("PaperID", "TotalPageRank");
query1.setStart(0);
query1.setRows(100);
query1.setSort("customrank", SolrQuery.ORDER.desc);
QueryResponse solrresponse = server.query(query1);
SolrDocumentList results = solrresponse.getResults();
for (int i = 0; i < results.size(); ++i) {
String resultsolr = results.get(i).toString();
}
Note: The customrank field shoud be integer, better to have customrank_i
Hope this will help!! Happy coding :)
I'm running a Kind based Query using Java API on GAE.
Here is the sample code:
DatastoreService dataStore = DatastoreServiceFactory.getDatastoreService();
Filter value1Filter = new FilterPredicate(PROPERTY_1, FilterOperator.EQUAL, value1);
Filter value2Filter = new FilterPredicate(PROPERTY_2, FilterOperator.EQUAL, value2);
Filter myFilter = CompositeFilterOperator.and(value1Filter, value2Filter);
Query findQuery = new Query("MyKIND").setFilter(myFilter);
myEntity = dataStore.prepare(findQuery).asSingleEntity();
PROPERTY_1 and PROPERTY_2 are indexed properties. This query works some times and now fails consistently for certain values. Let's say these values are value1 and value2 shown above.
However, if I run the same query using SELECT in the datastore viewer with same values, value1 and value2, it works and shows the result. I earlier suspected this to be a result of eventual consistency. However, the indexed values have been written long back (months earlier) for them to be replicated across the other instances.
Is there a way to correct this situation? Unfortunately, I don't have the key of the entity to query with.
i am trying to create an edismax query and set the query params like the defType, df, q.op...ect pragmatically. I was able to create a boolean query as below but couldn't set the query parameters. any idea how?
private List<String> getBoostedElevationObj(ResponseBuilder rb) {
SolrQueryRequest req = rb.req;
Query query = rb.getQuery();
List<String> docIds = null;
try {
BooleanQuery docIdsBq = new BooleanQuery();
TermQuery tq2 = new TermQuery(new Term("subscription", "yes"));
docIdsBq.add(tq2, BooleanClause.Occur.MUST);
SolrIndexSearcher solrIndexSearcher = req.getSearcher();
DocList docList = solrIndexSearcher.getDocList(query, docIdsBq, null,
0, 5);
DocIterator docIterator = docList.iterator();
docIds = new ArrayList<String>();
int docId;
Document doc = null;
while (docIterator.hasNext()) {
docId = docIterator.nextDoc();
doc = solrIndexSearcher.doc(docId);
docIds.add(doc.get(idField));
}
} catch (Exception e) {
e.printStackTrace();
}
return docIds;
}
Being that those are query parser parameters, and you are eliminating the query parser in these manually constructed queries, the responsibility for some of that functionality falls to you.
defType - Specifies the behavior of the query parser, and since you aren't using a query parser here, you have to construct queries appropriate to the types. If you are searching an int field, NumericRangeQuery is appropriate, etc.
df - This also applies to parsed queries. If you are constructing your queries manually, you need to specify the field.
q.op - When a clause is added to a BooleanQuery, you must also specify a BooleanClause.Occur setting, so there is no default operator.
some other common params:
sort - Passed into the getDocList call, third argument, in the form of a Sort
start, rows and filter - Passed directly into getDocList
fl - You can pass a list of fields to be returned into the IndexSearcher.doc call.
Also, you should keep in mind, that edismax generally produces a DisjunctionMaxQuery to join clauses, rather than a BooleanQuery, and there are significant differences in how they are scored and constructed. In the case of the BooleanQuery you've created this isn't an issue, since: A - it only has one clause, and B - it's being applied as a filter. However, probably worth keeping in mind if you have other cases in mind here in which that might be an issue.
Yet another potentially embarrassing question. Please feel free to point any obvious solution that may have been overlooked - I have searched for solutions previously and found nothing, but sometimes it's a matter of choosing the wrong keywords to search for.
Here's the situation: coded my own RequestHandler a few months ago for an enterprise-y system, in order to inject a few necessary security parameters as an extra filter in all queries made to the solr core. Everything runs smoothly until the part where the docs resulting from a query to the index are collected and then returned to the user.
Basically after the filter is created and the query is executed we get a set of document ids (and scores), but then we have to iterate through the ids in order to build the result set, one hit at a time - which is a good 10x slower that querying the standard requesthandler, and only bound to get worse as the number of results increase. Even worse, since our schema heavily relies on dynamic fields for flexibility, there is no way (that I know of) of previously retrieving the list of fields to retrieve per document, other than testing all possible combinations per doc.
The code below is a simplified version of the one running in production, for querying the SolrIndexSearcher and building the response.
Without further ado, my questions are:
is there any way of retrieving all results at once, instead of building a response document by document?
is there any possibility of getting the list of fields on each result, instead of testing all possible combinations?
any particular WTFs in this code that I should be aware of? Feel free to kick me!
//function that queries index and handles results
private void searchCore(SolrIndexSearcher searcher, Query query,
Filter filter, int num, SolrDocumentList results) {
//Executes the query
TopDocs col = searcher.search(query,filter, num);
//results
ScoreDoc[] docs = col.scoreDocs;
//iterate & build documents
for (ScoreDoc hit : docs) {
Document doc = reader.document(hit.doc);
SolrDocument sdoc = new SolrDocument();
for(Object f : doc.getFields()) {
Field fd = ((Field) f);
//strings
if (fd.isStored() && (fd.stringValue() != null))
sdoc.addField(fd.name(), fd.stringValue());
else if(fd.isStored()) {
//Dynamic Longs
if (fd.name().matches(".*_l") ) {
ByteBuffer a = ByteBuffer.wrap(fd.getBinaryValue(),
fd.getBinaryOffset(), fd.getBinaryLength());
long testLong = a.getLong(0);
sdoc.addField(fd.name(), testLong );
}
//Dynamic Dates
else if(fd.name().matches(".*_dt")) {
ByteBuffer a = ByteBuffer.wrap(fd.getBinaryValue(),
fd.getBinaryOffset(), fd.getBinaryLength());
Date dt = new Date(a.getLong());
sdoc.addField(fd.name(), dt );
}
//...
}
}
results.add(sdoc);
}
}
Per OPs request:
Although this doesn't answer your specific question, I would suggest another option to solve your problem.
To add a Filter to all queries, you can add an "appends" section to the StandardRequestHandler in the SolrConfig.xml file. Add a "fl" (stands for filter) section and add your filter. Every request piped through the StandardRequestHandler will have the filter appended to it automatically.
This filter is treated like any other, so it is cached in the FilterCache. The result is fairly fast filtering (through docIds) at query time. This may allow you to avoid having to pull the individual documents in your solution to apply the filtering criteria.