简体   繁体   中英

How to get a sub-field of a struct type map, in the search response of YQL query in Vespa?

Sample Data:

"fields": {
    "key1":0,
    "key2":"no",
    "Lang": {
        "en": {
            "firstName": "Vikrant",
            "lastName":"Thakur"
        },
        "ch": {
            "firstName": "维克兰特",
            "lastName":"塔库尔"
        }
    }
}

Expected Response:

"fields": {
  "Lang": {
      "en": {
          "firstName": "Vikrant",
          "lastName":"Thakur"
       }
  }
}

I have added the following in my search-definition demo.sd :

struct lang {
  field firstName type string {}
  field lastName type string {}
}

field Lang type map <string, lang> {
  indexing: summary
  struct-field key {
    indexing: summary | index | attribute
  }
}

I want to write a yql query something like this (This doesn't work):

http://localhost:8080/search/?yql=select Lang.en from sources demo where key2 contains 'no';

My temporary workaround approach

I have implemented a custom searcher in MySearcher.java , through which I am able to extract the required sub-field and set a new field 'defaultLang', and remove the 'Lang' field. The response generated by the searcher:

"fields": {
  "defaultLang": {
      "firstName": "Vikrant",
      "lastName":"Thakur"
  }
}

I have written the following in MySearcher.java:

for (Hit hit: result.hits()) {
    String language = "en";  //temporarily hard-coded
    StructuredData Lang = (StructuredData) hit.getField("Lang");
    Inspector o = Lang.inspect();
    for (int j=0;j<o.entryCount();j++){
        if (o.entry(j).field("key").asString("").equals(language)){
            SlimeAdapter value = (SlimeAdapter) o.entry(j).field("value");
            hit.setField("defaultLang",value);
            break;
        }
    }
    hit.removeField("Lang");
}

Edit-1: A more efficient way instead is to make use of the Inspectable interface and Inspector, like above (Thanks to @Jo Kristian Bergum)

But, in the above code, I am having to loop through all the languages to filter out the required one. I want to avoid this O(n) time-complexity and make use of the map structure to access it in O(1). (Because the languages may increase to 1000, and this would be done for each hit.)

All this is due to the StructuredData data type I am getting in the results. StructureData doesn't keep the Map Structure and rather gives an array of JSON like:

[{
  "key": "en",
  "value": {
    "firstName": "Vikrant",
    "lastName": "Thakur"
  }
}, {
  "key": "ch",
  "value": {
    "firstName": "维克兰特",
    "lastName": "塔库尔"
  }
}]

Please, suggest a better approach altogether, or any help with my current one. Both are appreciated.

The YQL sample query I guess is to illustrate what you want as that syntax is not valid. Picking a given key from the field Lang of type map can be done as you do in your searcher but deserializing into JSON and parsing the JSON is probably inefficient as StructuredData implements the Inspectable interface and you can inspect it directly without the need to go through JSON format. See https://docs.vespa.ai/documentation/reference/inspecting-structured-data.html

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM