1

I've got an iOS app written in obj-c which takes a query typed into a search box and performs a multi match field query on the elasticsearch api. Can someone help with the formatting of the JSON request body? This is an example of the body of the get query I would like to format:

GET /test/data/_search
{
  "min_score": 1.6,<br/>
  "query": { <br/>
      "multi_match": {<br/>
             "query": "smith",<br/>
             "fields": ["name", "surname"]<br/>
      }<br/>
    },<br/>
  "_source": ["name", "surname", "address"]<br/>
}<br/>

In my code I have:

NSString *jsonRequest = [NSString stringWithFormat:@"{\"min_score\":\"1.6\",\"query\":{\"multi_match\":{\"name\",\"surname\":\"%@\"}},\"_source\":[\"name\",\"surname\",\"address\"]}",[self.searchTextField text]];

Where [self.searchTextField text] is the value taken from the search field.

But I get this error when back from ElasticSearch when I query:

reason = "Unexpected character (',' (code 44)): was expecting a colon to separate field name and value\n at [Source:

Just as a test, using a query to match just one field works fine, so it looks to be just a formatting issue.

Sorry forgot to add this is where I set the URL I post to with the JSON body:

[self postDataToUrl:@"http://localhost:9200/test/data/_search?pretty=true" withJson:jsonRequest];

this then passes to:

-(void)postDataToUrl:(NSString*)urlString withJson:(NSString*)jsonString
{
    NSData* responseData = nil;
    NSURL *url=[NSURL URLWithString:[urlString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]]];

    responseData = [NSMutableData data] ;
    NSMutableURLRequest *request=[NSMutableURLRequest requestWithURL:url];
    [request setHTTPMethod:@"POST"];
    [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
    NSData *data = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
    [request setHTTPBody:data];
    [request setValue:[NSString stringWithFormat:@"%lu", (unsigned long)[data length]] forHTTPHeaderField:@"Content-Length"];

    NSURLSession *session = [NSURLSession sharedSession];
    [[session dataTaskWithRequest:request
                completionHandler:^(NSData *data,
                                    NSURLResponse *response,
                                    NSError *error) {
                    NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
                    NSLog(@"the final output is:%@",responseString);
                    NSError *lerror = nil;
                    NSDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:data options:0  error:&lerror];

                if (error != nil) {
                    NSLog(@"Error parsing JSON.");
                }
                else {

This is all works fine when I pass a regular match body e.g:

NSString *jsonRequest = [NSString stringWithFormat:@"{\"min_score\":\"1.6\",\"query\":{\"match\":{\"name\":\"%@\"}},\"_source\":[\"name\",\"surname\",\"address\"]}",[self.searchTextField text]];
Alex
  • 995
  • 12
  • 25
Chu
  • 11
  • 3
  • Is that supposed to be a query string? – Mike D Feb 08 '17 at 20:54
  • 4
    Your json invalid. There's no value for the "name" key in the "multi_match" dictionary. You shouldn't be manually creating a json string in code, create a dictionary and use `NSJSONSerialization` to convert it to a valid json string. – dan Feb 08 '17 at 20:57
  • Possible duplicate of [Send POST request using NSURLSession](http://stackoverflow.com/questions/19099448/send-post-request-using-nsurlsession) –  Feb 08 '17 at 21:00
  • @MikeD I've aded a bit more info, hopefully makes it more clear. – Chu Feb 08 '17 at 22:04
  • @dan Thanks for the reply. I added some more of the code I'm using. I'm not really sure what you mean, do you mind giving some tips on what's wrong? It works ok when I do a match on one field like detailed above. – Chu Feb 08 '17 at 22:19
  • Your first example shows an array with `name`and `surname` which you replaced with an invalid dictionary `{"name", "surname": "%@"}` <- that's invalid. And there's something wrong with the `query` parameter. You've messed it up :D... the `"query":` should be `"%@"`, shouldn't it? --- EDIT: And you missed one of the two `query` parameters! – cybergen Feb 08 '17 at 23:24
  • 1
    I think that converting your jsonRequest to dictionary first then updating the needed key will be less error prone that having you create a jsonString then updating the value by formatting the string – Joshua Feb 09 '17 at 02:29
  • @cybergen Thanks for the tips, not sure how the other JSON body was working okay! but i've formatted the body so it's got the missing query etc.. and it works now. – Chu Feb 10 '17 at 08:59
  • @Chu as other commenters suggested, you shouldn't have pure JSON strings in your code. Do it with a dictionary or better a dedicated lib like SwiftyJson. Oh, and go for Swift - it rocks! (And is again less error prone.) – cybergen Feb 11 '17 at 10:51

2 Answers2

0

You may want to check the content of your search results. It looks like you have a carriage return \n which breaks the string before the coma. You can remove the carriage return like this:

NSString *newString = [[self.searchTextField text] stringByReplacingOccurrencesOfString:@"\n" withString:@""];
NSString *jsonRequest = [NSString stringWithFormat:@"{\"min_score\":\"1.6\",\"query\":{\"match\":{\"name\":\"%@\"}},\"_source\":[\"name\",\"surname\",\"address\"]}", newString];
Alex
  • 995
  • 12
  • 25
0

Check the post from @cybergen, the JSON body wasn't set correctly, Elastic expects a JSON query in this format:

{
  "query": {
    "multi_match" : {
      "query":    "smith", 
      "fields": [ "name", "surname" ] 
    }
  }
}

I formatted the JSON request string to match that in my code.

Chu
  • 11
  • 3