2014-10-10 53 views
2

我正在Scala寫一個Play 2.3.2應用程序。 我使用reactivemongo驅動程序訪問mongodb數據庫。 我已經寫了這個查詢數據庫,以獲得數據庫中使用最多的標籤。 這種方法是Action.async並實現爲以下幾點:瞭解Scala的未來

def max = Action.async { request => 

      var max: Int = 0 
      var tagFound: Tag = null 
      //obtain all the tags in the db. 
      val futureTags: Future[List[Tag]] = Tags.all.toList 
      futureTags map{ (tags: List[Tag]) => 
      tags map { (tag: Tag) => 
       //create the tag String 
       val tagName = tag.category + ":" + tag.attr 
       //search in the db the documents where tags.tag == tag. 
       val futureRequests : Future[List[recommendationsystem.models.Request]]= Requests.find(Json.obj("tags.tag" -> tagName)).toList 
       futureRequests map { (requests: List[recommendationsystem.models.Request]) => 
       //get the numbers of documents matching the tag 
       val number: Int= requests.size 
       if(number > max) { 
        max = number 
        tagFound = tag 
       } 
       println(max) 
       } 
      } 

     val jsonObject = if(max > 0) Json.obj("tag" -> tagFound, "occurencies" -> max) else Json.obj("tag" -> "NoOne", "occurencies" -> 0) 
     Ok(jsonObject) 
     } 


     } 

但這種方法的行爲是不確定性的,什麼是錯的? 我不明白爲什麼

val jsonObject = if(max > 0) Json.obj("tag" -> tagFound, "occurencies" -> max) else Json.obj("tag" -> "NoOne", "occurencies" -> 0) 
      Ok(jsonObject) 
      } 

是執行異步的,不要等到了tags map語句完成。

回答

1

我發現你的代碼的幾個問題:

  1. 沒有用戶增值經銷商,你不知道他們什麼時候會被更新,因此確定性。 事實上,在您使用地圖的所有的foreach
  2. 不使用瓦爾,即你不返回從地圖中的任意值,使用的foreach明確,如果你不從未來
  3. 返回任何值趨於平緩未來[未來[T]使用flatMap,
  4. 改造名單[未來[T]給未來[列表[T]使用Future.sequence

這裏的代碼重寫一張,我還沒有編譯它,但你可以知道它應該如何工作:

def max = Action.async { request => 
    Tags.all.toList.flatMap { case tags => 
     val xs = tags map { case tag => 
     val tagName = tag.category + ":" + tag.attr 
     Requests.find(Json.obj("tags.tag" -> tagName)).toList.map (requests => (tag, requests.size)) 
     } 
     val f = Future.sequence(xs) 
     f.map { case ys => 
     val res = ys.foldLeft(Option.empty[(Tag, Int)]) { 
      case (Some((maxTag, maxOcc)), (tag, occ)) if occ > maxOcc => Some(tag, occ) 
      case ([email protected](_), _) => s 
      case (None, (tag, occ)) => Some(tag, occ) 
     } 
     val jsonObject = res.map { case (tag, maxOcc) => 
      Json.obj("tag" -> tagFound, "occurencies" -> maxOcc) 
     } getOrElse { 
      Json.obj("tag" -> "NoOne", "occurencies" -> 0) 
     } 
     Ok(jsonObject) 
     } 

    } 
} 
+0

感謝您的回覆,但我無法理解代碼的foldLeft部分。你能解釋你在做什麼? 否則代碼不會編譯,在我的@edit中可以看到編譯器錯誤。 – 2014-10-10 10:13:32

+0

編譯器錯誤是對讀者的練習。我將修正簡單的 – vitalii 2014-10-10 13:50:52

+0

foldleft這裏只是計算最大的「發生率」數字和相應的標記。您可以改爲使用可變變量,如問題所示 – vitalii 2014-10-10 13:54:37

0

Future.map返回另一個Future - 它不會使未來立即運行。致電f.map(...)後,f可能尚未完成。

如果你想阻止,直到Future完成時,使用Future.get(所以你可以做f.map(...).get,但在這種情況下,你不妨做f.get,做該值計算 - 當然這不會非阻塞)。如果你想鏈接幾個異步計算,你可以使用flatMapsequence,並且應該儘量避免在這種情況下使用var,如@ vitalii的答案。

-Ywarn-value-discard編譯器標誌可以在丟棄值時發出警告,這通常表示程序有問題。