I have Grails project with domain that has multiple fields, among them I have field 'price'.
I added searchable plugin to the project and it works fine, via general search:
def searchResults = searchableService.search(params.q, params)
Now I need to add price search via range. Example: price between $100 and $200.
I tried following but it doesn't work:
def searchResults = searchableService.search({
queryString(params.q)
lt("price", params.pmax?.trim().toBigDecimal())
},params)
How do I implement range search?
Does it matter what kind of data type it is: Integer, BigDecimal, Long?
Thank you
I did a search by range like this:
def searchResults = searchableService.search(params){
must(queryString(params.q) {
ge('price', params.pmax as BigDecimal)
le('price', params.pmin as BigDecimal)
})
}
[EDITED]
My previous solution doesn't work perfectly.
The right way to do search with numbers with searchable, you need first add this in your domain class:
searchable {
price index: "not_analyzed", format : "0000000000"
}
And then to do the search:
def searchResults = yourDomainClass.search("price:[" + (params.pmin ? params.pmin.trim().padLeft(10, "0") : "*" )+ " TO " + (params.pmax ? params.pmax.trim().padLeft(10, "0") : "*" )+ "]"
All that is need because when your data is indexed, is also textified.
http://brettscott.wordpress.com/2011/11/19/lucene-number-range-search-integers-floats/
http://grails.org/Searchable+Plugin+-+FAQ
Related
I have a multivalue field called freeDaysPool which has multiple dates as strings. With the following code, the search does not return anything. If I leave that field out, the search works just fine with the two other fields. I read that I should use CONTAINS with multivalue fields but then I got query not understandable.
I've tried the back-end field as a date field and as a text field and tested all kinds of query combinations and date formats but no luck. Any help is really appreciated.
This is the search button code:
var query = new Array("");
var cTerms = 0;
// Field 1
var search01 = getComponent("searchcustomReservationField01").getValue();
if (#Contains(#Text(search01),"any city")){"";}
else {query[cTerms++] = '[customReservationField01]="' + search01 +'"'};
// Field 2
var search02 = getComponent("searchcustomReservationField02").getValue();
if (#Contains(#Text(search02),"any city")){"";}
else {query[cTerms++] = '[customReservationField02]="' + search02 + '"'};
// Date 1
var formatter = new java.text.SimpleDateFormat("d.M.yyyy");
query[cTerms++] = 'FIELD freeDaysPool = ' + formatter.format(getComponent("searchcustomDateField01").getValue());
// if query is still empty, we fill it with asterisk
if(query == "" || query == null){
query[cTerms++] = "*";
}
// make all as string
qstring = query.join(" AND ").trim();
sessionScope.searchString = qstring;
It will return query as:
[customReservationField01]="Oslo" AND [customReservationField02]="Oslo" AND FIELD freeDaysPool = 6.2.2015
AFAIK date values in formulas (and a query is a formula) have to be noted like
[06.02.2015]
to compare them. Just try to use your formular in the Notes Client to do a fulltext search. If you get results and no errors you found the correct format. That's at least the way I test queries as I'm not able to remind the syntax for years :-D
Thank you for all the help! Seems that Domino keeps the field type as date field even if you change it back to text field (noticed that from the notes FTsearch). I created completely new text field and added the days as strings in dd.MM.yyyy format. I also search them as strings and it works fine.
The changed code bit now looks like this:
// Date 1
var formatter = new java.text.SimpleDateFormat("dd.MM.yyyy");
query[cTerms++] = '[freeDays] CONTAINS "' + formatter.format(getComponent("searchcustomDateField01").getValue())+'"';
Recently I've started using Apache CMIS and read the official documentation and examples. I haven't noticed anything about paging query results.
There is an example showing how to list folder items, setting maxItemsPerPage using operationContext, but it seems that operationContext can be used inside getChilder method:
int maxItemsPerPage = 5;
int skipCount = 10;
CmisObject object = session.getObject(session.createObjectId(folderId));
Folder folder = (Folder) object;
OperationContext operationContext = session.createOperationContext();
operationContext.setMaxItemsPerPage(maxItemsPerPage);
ItemIterable<CmisObject> children = folder.getChildren(operationContext);
ItemIterable<CmisObject> page = children.skipTo(skipCount).getPage();
This is ok when it comes to listing u folder. But my case is about getting results from custom search query. The basic approach is:
String myType = "my:documentType";
ObjectType type = session.getTypeDefinition(myType);
PropertyDefinition<?> objectIdPropDef = type.getPropertyDefinitions().get(PropertyIds.OBJECT_ID);
String objectIdQueryName = objectIdPropDef.getQueryName();
String queryString = "SELECT " + objectIdQueryName + " FROM " + type.getQueryName();
ItemIterable<QueryResult> results = session.query(queryString, false);
for (QueryResult qResult : results) {
String objectId = qResult.getPropertyValueByQueryName(objectIdQueryName);
Document doc = (Document) session.getObject(session.createObjectId(objectId));
}
This approach will retrieve all documents in a queryResult, but I would like to include startIndex and limit. The idea would be to type something like this:
ItemIterable<QueryResult> results = session.query(queryString, false).skipTo(startIndex).getPage(limit);
I'm not sure about this part: getPage(limit). Is this right approach for paging? Also I would like to retrieve Total Number of Items, so I could know how to set up the max items in grid where my items will be shown. There is a method, but something strange is written in docs, like sometimes the repository can't be aware of max items. This is that method:
results.getTotalNumItems();
I have tried something like:
SELECT COUNT(*)...
but that didn't do the trick :)
Please, could you give me some advice how to do a proper paging from a query result?
Thanks in advance.
Query returns the same ItemIterable that getChildren returns, so you can page a result set returned by a query just like you can page a result set returned by getChildren.
Suppose you have a result page that shows 20 items on the page. Consider this snippet which I am running in the Groovy Console in the OpenCMIS Workbench against a folder with 149 files named testN.txt:
int PAGE_NUM = 1
int PAGE_SIZE = 20
String queryString = "SELECT cmis:name FROM cmis:document where cmis:name like 'test%.txt'"
ItemIterable<QueryResult> results = session.query(queryString, false, operationContext).skipTo(PAGE_NUM * PAGE_SIZE).getPage(PAGE_SIZE)
println "Total items:" + results.getTotalNumItems()
for (QueryResult result : results) {
println result.getPropertyValueByQueryName("cmis:name")
}
println results.getHasMoreItems()
When you run it with PAGE_NUM = 1, you'll get 20 results and the last println statement will return true. Also note that the first println will print 149, the total number of documents that match the search query, but as you point out, not all servers know how to return that.
If you re-run this with PAGE_NUM = 7, you'll get 9 results and the last println returns false because you are at the end of the list.
If you want to see a working search page that leverages OpenCMIS and plain servlets and JSP pages, take a look at the SearchServlet class in The Blend, a sample web app that comes with the book CMIS & Apache Chemistry in Action.
I have a grails domain named Person, in that i have properties: firstName, middleName, lastName and others. I do not have a fullName field in the database, its a transients property in my domain. Now I want to create a search mechanism using all those three. Is there any way to implement this?
-> Update
I thought about this from different perspective and then it hit me !
So i did this,
My query
searchResult = Person.findAll("from Person p where p.firstName LIKE '%" + searchString + "%' or p.middleName LIKE '%" + searchString + "%' or p.lastName LIKE '%" + searchString + "%'")
but when i displayed the result, i limited the number of results, so the user has to enter more specific search string to get desired result. I also added a button "See More" so if the user can see all the fetched results but by default, it would only show a limited number of results.
(I could not answer to my own question so i wrote this in the question itself :D)
As long as there is a getter method I believe the Searchable plugin will work on transients.
public String getFullName()...
you need to pass params to fetch data in limited numbers.
i.e. .findAll(Query,params)
I am wondering about how to search in J2ME. I have been searching in the internet, so many result show to me, and I see in Java2s.com I got a result use RecordFilter and matches method for search in record store.
But my problem is, when I need to pass 2 or more parameters into it. How can result matches with these parameter?
And how to sort descending or ascending like bubble sort?
Concatenate your searches into a single String variable. Separate each of them with ; for example. In the code of the matches method explode the String to get each search criteria.
To make the filter in effect create an instance of SearchFilter and call the matches method with the concantenated String as its param.
For the sort implement the RecordComparator interface ; implement the compare method to build your sort criteria. Make a google search about j2me+recordcomparator to see examples about how to make sorts.
EDIT :
In the code of the matches method explode the String param obtained from the byte[] param. Treat each String exploded to make the criteria.
As I understand you want to pass two string as a search criteria when you wrote :
SearchFilter search = new SearchFilter(txtSearch.getString(), strType);
So in the constructor there should be two params !!!
When you want to make the matching then call
if searchFilter.matches((search1+";"+sType).getBytes())
Then explode the candidate param into two String when you code the matches method.
When I save my Data in RMS I save it as a String[] like I want to save Name, Age,Salary,EmpID for each employee I save it create an array and convert it to bytes and save it in RMS. When i retrieve it i do the reverse process. Now if i want to get employee with names starting with A and with salary 10000 i use the following filter
class UtilFilter implements RecordFilter{
public UtilFilter(String str_searchText,String str_searchText1)
{
this.str_searchText = str_searchText.toLowerCase();
this.str_searchText1 = str_searchText1.toLowerCase();
}
public boolean matches(byte[] bt_byteData)
{
String str_str = "";
String str_str1 = "";
//here goes code how u get back ur String[] from RMS say u get it in Data
str_str = Data[0].trim();
str_str1 = gd_cd.Data[2].trim();
if(str_searchText != null && str_searchText1 != null && str_str.equals(str_searchText) && str_str1.equals(str_searchText1 ))
{
return true;
}
else
{
return false;
}
}
}
This way i can filter any no of parameters.Hope tht helps! :)
For my website, i need to do a search mechanism, in which some of the entry field would be: Country, City, Between Dates (with or without year field), Keywords, etc etc.
My problem is, the user must decide what they wanna search for. For example, if they want to introduce just date, or date and city, or city and keyword.. etc. I dont really know how to do that, i mean, i know how to search for one thing at a time, but i'm not sure how can do this all-in-one.
a) Would i need like something like this: (if-else, if-else) and than write the code for each combination, or there is an easier way to do that?
b )Bytheway, my search mechanism is done the folowing way (i'v never done a search mechanism before, so i dont know if it is the best aproach, would apreciate some comments here also and suggestions):
class book{
String a
String b
...
Date z
String allAttributesTogether() {
a + b + c + ... + z
}
}
then in my controller, i do a double for statment and cross-match the introduced words for the search and the result of allAttributesTogether().
Thanks in advanced, VA
Check out the filter pane plugin.
When you say "search", comes to my mind search engines. But I think you are asking about querying the database, right?
If you are talking about search mechanisms, search engines are a great tool. You can take a look at Lucene, Compass, and ElasticSearch (ES) to name a few. Compass and ES are based on lucene, but are much higher in the abstraction level (easier to use).
I have been using ElasticSearch with great satisfaction.
If you are talking about querying the database, then you can just build a HQL query dynamically. The method bellow should be in a Controller, as it uses the params attribute. It is not tested ok?
List allAttributesTogether() {
def query = " select book from Book book "
def queryParams = [:]
def needsAnd = false
if(params.a || params.b || params.z ){
query += " where "
}
if(params.a){
query += " book.a = :a "
queryParams['a'] = params.a
needsAnd = true
}
if(params.b){
if(needsAnd) query += " and "
query += " book.b = :b "
queryParams['b'] = params.b
needsAnd = true
}
if(params.a){
if(needsAnd) query += " and "
query += " book.z = :z "
queryParams['z'] = params.z
}
return Book.executeQuery(query, queryParams)
}
There is also the alternative of using Criteria builder. You can also use "if" to add clauses to your Criteria clauses.