public static async Task <(Dictionary <string, Tuple <float, float> >, Dictionary <string, string>)> RequestOverrideLonglat (Dictionary <string, string> overrideTable) { Console.WriteLine("Requesting override table"); IEnumerable <string> requestGen = overrideTable.Where( kv => kv.Value.Split('\t')[0] != "[NO OVERRIDE]") .Select(kv => "https://www.als.ogcio.gov.hk/lookup?n=1&q=" + HttpUtility.UrlEncode( overrideTable[kv.Key].Split('\t')[0]) + "&i=" + HttpUtility.UrlEncode(kv.Key)); Dictionary <string, Tuple <float, float> > longlatOverrideTable = new Dictionary <string, Tuple <float, float> >(); Dictionary <string, string> addressTable = new Dictionary <string, string>(); Pacer estimatePacer = new Pacer(requestGen.Count()); Task <GeoInfo>[] taskResponse; for (int batchStart = 0; batchStart < requestGen.Count(); batchStart += Program.batchSize) { taskResponse = requestGen.Skip(batchStart).Take(Program.batchSize) .Select(s => GeoInfo.FromUrl(s, estimatePacer)).ToArray(); await Task.WhenAll(taskResponse); foreach (GeoInfo response in taskResponse.Select(t => t.Result)) { string nameKey = HttpUtility.UrlDecode(response.requestKey); string[] offset = overrideTable[nameKey].Split('\t').Skip(1).Take(2).ToArray(); longlatOverrideTable.Add(nameKey, new Tuple <float, float>( response.longlat.Item1 + float.Parse(offset[0]), response.longlat.Item2 + float.Parse(offset[1]))); addressTable.Add(nameKey, response.address); } } estimatePacer.Stop(); return(longlatOverrideTable, addressTable); }
// take in valid address list and perform API request private static async Task BatchReq(int[] parsedIndex, string[] parsedAddress, XDocument root, XNamespace xmlnsUrl, Tuple <int, int> ratio, Dictionary <string, string> overrideTable, string executablePath) { string lookupUrl = "https://www.als.ogcio.gov.hk/lookup?n=1&q="; // allocate full length longlat list XElement[] unitList = root.Descendants(xmlnsUrl + "serviceUnit").ToArray(); Tuple <float, float>[] longlatList = new Tuple <float, float> [unitList.Length] .Select(t => new Tuple <float, float>(0, -91)).ToArray(); // encode and request multiple URL simultaneously IEnumerable <string> requestGen = parsedAddress.Select((s, i) => lookupUrl + HttpUtility.UrlEncode(s) + "&i=" + parsedIndex[i]); StreamWriter overrideStream = new StreamWriter(executablePath + "/../override.csv", true, Encoding.UTF8); Pacer estimatePacer = new Pacer(parsedIndex.Length); Task <GeoInfo>[] taskResponse; for (int batchStart = 0; batchStart < parsedIndex.Length; batchStart += batchSize) { taskResponse = requestGen.Skip(batchStart).Take(batchSize) .Select(s => GeoInfo.FromUrl(s, estimatePacer)).ToArray(); await Task.WhenAll(taskResponse); estimatePacer.Stop(); foreach (GeoInfo response in taskResponse.Select(t => t.Result)) { // check district correctness int unitIndex = int.Parse(response.requestKey); XElement targetUnit = unitList[unitIndex]; string parsedDistrict = targetUnit.Descendants(xmlnsUrl + "districtEnglish").First().Value; parsedDistrict = parsedDistrict.ToUpper().Replace(" AND ", " & "); string longlatDistrict = response.root.Descendants("DcDistrict").First().Value; string name = targetUnit.Descendants(xmlnsUrl + "nameTChinese").First().Value.ToUpper(); // append to override table if district test failed and no entry exists if (!longlatDistrict.Contains(parsedDistrict) && !overrideTable.ContainsKey(name)) { Console.WriteLine("District test failed for " + response.address); string tcaddress = targetUnit.Descendants(xmlnsUrl + "addressTChinese").First().Value; overrideStream.Write($"\n{name}\t[NO OVERRIDE]\t0\t0\t{tcaddress}"); ratio = new Tuple <int, int>(ratio.Item1 - 1, ratio.Item2 + 1); continue; } longlatList[unitIndex] = response.longlat; } } Console.WriteLine($"Query ratio is {ratio.Item1}:{ratio.Item2}"); overrideStream.Close(); (Dictionary <string, Tuple <float, float> > longlatOverrideTable, _) = await Amender.RequestOverrideLonglat(overrideTable); Console.WriteLine("Applying override table"); List <Dictionary <string, string> > unitDictList = new List <Dictionary <string, string> >(); foreach (XElement unit in root.Descendants(xmlnsUrl + "serviceUnit")) { Dictionary <string, string> propDict = new Dictionary <string, string>(); foreach (XElement prop in unit.Descendants()) { propDict.Add(prop.Name.LocalName, prop.Value); } unitDictList.Add(propDict); } for (int index = 0; index < unitDictList.Count; index++) { // define None for default address override unitDictList[index].Add("addressOverride", ""); string nameKey = unitDictList[index]["nameTChinese"].ToUpper(); if (longlatOverrideTable.ContainsKey(nameKey)) { longlatList[index] = longlatOverrideTable[nameKey]; unitDictList[index]["addressOverride"] = overrideTable[nameKey].Split('\t')[0]; } } Amender.PatchUnitInfo(longlatList, unitDictList[0].Keys, unitDictList.Select(d => d.Values.ToArray()).ToArray(), executablePath); }