//ready to Launched status change happens by the AmazonHITTableManager //Completed tasks are removed from the TaskTable //Thus, we check if tasks are still pernding //if not tasks for a GUID are pending its deemed as complete //then save the results and chnage status to completed public static void processLaunchedJobs() { SatyamJobSubmissionsTableAccess jobDB = new SatyamJobSubmissionsTableAccess(); List <string> guidList = jobDB.getAllJobGUIDSByStatus(JobStatus.launched); List <string> readyList = jobDB.getAllJobGUIDSByStatus(JobStatus.ready); guidList.AddRange(readyList); SatyamTaskTableAccess taskDB = new SatyamTaskTableAccess(); foreach (String GUID in guidList) { if (GUID == "SINGLE_OBJECT_LABLING_DEMO") { continue; } List <int> IDList = taskDB.getAllIDsByGUID(GUID); if (IDList.Count == 0) { SatyamSaveResults.SaveByGUIDRequester(GUID); SatyamSaveResults.SaveByGUIDSatyam(GUID); SatyamSaveAggregatedResult.SaveByGUIDRequester(GUID); SatyamSaveAggregatedResult.SaveByGUIDSatyam(GUID); jobDB.UpdateEntryStatus(GUID, JobStatus.completed); } } jobDB.close(); taskDB.close(); }
public static void processPreprocessedJobs() { SatyamJobSubmissionsTableAccess jobDB = new SatyamJobSubmissionsTableAccess(); List <SatyamJobSubmissionsTableAccessEntry> jobEntries = jobDB.getAllEntriesByStatus(JobStatus.preprocessed); foreach (SatyamJobSubmissionsTableAccessEntry entry in jobEntries) { SatyamTaskGenerator.PopulateTasksIntoTaskTable(entry); if (TaskConstants.MTurkTaskTemplates.Contains(entry.JobTemplateType)) { jobDB.UpdateEntryStatus(entry.JobGUID, JobStatus.ready); } else { jobDB.UpdateEntryStatus(entry.JobGUID, JobStatus.launched); } } jobDB.close(); }
//goes through the jobDB and finds submitted jobs //uses the TaskGenerator to populate the taskTable //public static string processSubmittedJobsDebug() //{ // string debugString = "Entered the Function\n"; // SatyamJobSubmissionsTableAccess jobDB = new SatyamJobSubmissionsTableAccess(); // List<SatyamJobSubmissionsTableAccessEntry> jobEntries = jobDB.getAllEntriesByStatus(JobStatus.submitted); // debugString += "got the job entries, there are " + jobEntries.Count + "\n"; // if (jobEntries.Count == 0) // { // debugString += "No new Entries in the DB\n"; // return debugString; // } // int noEntries = 0; // foreach (SatyamJobSubmissionsTableAccessEntry entry in jobEntries) // { // debugString += "About To Populate Entry " + noEntries + "\n"; // //SatyamTaskGenerator.PopulateTasksIntoTaskTable(entry); // debugString += SatyamTaskGenerator.PopulateTasksIntoTaskTableDebug(entry); // return debugString; // if (TaskConstants.MTurkTaskTemplates.Contains(entry.JobTemplateType)) // { // jobDB.UpdateEntryStatus(entry.JobGUID, JobStatus.ready); // } // else // { // jobDB.UpdateEntryStatus(entry.JobGUID, JobStatus.launched); // } // noEntries++; // } // return debugString; //} public static void preprocessSubmittedData() { SatyamJobSubmissionsTableAccess jobDB = new SatyamJobSubmissionsTableAccess(); List <SatyamJobSubmissionsTableAccessEntry> jobEntries = jobDB.getAllEntriesByStatus(JobStatus.submitted); foreach (SatyamJobSubmissionsTableAccessEntry entry in jobEntries) { if (SatyamTaskGenerator.PreprocessSubmittedData(entry)) { jobDB.UpdateEntryStatus(entry.JobGUID, JobStatus.preprocessed); } } jobDB.close(); }
// If the results were not good enough, or aggregation method changed, retargeted, users might want to reopen the job // All we need to do: (IN STRICT ORDER) // clear all results back to inconclusive, // remove all aggregated results // restore the task table as it was for the guid, // change the job status back to launched, and // WARNING: // for safety, this has to be run atomically synchronously, without any parallel process. for now. public static void reopenJobForMoreResults(string guid) { SatyamJobSubmissionsTableAccess jobDB = new SatyamJobSubmissionsTableAccess(); SatyamJobSubmissionsTableAccessEntry jobEntry = jobDB.getEntryByJobGIUD(guid); jobDB.close(); if (jobEntry.JobStatus != JobStatus.completed) { Console.WriteLine("Job not completed yet!"); return; } SatyamAggregatedResultsTableAccess aggResultDB = new SatyamAggregatedResultsTableAccess(); bool delSuccess = aggResultDB.DeleteEntriesByGUID(guid); aggResultDB.close(); if (!delSuccess) { Console.WriteLine("Delete Agg Result DB Failed"); return; } SatyamResultsTableAccess resultDB = new SatyamResultsTableAccess(); if (!resultDB.UpdateStatusByGUID(guid, ResultStatus.inconclusive)) { Console.WriteLine("Update Result DB Failed"); //resultDB.close(); //return; } List <SatyamResultsTableEntry> results = resultDB.getEntriesByGUID(guid); resultDB.close(); Dictionary <int, SatyamTask> taskParamsByTaskID = new Dictionary <int, SatyamTask>(); foreach (SatyamResultsTableEntry result in results) { if (taskParamsByTaskID.ContainsKey(result.SatyamTaskTableEntryID)) { continue; } SatyamResult satyamRes = JSonUtils.ConvertJSonToObject <SatyamResult>(result.ResultString); SatyamTask task = JSonUtils.ConvertJSonToObject <SatyamTask>(satyamRes.TaskParametersString); taskParamsByTaskID.Add(result.SatyamTaskTableEntryID, task); } SatyamTaskTableAccess taskDB = new SatyamTaskTableAccess(); foreach (int taskID in taskParamsByTaskID.Keys) { SatyamTask task = taskParamsByTaskID[taskID]; SatyamJob job = task.jobEntry; bool suc = taskDB.AddEntryWithSpecificID(taskID, job.JobTemplateType, job.UserID, job.JobGUIDString, JSonUtils.ConvertObjectToJSon(task), job.JobSubmitTime, job.amazonHITInformation.Price); if (!suc) { Console.WriteLine("Update Task Table Failed"); taskDB.close(); return; } } taskDB.close(); jobDB = new SatyamJobSubmissionsTableAccess(); bool success = jobDB.UpdateEntryStatus(guid, JobStatus.launched); jobDB.close(); if (!success) { Console.WriteLine("Update Job Entry Failed"); return; } }
//public static Dictionary<string, int> getRemainingHITsFinishedTasksFromResultDB(string guid, int taskPerHIT) //{ // SatyamResultsTableAccess resultDB = new SatyamResultsTableAccess(); // List<SatyamResultsTableEntry> entries = resultDB.getEntriesByGUID(guid); // Dictionary<string, int> noResultPerHITID = new Dictionary<string, int>(); // //int noFinishedHIT = 0; // foreach (SatyamResultsTableEntry entry in entries) // { // string HITId = JSonUtils.ConvertJSonToObject<SatyamResult>(entry.ResultString).amazonInfo.HITID; // if (!noResultPerHITID.ContainsKey(HITId)) // { // noResultPerHITID.Add(HITId,1); // } // else // { // noResultPerHITID[HITId]++; // //if (noResultPerHITID[HITId] == taskPerHIT) // //{ // // noFinishedHIT++; // //} // } // } // return noResultPerHITID; //} //makes sure that there are enough HITS in Amazon to ensure that jobs will be done public static void LaunchAmazonHITsFromTaskTable(int max = int.MaxValue) { //Group them by jobguids since each job can have many tasks Dictionary <string, List <SatyamTaskTableEntry> > TasksByGUID = OrganizeMTurkTasksByGUID(); if (TasksByGUID == null) //there is nothing to do!! { return; } //after running the aggregator, the number of tasks in each guid <= no of HITS pending //so if there are less HITS pending we launch more and if there are more we leave them alone until the job is done SatyamAmazonHITTableAccess hitDB = new SatyamAmazonHITTableAccess(); SatyamJobSubmissionsTableAccess jobDB = new SatyamJobSubmissionsTableAccess(); //now check how manyy hits are pending and launch to ensure that there are enough hits in amazon foreach (KeyValuePair <string, List <SatyamTaskTableEntry> > entry in TasksByGUID) { String jobGUID = entry.Key; SatyamTask task = JSonUtils.ConvertJSonToObject <SatyamTask>(entry.Value[0].TaskParametersString); SatyamJob job = task.jobEntry; //// filter task templates -- temporary filter //if (job.JobTemplateType == TaskConstants.Segmentation_Image_MTurk) continue; string AmazonAccessKeyID = job.amazonHITInformation.AmazonAccessKeyID; string AmazonSecretAccessKeyID = job.amazonHITInformation.AmazonSecretAccessKeyID; string JobTemplateType = entry.Value[0].JobTemplateType; Dictionary <string, Object> hitParams = new Dictionary <string, object>(); hitParams.Add("Title", job.amazonHITInformation.AmazonMTurkTaskTitle); hitParams.Add("TaskDescription", job.amazonHITInformation.AmazonMTurkTaskDescription); hitParams.Add("KeyWords", job.amazonHITInformation.AmazonMTurkTaskKeywords); hitParams.Add("Reward", job.amazonHITInformation.Price); //convert cents to dollars if (TaskConstants.masterGUIDs.Contains(job.JobGUIDString)) { hitParams.Add("Masters", true); } int tasksPerHIT = job.TasksPerJob; List <SatyamAmazonHITTableAccessEntry> hitEntries = hitDB.getAllEntriesByJobGUIDAndStatus(jobGUID, HitStatus.pending); // the task will be marked as submitted when the webpage exit int noHITsRemaining = hitEntries.Count; ////////////////////////// check and deal with pending stragglers, the actual hit might have expired. //int noStragglers = 0; //foreach (SatyamAmazonHITTableAccessEntry pendingEntry in hitEntries) //{ // if ((DateTime.Now - pendingEntry.CreationTime).TotalHours > 1) // { // // the hit will be finished in 1hr if taken by a user, // // there is a higher chance that this hit have already been expired // // launch more for stragglers // noStragglers++; // } //} //noHITsRemaining -= noStragglers; /////////////////////////////// //////////////////////////////////// the query amazon way //AmazonMTurkHIT hit = new AmazonMTurkHIT(); //hit.setAccount(AmazonAccessKeyID, AmazonSecretAccessKeyID, false); ////an alternative without querying amazon ////Dictionary<string, int> noHITsFinishedTasks = getRemainingHITsFinishedTasksFromResultDB(jobGUID, tasksPerHIT); ////int noHITsRemaining = 0; //noHITsRemaining = 0; //int noPendingHITDone = 0; //foreach (SatyamAmazonHITTableAccessEntry hitEntry in hitEntries) //{ // int noTasksPending = hit.getNumTasksRemaining(hitEntry.HITID); // noHITsRemaining += noTasksPending; // //an alternative without querying amazon // //if (noHITsFinishedTasks.ContainsKey(hitEntry.HITID) && noHITsFinishedTasks[hitEntry.HITID] == tasksPerHIT) // //{ // // //HIT done // // noPendingHITDone++; // //} //} ////int noHITsRemainingFromResultDB = hitEntries.Count - noPendingHITDone; ////Console.WriteLine("Job {0}, HITS Remaining/fromDB/Pending/noTasks: {1}/{2}/{3}", //// jobGUID, noHITsRemaining, noHITsRemainingFromResultDB, hitEntries.Count, TasksByGUID[jobGUID].Count); ////if (noHITsRemainingFromResultDB!= noHITsRemaining) ////{ //// // not gonna work, what is the hit has less tasks than tasksPerHIT?? //// Console.WriteLine("Database method is wrong"); ////} ///////////////////////////////////////////////////////// int NoParallelTurker = 3; // too large will make the task stale on AMT, too small will hurt latency int difference = (int)Math.Ceiling((double)(TasksByGUID[jobGUID].Count * NoParallelTurker - noHITsRemaining * tasksPerHIT) / (double)tasksPerHIT); //int difference = 50; //difference *= 2; // boost for parallelism //difference = 10; //difference = Math.Min(difference, max) * NoParallelTurker; if (difference > 0) { AmazonMTurkHITBatchLauncher hitLauncher = new AmazonMTurkHITBatchLauncher(AmazonAccessKeyID, AmazonSecretAccessKeyID); string url = TaskConstants.JobTemplateTypeToTaskURI[JobTemplateType]; double reward = job.amazonHITInformation.Price; url = url + "?reward=" + reward; List <string> hitIDs = null; string hitParametersString = JSonUtils.ConvertObjectToJSon <Dictionary <string, object> >(hitParams); hitLauncher.LaunchBatches(url, hitParams, difference, out hitIDs); if (hitIDs != null) { foreach (string hitID in hitIDs) { hitDB.AddEntry(JobTemplateType, job.UserID, hitID, job.JobGUIDString, DateTime.Now, hitParametersString, AmazonAccessKeyID, AmazonSecretAccessKeyID); } jobDB.UpdateEntryStatus(entry.Key, JobStatus.launched); } } } jobDB.close(); hitDB.close(); }