142 server hits for 20 valid responses...is this normal?


I'm making a spelling bee game in Swift that generates a random word (from another API because Oxford apparently doesn't support randomization yet) and then checks the Oxford data to retrieve that word's pronuncation MP3, a short definition, and a sample phrase. If the search for these items fails, then the app chooses a different word and tries again until a valid JSON object is returned. I just played the game, and 20 valid objects required 142 server hits. Is this normal, or is there something wrong with my code/logic that is causing this inefficiency?

Also, I've noticed that some words just keep showing up. How many of the Oxford words have audio pronunciations?

Here are the parts of my code that generate the random word and search the Oxford data:

Thank you for your help!

    // get random word from Lexicontext API

    func selectRandomWord() {

    DispatchQueue.main.async { [unowned self] in

    self.activitySpinner.isHidden = false

    randomWord = (dictionary?.randomWord())!
    wordLength = randomWord.count

    print ("The random word is \(randomWord)")

   // I don't want hyphenated, double words, short words, or repeats
    while randomWord.contains(" ")
        || randomWord.contains("-")
        || randomWord.count < 8
        || self.usedWords.contains(randomWord)


        randomWord = (dictionary?.randomWord())!
        print ("The new random word is \(randomWord)")

    // This is the random word selected
    print (randomWord)


 func speakRandomWord() {

  //now let's search Oxford for a matching JSON object

   appId = "private"
   appKey = "private"
   language = "en"
   word = randomWord
   regions = "us"
   word_id = word.lowercased() //word id is case sensitive and lowercase is required
   url = URL(string: "https://od-api.oxforddictionaries.com:443/api/v1/entries/\(language)/\(word_id)/regions=\(regions)")!
var request = URLRequest(url: url)
request.addValue("application/json", forHTTPHeaderField: "Accept")
request.addValue(appId, forHTTPHeaderField: "app_id")
request.addValue(appKey, forHTTPHeaderField: "app_key")

   let session = URLSession.shared
   print ("URLSession began...")
    _ = session.dataTask(with: request, completionHandler: { data, response, error in
    if let httpResponse = response as? HTTPURLResponse {
    print("statusCode: \(httpResponse.statusCode)")

    // if a matching JSON object is found, great, otherwise, try again
    if httpResponse.statusCode != 200 {



  DispatchQueue.main.async { [unowned self] in
  self.activitySpinner.isHidden = true
  self.repeatButton.isEnabled = true
  self.defineButton.isEnabled = true


    //I have a valid JSON object, so now I serialize it to get the elements we want
    if let response = response,
        let data = data,
        let jsonData = try? JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String:AnyObject]


let dictionary = jsonData as? [String: Any],

let results = dictionary["results"] as? [[String: Any]],
//You need to choose one from "results"
!results.isEmpty, case var result = results[0],

let lexicalEntries = result["lexicalEntries"] as? [[String: Any]],
//You need to choose one from "lexicalEntries"
!lexicalEntries.isEmpty, case var lexicalEntry = lexicalEntries[0],

let derivatives = lexicalEntry["derivatives"] as? [[String:Any]],
!derivatives.isEmpty, case var derivative = derivatives[0],

let pronunciations = lexicalEntry["pronunciations"] as? [[String: Any]],
//You need to choose one from "lexicalEntries"
!pronunciations.isEmpty, case var pronunciation = pronunciations[0],

let entries = lexicalEntry["entries"] as? [[String:Any]],
//I need to choose one from "lexicalEntries"
!entries.isEmpty, case var entry = entries[0],

let senses = entry["senses"] as? [[String:Any]],
//I need to choose one from "senses"
!senses.isEmpty, case var sense = senses[0],

let examples = sense["examples"] as? [[String:Any]],
//I need to choose one from "examples"
!examples.isEmpty, case var example = examples[0]

   print (entry)
    if let theText = example.removeValue(forKey:"text") {

    print ("The value is \(theText)")

   self.theText = String(describing:theText)


if let meaning = sense.removeValue(forKey:"short_definitions") {

print ("The short meaning is \(meaning)")

self.newMeaning = String(describing:meaning)


//Play the audio MP3
if let audioPath = pronunciation["audioFile"] as? String {
    print ("I'm here, the audio succeeded")

self.path = String(describing:audioPath)
    self.repeatPath = self.path
    let url = URL.init(string: self.path)
self.player = AVPlayer.init(url: url!)

//These two else blocks are where I'm really confused, am I doing this all wrong?
else {
    print ("No MP3 data for this word")  // out of 142 hits, this happened 18 times


   else {
   print ("Something else went wrong")   // out of 142 hits, this happened 99 times





  • AmosDuveenAmosDuveen Member, Administrator, Moderator admin
    edited July 2018

    Hi @egarfinkel99 ,

    A few possibilities come to mind. The first is that we do not list many inflected forms, especially regular inflections, at headword level (something we are aware of and looking into); you may find that calling the search endpoint first will direct you to the entry for the root form of the word and increase your hit rate.

    Also, Lexi Content is based on the Wordnet data which is user generated without much editorial oversight so, if the source list contains a lot of arcane entries or poorly attested neologisms, those words are unlikely to be found in our data, which is curated and focuses on well established current language.

    If you give me some examples of words that have failed, I might be able to give you a more certain answer.

  • egarfinkel99egarfinkel99 Member

    Thank you for answering!

    Here is a console log of successes and failures. Some failures were for words that existed but audio could not be found. Other failures were for an unknown reason. I'm trying to figure out why there are so few hits for so many attempts. This round, for instance, shows a 10 percent success rate.

    I see that some of the words failed because Oxford API only has entries for root words, but some of the root words failed, too. In a recent round, the word "house" failed. So there must be something I'm doing wrong to get such low hit stats.

    URL Session failures: 42
    Oxford API attempts: 166.0
    Oxford API successes: 17.0
    Oxford API failures: 107.0
    Successful Oxford API hit percentage: 10.2409638554217

    These 17 words succeeded: ["quadrupedal", "pristine", "compulsive", "mythical", "unquiet", "incline", "sibilant", "knavish", "attach", "lenient", "dismiss", "extrinsic", "discontent", "clerk", "activate", "seasick", "disambiguate"]

    These 28 words had no audio: ["westward", "spasmodic", "graze", "rumple", "delineate", "leggy", "incorporate", "peel", "cover", "wealthy", "factual", "perpetrate", "muckrake", "placid", "romanticize", "renegotiate", "syllabic", "dilatory", "slighting", "straw", "quack", "conventional", "brave", "impetuous", "semiconscious", "heedless", "mutate", "dimension"]

    These words 79 words failed for an unknown reason: ["boot", "unbreakable", "altercate", "misconstrue", "fledge", "silkscreen", "psychopathological", "candidness", "crossbeam", "demean", "askance", "flicker", "violet", "verbascum", "gambusia", "singing", "drunken", "depopulate", "dun", "somnolent", "calcify", "braze", "victimization", "feudalistic", "rhenium", "whop", "stud", "transalpine", "headquarter", "alated", "mush", "denumerable", "utter", "decay", "charcoal", "yankee", "reappraisal", "prolapsus", "unsalted", "pave", "whole", "allude", "ant", "incaution", "continuant", "burglarproof", "overindulgent", "cream", "constituent", "warrior", "emphasize", "placard", "pokey", "ruiner", "eurasian", "asteroid", "mithraistic", "correspondent", "digester", "u", "fatten", "demureness", "lidless", "fruiting", "tactical", "stockpile", "speciate", "acquirable", "conk", "misprint", "farsighted", "progress", "acicular", "cloven", "communicatory", "fahrenheit", "polemicize", "cerebrate", "borscht"]

    Why would simple words like graze, peel, cover, and brave have no audio? (I'm sure they do have audio, the question is why didn't my app find it?)

    Why do you think words like boot, dun, whop, decay, and ant would fail?

    Thank you again!


  • AmosDuveenAmosDuveen Member, Administrator, Moderator admin

    Hi @egarfinkel99,

    I'm not concerned with that first group as they were found.

    The second group do not (yet) have US audio, but many do have UK audio (you'll have to set the filter to .../regions=uk to get there). We do have an ongoing program of recording audio to fill in gaps and improve the quality of old files so in time, these will get resolved, meanwhile new words are always being added so there will always be a few words with no audio.

    That third group is a mystery to me because, although I haven't tried all of them, every one I did try gave me the expected response (although not always with audio, see above). I can only assume that the problem is somewhere in your code. Have you tried isolating segments of the script to test each bit of functionality separately?

  • egarfinkel99egarfinkel99 Member

    Yes, I'll have to find whatever is causing these skips on perfectly good words. If I find the lemma first, do I then need to do a second access to find that lemma's audio? Thank you!

  • AmosDuveenAmosDuveen Member, Administrator, Moderator admin

    Hi @egarfinkel99,

    It depends how you go about it, a straightforward request to the entries endpoint is just a single call and will deliver the audio link (except where it is not available). However, any typo or miss-match between the entered text and the headword will result in a 404, this includes most inflected forms. To overcome this, we recommend putting a search call in first which will direct the app to the most relevant confirmed entries so that the next call to retrieve the dictionary entry doesn't fail.

    None of the above guarantees the availability of audio, so depending on how important/relevant you feel it is, you may decide a further call to the UK database to retrieve UK audio may be worthwhile to increase your coverage, albeit with a different accent.

Sign In or Register to comment.