How to use the composite filter of app-engine data store queries? - google-app-engine

I have the this function:
#Override
public List<Expense> getExpensesBetween(Date firstDate, Date secondDate) {
Query query = new Query(expenseEntityKind);
query.addFilter("date", Query.FilterOperator.GREATER_THAN_OR_EQUAL, secondDate);
query.addFilter("date", Query.FilterOperator.GREATER_THAN_OR_EQUAL, firstDate);
Iterable<Entity> entities = service.prepare(query).asIterable();
return getReturnedExpenses(entities);
}
I want to return all the expenses between two date i.e greater than or equal 2012-05-01 AND less than or equal 2012-06-01. I took a look at the documentations of Google app-engine. It says that we must use Composite Filters. Google documentations: " However, if you want to set more than one filter on a query, you must use CompositeFilter. You must have at least two filters to use CompositeFilter. However, this documentations seems to be old and i didn't find any function called setFilter();. Any suggestion how to create a composite filter ? I use App-engine sdk 1.6.6. Thanks in advance.

The following is taken from https://cloud.google.com/appengine/docs/java/datastore/queries which might be helpful here
Filter heightMinFilter =
new FilterPredicate("height",
FilterOperator.GREATER_THAN_OR_EQUAL,
minHeight);
Filter heightMaxFilter =
new FilterPredicate("height",
FilterOperator.LESS_THAN_OR_EQUAL,
maxHeight);
//Use CompositeFilter to combine multiple filters
Filter heightRangeFilter =
CompositeFilterOperator.and(heightMinFilter, heightMaxFilter);

The documentation you are looking is for the newest version (1.7.0). That features have been just introduced. Here an example of how to use CompositeFilter (1.7.0 also).

Related

How to dynamically set Azure Search's returned document size?

I know that by default Azure search will return 50 rows and maximum, it can return 1000 in one request. Then I need to use the continueToken to get the rest.
However, when I use SearchServiceClient and SearchParameters to do a query with the SDK, seems I can't pass a parameter to say how many rows I want to return in one request. Did I miss something? There is my simple code, just to return everything.
(what I want is that for certain scenario, return max 50 rows per request, but in other scenario, return 1000 rows per request and loop to get the rest).
var _searchClient = new SearchServiceClient(searchServiceName, new SearchCredentials(apiKey));
var _indexClient = _searchClient.Indexes.GetClient("unit");
SearchParameters sp = new SearchParameters() { SearchMode = SearchMode.All};
var result= _indexClient.Documents.Search(null , sp);
Azure Cognitive Search provides a model class SearchParameters in Microsoft.Azure.Search.Models namespace for the .NET SDK. You can set the Top and Skip properties to control the number of returned docs.
Refer to docs for SearchParameters for more properties. The following article gives examples of using this parameters with search - How to use Azure Cognitive Search from a .NET Application
In Azure Cognitive Search, you use the $count, $top, and $skip parameters to return the number of search results . The following example shows a sample request for total hits on an index called "online-catalog", returned as #odata.count:
GET /indexes/online-catalog/docs?search=*&$top=15&$skip=0&$count=true
For more details, you could refer to this article.

App Engine Search API - Sort Results

I have several entities that I am searching across that include dates, and the Search API works great across all of them except for one thing - sorting.
Here's the data model for one of my entities (simplified of course):
class DepositReceipt(ndb.Expando):
#Sets creation date
creation_date = ndb.DateTimeProperty(auto_now_add=True)
And the code to create the search.Document where de is an instance of the entity:
document = search.Document(doc_id=de.key.urlsafe(),
fields=[search.TextField(name='deposit_key', value=de.key.urlsafe()),
search.DateField(name='created', value=de.creation_date),
search.TextField(name='settings', value=de.settings.urlsafe()),
])
This returns a valid document.
And finally the problem line. I took this snippet from the official GAE Search API tutorial and just changed the direction of the sort to DESCENDING and changed the search expression to created (the date property from the Document above).
expr_list = [search.SortExpression(
expression="created", default_value='',
direction=search.SortExpression.DESCENDING)]
I don't think this is important, but the rest of the search code looks like this:
sort_opts = search.SortOptions(expressions=expr_list)
query_options = search.QueryOptions(
cursor=query_cursor,
limit=_NUM_RESULTS,
sort_options=sort_opts)
query_obj = search.Query(query_string=query, options=query_options)
search_results = search.Index(name=index_name).search(query=query_obj)
In production, I get this error message:
InvalidRequest: Failed to parse search request "settings:ag5zfmdoaWRvbmF0aW9uc3IQCxIIU2V0dGluZ3MYmewDDA"; failed to parse date
Changing the expression="created" to anything else works perfectly fine. This also happens across my other entity types that use dates, so I have no idea what's going on. Advice?
I think default_value needs to be a valid date, rather than '' as you have it.

Indexing PDF documents with addtional search fields using SolrNet?

I found this article useful when indexing documents, however, how can I attach additional fields so I can pass in, say, the ID of the document in our database for use in displaying the search results? I thought by using the Fields (Of the ExtractParameters class) property I could index additional data with the document, but that doesn't seem to work or that is not its function.
Example code:
var solr = ObjectLocator.Instance.Resolve<ISolrOperations<IndexDocument>>();
var guid = Guid.NewGuid().ToString();
using (var fileStream = System.IO.File.OpenRead(Server.MapPath("~/files/") + "greenroof.pdf"))
{
var response =
solr.Extract(
new ExtractParameters(fileStream, "greenRoof1234")
{
ExtractFormat = ExtractFormat.Text,
ExtractOnly = false,
Fields = new[] { new ExtractField("field1", "value1"), new ExtractField("field2", "value2") }
});
}
#aitchnyu is correct, passing the values via the literal.field=value method is the correct way to do this.
However, according to this post on ExtractingRequestHandler support in the SolrNet Google Group, there was a bug with the ExtractParameters.Fields not working properly. This was fixed in the 0.4.0.X versions of SolrNet. Please make sure you are using one of the latest versions of SolrNet. You can obtain that by one of the following means:
Project Site Downloads
NuGet PreRelease Package
Also that discussion has some good examples of using the ExtractingRequestHandler in SolrNet as well as a workaround for adding the additional field values if you cannot upgrade to a newer version of SolrNet.
This is sufficient: http://wiki.apache.org/solr/ExtractingRequestHandler#Literals .
In general use a literal.field=value while uploading.
It turned out not to be an issue with SOLRNet, but my knowledge of SOLR, in general. I needed to specify the fields in my schema. After i added the fields to my schema they were visible in my SOLR query.

Create Index for Full Text Search in Google App Engine

I'm reading the documentation on full text search api (java) in google app engine at https://developers.google.com/appengine/docs/java/search/overview. They have example on getting the index:
public Index getIndex() {
IndexSpec indexSpec = IndexSpec.newBuilder()
.setName("myindex")
.setConsistency(Consistency.PER_DOCUMENT)
.build();
return SearchServiceFactory.getSearchService().getIndex(indexSpec);
}
How about on creating an index? How to create one?
Thanks
You just did. You just created one.
public class IndexSpec
Represents information about an index. This class is used to fully specify the index you want to retrieve from the SearchService. To build an instance use the newBuilder() method and set all required parameters, plus optional values different than the defaults.
https://developers.google.com/appengine/docs/java/javadoc/com/google/appengine/api/search/IndexSpec
You can confirm this by looking at the SearchService
SearchService is also responsible for creating new indexes. For example:
SearchService searchService = SearchServiceFactory.getSearchService();
index = searchService.getIndex(IndexSpec.newBuilder().setName("myindex"));
https://developers.google.com/appengine/docs/java/javadoc/com/google/appengine/api/search/SearchService
Anyway, It seems your code will create a new index if it doesn't exist. That's what the docs suggest:
// Get the index. If not yet created, create it.
Index index = searchService.getIndex(
IndexSpec.newBuilder()
.setIndexName("indexName")
.setConsistency(Consistency.PER_DOCUMENT));
https://developers.google.com/appengine/docs/java/javadoc/com/google/appengine/api/search/Index
Now, what happens if you run the code again and change the Consistency? Do you have the same index with a different consistency? Is the index overwritten? I don't know. I would use the SearchService to lookup existing indexes instead of using code that might create them just to avoid trying to get an index in my code but changing the specs inadvertantly.
An Index is implicitly created when a document is written. Consistency is an attribute of the index, i.e. you can't have two indexes of the same name with different consistencies.

google-app-engine: querying a String property in Model doesn't retrieves result

I have a Model represented as
class Suggestion(db.Model):
text = db.TextProperty()
votes = db.IntegerProperty()
time_added = db.DateTimeProperty(auto_now_add=True)
time_modified = db.DateTimeProperty(auto_now=True)
and I added a Suggestion as
suggestion = Suggestion(text='Adding Suggestion', votes=1)
suggestion.put()
I see that that the value is inserted, now I want to get this suggestion by querying the text property. I did the following
from models import Suggestion
suggestion = Suggestion.all().filter('text = ', 'Adding Suggestion').fetch(1)[0]
print suggestion
The result is empty. How can I make this query work?
Thank you
It is due to the text property cannot be used in filters.
http://code.google.com/appengine/docs/python/datastore/typesandpropertyclasses.html#TextProperty
Unlike StringProperty, a TextProperty value can be more than 500
characters long. However, TextProperty values are not indexed, and
cannot be used in filters or sort orders
There are some alternative ways to do so.
If the "text" shorter than 500 characters, then you may use StringProperty. StringProperty can be used in filter.
Try the 3rd party full text search approaches for google app engine.
http://code.google.com/p/guestbook-example-appengine-full-text-search/
App engine team is working on providing The full text search function in near future.
http://googleappengine.blogspot.com/2012/01/happy-birthday-high-replication.html
Edit
the full text functin is developed by google app engine team:
https://developers.google.com/appengine/docs/python/search/overview

Resources