Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>I suggest you take a look at <a href="http://github.com/szeiger/scala-query" rel="nofollow noreferrer">ScalaQuery</a>, which does about the same thing. And it can do so, because this is a monad problem. In fact, some Haskell solutions such as Arrows, which are implemented by the <a href="http://code.google.com/p/scalaz/" rel="nofollow noreferrer">Scalaz library</a>, seems to be pretty close.</p> <p>That would be the best solution, as the proper abstraction will make changes easier in the future.</p> <p>As a hack, I figure something like this:</p> <pre><code>abstract class QueryModifiers case object Consolidate extends QueryModifiers // create others as appropriate class Query(title: String) { self =&gt; // Create actors def createActor(qm: QueryModifiers): Actor = { val actor = qm match { case Consolidate =&gt; // create a consolidator actor case //... as needed } actor.start actor } // The pipeline val pipe: List[List[QueryModifiers]] = Nil // Build the pipeline def -&gt;(qms: List[QueryModifiers]) = new Query(title) { override val pipe = qms :: self.pipe } def -&gt;(qm: QueryModifiers) = new Query(title) { override val pipe = List(qm) :: self.pipe } def -&gt;(c: Consolidate.type) = { // Define the full pipeline // Because the way pipe is built, the last layer comes first, and the first comes last val pipeline = Consolidate :: pipe // Create an actor for every QueryModifier, using an unspecified createActor function val actors = pipeline map (_ map (createActor(_)) // We have a list of lists of actors now, where the first element of the list // was the last QueryModifiers we received; so, group the layers by two, and for each // pair, make the second element send the result to the first. // Since each layer can contain many actors, make each member of the second // layer send the results to each member of the first layer. // The actors should be expecting to receive message SendResultsTo at any time. for { List(nextLayer, previousLayer) &lt;- actors.iterator sliding 2 nextActor &lt;- nextLayer previousActor &lt;- previousLayer } previousActor ! SendResultsTo(nextActor) // Send the query to the first layer for ( firstActor &lt;- actors.last ) firstActor ! Query(title) // Get the result from the last layer, which is the consolidator val results = actors.head.head !? Results // Return the results results } } </code></pre> <p><strong>EDIT</strong></p> <p>You can guarantee ordering too, with a bit of a trick. I'm trying to avoid Scala 2.8 here, though it can make this much easier with named and default parameters.</p> <pre><code>sealed abstract class QueryModifiers case class QMSearcher(/*...*/) extends QueryModifiers case class QMFilter(/*...*/) extends QueryModifiers case class QMFetcher(/*...*/) extends QueryModifiers case object Consolidate extends QueryModifiers class Query[NextQM] private (title: String, searchers: List[QMSeacher], filters: List[QMFilter], fetchers: List[QMFetcher]) { // Build the pipeline def -&gt;[T &lt;: NextQM](qms: List[NextQM])(implicit m: Manifest[T]) = m.toString match { case "QMSearch" =&gt; new Query[QMFilter](title, qms, Nil, Nil) case "QMFilter" =&gt; new Query[QMFetcher](title, seachers, qms, Nil) case "QMFetcher" =&gt; new Query[Consolidate.type](title, searches, filters, qms) case _ /* "Consolidate$", actually */ =&gt; error("List of consolidate unexpected") } // Do similarly for qm: NextQM // Consolidation def -&gt;(qm: Consolidate.type) = { // Create Searchers actors // Send them the Filters // Send them Fetchers // Create the Consolidator actor // Send it to Searchers actors // Send Searchers the query // Ask Consolidator for answer } } object Query { def apply(title: String) = new Query[QMSearcher](title, Nil, Nil, Nil) } </code></pre> <p>Now, Searchers actors keep a list of filters, a list of fetchers, and the reference to the consolidator. They listen to messages informing them of these things, and for the query. For each result, they create a Filter actor for every filter in the list, send each of them the list of fetchers and the consolidator, and then send them the result.</p> <p>Filter actors keep a list of fetchers and a reference to the consolidator. They listen to messages informing them of these things, and for the result of the searcher. They send their output, if any, to newly created fetcher actors, who are first informed of the consolidator.</p> <p>Fetchers keep a reference to the consolidators. They listen to a message informing them of that reference, and to the result from the filter. They send their result, in turn, to the consolidator.</p> <p>The consolidator listen to two messages. One message, coming from fetcher actors, inform them of results, which they accumulate. Another message, coming from the Query, asks for that result, which it returns.</p> <p>The only thing left is devising a way to let the consolidator know that all results have been processed. One way would be the following:</p> <ol> <li>In the Query, inform the Consolidator actor of every Searcher that was created. The consolidator keeps a list of them, with a flag indicating whether they are finished or not.</li> <li>Each searcher keeps a list of the filters it created, and waits for a "done" message from them. When a searcher has no processing left to do and has received "done" from all filters, it sends a message to the consolidator informing it that it has finished.</li> <li>Each filter, in turn, keeps a list of fetchers <em>it</em> has created, and, likewise, waits for "done" messages from them. When it has finished processing, and has received "done" from all fetchers, it informs the searcher that it has done.</li> <li>It fetcher sends a "done" message to the filter that has created it when its work is completed and sent to the consolidator.</li> <li>The consolidator only listens to the message querying the result after it has received a "done" from all searchers.</li> </ol>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload