I try to get ASIN for movies in my DB, try to match via EAN. I created simple java class to connect with Amazon:
AWSECommerceServiceservice = new AWSECommerceService();
service.setHandlerResolver(new AwsHandlerResolver(AMAZON_SECRET_KEY));
AWSECommerceServicePortType port = service.getAWSECommerceServicePortDE();
Holder<OperationRequest> operationrequest = new Holder<OperationRequest>();
failedItem = 0;
doneItem = 0;
ItemLookup lookup = new ItemLookup();
lookup.setAWSAccessKeyId(AMAZON_ACCESS_ID);
lookup.setAssociateTag(ASSOCIATE_TAG);
ItemLookupRequest request = new ItemLookupRequest();
request.getResponseGroup().add("ItemAttributes");
request.setSearchIndex("Video");
request.setIdType("EAN");
//Here iterates on my amazon-movies object
for (AmazonSIdN i : amazonItems) {
request.getItemId().add(i.getEan());
if (request.getItemId().size() % 10 == 0) { //numbers of items in request
LOG.info("Request size = " + request.getItemId().size());
break;
}
}
Holder<List<Items>> items = new Holder<List<Items>>();
lookup.getRequest().add(request);
port.itemLookup(lookup.getMarketplaceDomain(), lookup.getAWSAccessKeyId(),
lookup.getAssociateTag(),lookup.getXMLEscaping(), lookup.getValidate(),
lookup.getShared(), lookup.getRequest(),operationrequest, items);
List<Items> result = items.value;
for (int k = 0; k < result.get(0).getItem().size(); ++k) {
Item i = result.get(0).getItem().get(k);
//do something with item
}
It is working, but one thing is really strange for me. When in this line:
if (request.getItemId().size() % 10 == 0) { //numbers of items in request
I use 40 000 instead of 10 WS returns:
The server sent HTTP status code 413: Request Entity Too Large
And this is understandable. But when I put number greater then 10 WS doesn't return eny errors but result has no items:
Can anybody tell me what I a'm doing wrong or what did I forget set? Any advice?
I found an answer, so I put it here maybe someone save some time in future.
In Amazon ItemLookup documentatnion is written:
ItemId - One or more (up to ten) positive integers that uniquely identify an item. The meaning of the number is specified by IdType. That is, if IdType is ASIN, the ItemId value is an ASIN. If ItemIdis an ASIN, a search index cannot be specified in the request.
Type: String
Default: None
Constraints: Must be a valid item ID. For more than one ID, use a comma-separated list of up to ten IDs.
Related
I am trying to populate an empty array in the first column with ordered numbers and write this back. This works, but I need the row location passed back too for reference in another method.
// Generate a customer/order number.
public static String[][] gen_cust_number(String[][] cust_order, int order_location)
{
for(int row = 0; row < cust_order.length; row++)
{
if (cust_order[row][0] == null)
{
cust_order[row][0] = Integer.toString(row + 1000);
order_location = row;
Gen.p("\n\n\tYour order number is : " + cust_order[row][0]);
break;
}
}
return cust_order;
}
I'm not very familiar with working with objects, pairs, and whatnot as I am still learning but have done some searching on it and am stumped in understanding how to do it.
I'm not 100% sure with what you're trying to achieve, but by reading the code I think what get_cust_number should do is
Generate new order to the very first empty order list.
Return the new order list and its index.
If this is right, you don't have to pass the String[][] back because the reference of this instance is what the caller side already know as it's passed in the parameters.
You can also remove the order_location param as it's never read inside the method.
So what you can do to make it work is to
Remove the order_location from params.
Return the index of added order instead of the array itself.
This results in the following code.
// Generate a customer/order number.
public static int gen_cust_number(String[][] cust_order)
{
for(int row = 0; row < cust_order.length; row++)
{
if (cust_order[row][0] == null)
{
cust_order[row][0] = Integer.toString(row + 1000);
Gen.p("\n\n\tYour order number is : " + cust_order[row][0]);
return row;
}
}
// cust_order is full
return -1;
}
In the calling side, you can do the following:
String[][] cust_order = /* Some orders according to your logic. */;
int cust_order_count = /* Number of the orders generated. */;
// Generate the order and this will be the new number of orders.
cust_order_count = gen_cust_number(cust_order);
I want to query multiple candidates for a search string which could look like "My sear foo".
Now I want to look for documents which have a field that contains one (or more) of the entered strings (seen as splitted by whitespaces).
I found some code which allows me to do a search by pattern:
#View(name = "find_by_serial_pattern", map = "function(doc) { var i; if(doc.serialNumber) { for(i=0; i < doc.serialNumber.length; i+=1) { emit(doc.serialNumber.slice(i), doc);}}}")
public List<DeviceEntityCouch> findBySerialPattern(String serialNumber) {
String trim = serialNumber.trim();
if (StringUtils.isEmpty(trim)) {
return new ArrayList<>();
}
ViewQuery viewQuery = createQuery("find_by_serial_pattern").startKey(trim).endKey(trim + "\u9999");
return db.queryView(viewQuery, DeviceEntityCouch.class);
}
which works quite nice for looking just for one pattern. But how do I have to modify my code to get a multiple contains on doc.serialNumber?
EDIT:
This is the current workaround, but there must be a better way i guess.
Also there is only an OR logic. So an entry fits term1 or term2 to be in the list.
#View(name = "find_by_serial_pattern", map = "function(doc) { var i; if(doc.serialNumber) { for(i=0; i < doc.serialNumber.length; i+=1) { emit(doc.serialNumber.slice(i), doc);}}}")
public List<DeviceEntityCouch> findBySerialPattern(String serialNumber) {
String trim = serialNumber.trim();
if (StringUtils.isEmpty(trim)) {
return new ArrayList<>();
}
String[] split = trim.split(" ");
List<DeviceEntityCouch> list = new ArrayList<>();
for (String s : split) {
ViewQuery viewQuery = createQuery("find_by_serial_pattern").startKey(s).endKey(s + "\u9999");
list.addAll(db.queryView(viewQuery, DeviceEntityCouch.class));
}
return list;
}
Looks like you are implementing a full text search here. That's not going to be very efficient in CouchDB (I guess same applies to other databases).
Correct me if I am wrong but from looking at your code looks like you are trying to search a list of serial numbers for a pattern. CouchDB (or any other database) is quite efficient if you can somehow index the data you will be searching for.
Otherwise you must fetch every single record and perform a string comparison on it.
The only way I can think of to optimize this in CouchDB would be the something like the following (with assumptions):
Your serial numbers are not very long (say 20 chars?)
You force the search to be always 5 characters
Generate view that emits every single 5 char long substring from your serial number - more or less this (could be optimized and not sure if I got the in):
...
for (var i = 0; doc.serialNo.length > 5 && i < doc.serialNo.length - 5; i++) {
emit([doc.serialNo.substring(i, i + 5), doc._id]);
}
...
Use _count reduce function
Now the following url:
http://localhost:5984/test/_design/serial/_view/complex-key?startkey=["01234"]&endkey=["01234",{}]&group=true
Will return a list of documents with a hit count for a key of 01234.
If you don't group and set the reduce option to be false, you will get a list of all matches, including duplicates if a single doc has multiple hits.
Refer to http://ryankirkman.com/2011/03/30/advanced-filtering-with-couchdb-views.html for the information about complex keys lookups.
I am not sure how efficient couchdb is in terms of updating that view. It depends on how many records you will have and how many new entries appear between view is being queried (I understand couchdb rebuilds the view's b-tree on demand).
I have generated a view like that that splits doc ids into 5 char long keys. Out of over 1K docs it generated over 30K results - id being 32 char long, simple maths really: (serialNo.length - searchablekey.length + 1) * docscount).
Generating the view took a while but the lookups where fast.
You could generate keys of multiple lengths, etc. All comes down to your records count vs speed of lookups.
I have a problem when I'm trying to generate a unique customer-id in my application. I want the numbers to start from 1 and go up. I have a register-class using tree-map that generates the next customer-number using this code:
public String generateNumber()
{
int number = 1;
for(Map.Entry<String, Forsikringkunde> entry : this.entrySet())
{
if(entry.getValue().getNumber().equals(String.valueOf(number)))
{
number++;
}
}return String.valueOf(number);
}
When I generate customers in my application I get duplicates of the numbers even though I iterate through the map. When creating a customer I create the object, run this method, use a set-method for the ID and adds it to the register, but it doesn't work. Anyone have a solution?
If you're on Java 8, I suggest you try this:
int max = this.values()
.stream()
.map(Forsikringkunde::getNumber)
.mapToInt(Integer::parseInt)
.max()
.orElse(0);
return String.valueOf(max + 1);
Modify the code to instead find the maximum number in your map, and then use that+1:
public String generateNumber()
{
int max = -1;
for(Map.Entry<String, Forsikringkunde> entry : this.entrySet())
{
int entry = Integer.parseInt(entry.getValue().getNumber());
if(entry > max)
{
max = entry;
}
}
return String.valueOf(max + 1);
}
(This mimics your coding style. aioobe's answer shows how to do the same thing more elegantly.)
Your method doesn't work because the map is not iterated in order. For example, here's what happens if you iterate through two users with number 2 and 1 respectively:
Start with "number = 1"
Check if number == 2: it's not, so continue
Check if number == 1: it is, so set number = 2
Now the loop is done and number is 2, even though a user with id 2 already exists. If it had been iterated in order, it would have worked.
I am using Twitter4j to build a client to fetch tweets for the input search term. I am also trying to provide the facility to the user to enter the number of tweets he wants in the result.
I know that we can set the number of tweets to be returned per page with the Query's setCount() method:
Query q = new Query(searchTerm);
q.setCount(maxTweets);
But if I am giving the value 1 as maxTweets, it returns 2 tweets.
Update: After further research I observed that it is returning 1 extra tweet per search. So I am giving 1 as maxTweets value it is returning 2 tweets. If I am giving 2 as maxTweets value it is returning 3 tweets and so on.
I am not sure where I am wrong but please let me know if there is a way by which I can get the fixed number of tweets using twitter4j.
Any guidance will be helpful.
When you write
Query q = new Query(searchTerm);
Think of it as one tabled page which contains an amount of result matching your query. But there might be more multiple pages.
When you set
q.setCount(maxTweets);
it will bring you maxTweets amount of tweets per page. In your case, 2, because there were two pages matching your query and you selected one tweet per page.
What you can do, try to handle it with a do - while loop.
Query q = new Query(searchTerm);
QueryResult result;
int tempUSerInput = 0; //keep a temp value
boolean flag = false;
do {
result = twitter.search(query);
List<Status> tweets = result.getTweets();
tempUSerInput = tempUSerInput + tweets.size();
if(tempUSerInput >= realyourUserInput) // you have already matched the number
flag = true; //set the flag
}
while ((query = result.nextQuery()) != null && !flag);
// Here Take only realyourUserInput number
// as you might have taken more than required
List<Status> finaltweets = new ArrayList();
for(int i=0; i<realyourUserInput; i++)
finaltweets.add( tweets.get(i) ); //add them to your final list
request = GET /solr1/select?q=reqRelDate_l%3A%5B1321516800000+TO+1321775940000%5D+AND+requestStatus_s%3ASUB29&wt=javabin&version=1 HTTP/1.1
or
request = GET /solr1/select?q=reqRelDate_l%3A%5B1321516800000+TO+1321775940000%5D+AND+requestStatus_s%3ASUB29&wt=javabin&version=1 HTTP/1.1
And I want to get all the data of &fq= So in the first case &fq= contains
doctype_s%3Acom.host.ems.qsrr.SurveyInstance
fq=%21survey_id_l%3A%2829%29
So I want filter should contain the value starting from first &fq= meaning that filter should contain the below value for the first case. And request can have many &fq= so I want filter to have value starting from &fq=
doctype_s%3Acom.host.ems.qsrr.SurveyInstance&fq=%21survey_id_l%3A%2829%29
So if I do by this way-- then I get only first value of &fq= not other value.. So what's the best way to get all the value starting from first &fq= and replacing these thing &wt=javabin&version=1 HTTP/1.1
filter = request.split("&fq=")[1];
I need to parse the above request string so that I can get the value of &fq= in the filter variable..
Off the top of my head I guess you could do something like this:
String[] params = request.split("&");
List<String> values = new ArrayList<String>();
for (int i = 0; i < params.length; i++) {
if (params[i].startsWith("fq")) {
String[] fqsplit = params[i].split("=");
if (fqsplit.length > 1) {
values.add(fqsplit[1]);
}
}
}
Now you will have a List with all the values of the fq parameters.
Sure I could come up with something more clever.
If there is always another &VAR following &fq=, you can do:
String fq_stuff = filter.split("&")[0];
If it is truly the first instance of fq, why not be simple?? I really think all these splits and regexs are overkill sometimes.
int firstFQ = request.indexOf("&fq");
if (firstFQ < 0)
throw new SomeException();
int nextAmp = request.indexOf("&", firstFQ+1);
if (nextAmp < 0)
throw new SomeException();
return request.subString(firstFQ+3, nextAmp); // I may have an off by 1 error here
You can clean this up by making "&fq" a nice constant or an arg passed in.