<!DOCTYPE article PUBLIC "-//NLM//DTD JATS (Z39.96) Journal Archiving and Interchange DTD v1.0 20120330//EN" "JATS-archivearticle1.dtd">
<article xmlns:xlink="http://www.w3.org/1999/xlink">
  <front>
    <journal-meta />
    <article-meta>
      <title-group>
        <article-title>The Curse of Zipf and Limits to Parallelization: A Look at the Stragglers Problem in MapReduce</article-title>
      </title-group>
      <contrib-group>
        <contrib contrib-type="author">
          <string-name>Jimmy Lin</string-name>
          <email>jimmylin@umd.edu</email>
          <xref ref-type="aff" rid="aff0">0</xref>
          <xref ref-type="aff" rid="aff1">1</xref>
        </contrib>
        <aff id="aff0">
          <label>0</label>
          <institution>General Terms: Algorithms</institution>
          ,
          <addr-line>Performance</addr-line>
        </aff>
        <aff id="aff1">
          <label>1</label>
          <institution>The iSchool, College of Information Studies, University of Maryland National Center for Biotechnology Information, U.S. National Library of Medicine</institution>
          ,
          <country country="US">USA</country>
        </aff>
      </contrib-group>
      <abstract>
        <p>This paper explores the problem of \stragglers" in MapReduce: a common phenomenon where a small number of mappers or reducers takes signi cantly longer than the others to complete. The e ects of these stragglers include unnecessarily long wall-clock running times and sub-optimal cluster utilization. In many cases, this problem cannot simply be attributed to hardware idiosyncrasies, but is rather caused by the Zip an distribution of input or intermediate data. I present a simple theoretical model that shows how such distributions impose a fundamental limit on the amount of parallelism that can be extracted from a large class of algorithms where all occurrences of the same element must be processed together. A case study in parallel ad hoc query evaluation highlights the severity of the stragglers problem. Fortunately, a simple modi cation of the input data cuts end-to-end running time in half. This example illustrates some of the issues associated with designing e cient MapReduce algorithms for real-world datasets.</p>
      </abstract>
    </article-meta>
  </front>
  <body>
    <sec id="sec-1">
      <title>-</title>
      <p>Categories and Subject Descriptors: H.3.3
[Information Storage and Retrieval]: Information Search and
Retrieval</p>
    </sec>
    <sec id="sec-2">
      <title>1. INTRODUCTION</title>
      <p>
        The only practical solution to large data problems
today is to distribute computations across multiple machines
in a cluster. With traditional parallel programming
models (e.g., MPI, pthreads), the developer shoulders the
burden of explicitly managing concurrency. As a result, a
signi cant amount of the developer's attention must be
devoted to managing system-level details (e.g.,
synchronization primitives, inter-process communication, data
transfer, etc.). MapReduce [
        <xref ref-type="bibr" rid="ref2">2</xref>
        ] presents an attractive
alternative: its functional abstraction provides an
easy-to-understand model for designing scalable, distributed algorithms.
      </p>
      <p>Taking inspiration from higher-order functions in
functional programming, MapReduce provides an abstraction for
Copyright c 2009 for the individual papers by the papers’ authors.
Copying permitted for private and academic purposes. Re-publication of material
from this volume requires permission by the copyright owners. This volume
is published by its editors.</p>
      <p>LSDS-IR Workshop. July 2009. Boston, USA.
programmer-de ned \mappers" and \reducers". Key-value
pairs form the processing primitives in MapReduce. The
mapper is applied to every input key-value pair to generate
an arbitrary number of intermediate key-value pairs. The
reducer is applied to all values associated with the same
intermediate key to generate output key-value pairs. This
two-stage processing structure is illustrated in Figure 1.</p>
      <p>
        Under the MapReduce framework, a programmer needs
only to provide implementations of the mapper and reducer.
On top of a distributed le system [
        <xref ref-type="bibr" rid="ref3">3</xref>
        ], the runtime
transparently handles all other aspects of execution on clusters
ranging from a few to a few thousand processors. The
runtime is responsible for scheduling, coordination, handling
faults, and the potentially very large sorting problem
between the map and reduce phases whereby intermediate
keyvalue pairs must be grouped by key. The availability of
Hadoop, an open-source implementation of the MapReduce
programming model, coupled with the dropping cost of
commodity hardware and the growing popularity of alternatives
such as utility computing, has brought data-intensive
distributed computing within the reach of many academic
researchers [
        <xref ref-type="bibr" rid="ref5">5</xref>
        ].
      </p>
      <p>This paper explores a performance issue frequently
encountered with MapReduce algorithms on natural language
text and other large datasets: the \stragglers problem", where
the distribution of running times for mappers and reducers
is highly skewed. Often, a small number of mappers takes
signi cantly longer to complete than the rest, thus blocking
the progress of the entire job. Since in MapReduce the
reducers cannot start until all the mappers have nished, a
few stragglers can have a large impact on overall end-to-end
running time. The same observation similarly applies to the
reduce stage, where a small number of long-running
reducers can signi cantly delay the completion of a MapReduce
job. In addition to long running times, the stragglers
phenomenon has implications for cluster utilization|while a
submitted job waits for the last mapper or reducer to
complete, most of the cluster is idle. Of course, interleaving the
execution of multiple MapReduce jobs alleviates this
problem, but presently, the scheduler in the open-source Hadoop
implementation remains relatively rudimentary.</p>
      <p>
        There are two main reasons for the stragglers problem.
The rst is idiosyncrasies of machines in a large cluster|
this problem is nicely handled by \speculative execution" [
        <xref ref-type="bibr" rid="ref2">2</xref>
        ],
which is implemented in Hadoop. To handle machine-level
variations, multiple instances of the same mapper or
reducer are redundantly executed in parallel (depending on
the availability of cluster resources), and results from the
input
input
input
input
map
map
map
      </p>
      <p>map</p>
      <p>Barrier: group values by keys
reduce
reduce</p>
      <p>reduce
output output output</p>
      <p>rst instance to nish are used (the remaining results are
discarded). This, however, does not address skewed
running times caused by the distribution of input or
intermediate data. To illustrate this, consider the simple example of
word count using MapReduce (for example, as the rst step
to computing collection frequency in a language-modeling
framework for information retrieval): the mappers emit
keyvalues pairs with the term as the key and the local count as
the value. Reducers sum up the local counts to arrive at the
global counts. Due to the distribution of terms in natural
language, some reducers will have more work than others
(in the limit, imagine counting stopwords)|this yields
potentially large di erences in running times, independent of
hardware idiosyncrasies.</p>
      <p>This paper explores the stragglers problem in MapReduce,
starting rst with a theoretical analysis in Section 2. A
speci c case study in parallel ad hoc query evaluation is
discussed in Section 3; for that speci c task, a simple
manipulation of the input data yields a signi cant decrease in
wallclock running time. I conclude with some thoughts on the
design of MapReduce algorithms in light of these ndings.</p>
    </sec>
    <sec id="sec-3">
      <title>A THEORETICAL ANALYSIS</title>
      <p>
        It is a well-known observation that word occurrences in
natural language, to a rst approximation, follow a Zip an
distribution. Many other naturally-occurring phenomena,
ranging from website popularity to sizes of craters on the
moon, can be similarly characterized [
        <xref ref-type="bibr" rid="ref7">7</xref>
        ]. Loosely
formulated, Zip an distributions are those where a few elements
are exceedingly common, but contain a \long tail" of rare
events. More precisely, for a population of N elements,
ordered by frequency of occurrence, the frequency of the
element with rank k can be characterized by:
p(k; s; N ) =
      </p>
      <p>k s
PN
n=1 1=ns
(1)
where s is the characteristic exponent. The denominator is
known as the N th generalized harmonic number, often
written as HN;s. For many types of algorithms, all occurrences
of the same type of element must be processed together.
That is, the element type represents the nest grain of
parallelism that can be achieved. Let us assume that the amount
of \work" associated with processing a type of element is
2 y = 1
0 0
1</p>
      <p>2 3
s (characteristic exponent)
4
5
O(n) with respect to the number of element instances. In
other words, the amount of work necessary to process an
element is proportional to its frequency. If we normalize the
total amount of work to one, then the fraction of the total
work that must be devoted to processing the most common
element is:</p>
      <p>
        Even if we assume unlimited resources and the ability to
process all element types in parallel, the running time of
an algorithm would still be bound by the time required to
process the most frequent element. In the same spirit as
Amdahl's Law [
        <xref ref-type="bibr" rid="ref1">1</xref>
        ], Zipf's Law places a theoretical upper bound
on the amount of parallelism that can be extracted for
certain classes of algorithms. In short, an algorithm is only as
fast as the slowest of the sub-tasks that can run in parallel.
      </p>
      <p>As a concrete example, suppose N = 106 and s = 1. The
most frequently-occurring element would be observed about
6.95% percent of the time|which means that the maximum
theoretical speedup of any parallel algorithm is about a
factor of 14 (assuming that all instances of the same element
must be processed together). For this class of algorithms,
the maximum theoretical speedup is simply HN;s. Figure 2
plots HN;s with varying values of s for N = 106. This simple
theoretical model shows that Zip an distributions present a
serious impediment to the development of e cient parallel
algorithms for a large class of real-world problems.</p>
      <p>This analysis can be directly applied to MapReduce
algorithms. In a common scenario, each key corresponds to
a single type of element, and the fraction of total values
associated with each key can be characterized by a Zip an
distribution. In other words, a few keys have a large number
of associated values, while a very large number of keys have
only a few values. Take the two following examples:</p>
      <p>Inverted indexing. The well-known MapReduce
algorithm for inverted indexing begins by mapping over input
documents and emitting individual postings as intermediate
key-value pairs. All postings associated with each term are
gathered in the reducer, where the nal postings lists are
created and written to disk. The most straightforward
implementation of the algorithm divides the term space into
roughly equal-sized partitions and assigns each to a reducer
(typically, through hashing). This, however, does not take
into account the inherent distribution of document
frequencies (which characterizes the length of each postings list, and
hence the amount of work that needs to be done for each
term). Due to the Zip an distribution of term occurrences,
the reducers assigned to very frequent terms will have
signi cantly more work than the other reducers, and therefore
take much longer to complete. These are the stragglers
observed in the execution of the algorithm.</p>
      <p>
        Computing PageRank over large graphs. Although
Google recently revealed that it has developed
infrastructure speci cally designed for large-scale graph algorithms
(called Pregel), the implementation of PageRank [
        <xref ref-type="bibr" rid="ref8">8</xref>
        ] in
MapReduce is nevertheless instructive. The standard iterative
MapReduce algorithm for computing PageRank maps over
adjacency lists associated with each vertex (containing
information about outlinks); PageRank contributions are passed
onto the target of those outlinks, keyed by the target
vertex id. In the reduce stage, PageRank contributions for each
vertex are totaled.1 In the simplest implementation, vertices
are distributed across the reducers such that each is
responsible for roughly the same number of vertices (by hashing).
However, the highly skewed distribution of incoming links to
a page presents a problem: the vast majority of pages have
few inbound links, while a few (e.g., the Google homepage)
have many orders of magnitude more. In computing
PageRank, the amount of work required to process a vertex is
roughly proportional to the number of incoming links. The
stragglers are exactly those assigned to process vertices in
the graph with large in-degrees.
      </p>
      <p>In practice, faster speed-ups than predicted are possible
because in most cases some amount of local aggregation can
be performed, thus making the skewed key-value
distributions less pronounced. In MapReduce, this is accomplished
with \combiners", which can dramatically increase e ciency.
Nevertheless, the stragglers problem remains both common
and severe.</p>
      <p>In both of the examples presented above, the stragglers
problem is most severe in the reduce stage of processing,
since the distribution of the intermediate data can be
characterized as Zip an. However, depending on the
distribution of input key-value pairs, it is also possible to have the
stragglers problem in the map phase|in fact, the case study
presented in the next section examines such a case.</p>
    </sec>
    <sec id="sec-4">
      <title>PARALLEL QUERIES: A CASE STUDY</title>
      <p>
        This paper presents a case study of the stragglers
problem that builds on the parallel queries algorithm described in
SIGIR 2009 [
        <xref ref-type="bibr" rid="ref6">6</xref>
        ]. This piece is meant to serve as a companion
to the paper in the main conference proceedings. The
problem explored here nicely illustrates how the running time of
a MapReduce algorithm is dominated by the slowest parallel
sub-task. Fortunately, for this problem, a simple
manipulation of the input data cuts running time in half.
1This algorithm sketch ignores details such as handling of
dangling links and the jump factor.
1: procedure Map(Term t; Postings P )
2: [Q1; Q2; : : : Qn] LoadQueries()
3: for all Qi 2 [Q1; Q2; : : : Qn] do
4: if t 2 Qi then
5: Initialize.AssociativeArray(H)
6: for all ha; f i 2 P do
7: Hfag wt;q wt;d
8: Emit(i; H)
1: procedure Reduce(Qid i; [H1; H2; H3; : : :])
2: Initialize.AssociativeArray(Hf )
3: for all H 2 [H1; H2; H3; : : :] do
4: Merge(Hf ; H)
5: Emit(i; Hf )
      </p>
      <p>
        Computing pairwise similarity on document collections is
a task common to a variety of problems such as clustering,
unsupervised learning, and text retrieval. One algorithm
presented in [
        <xref ref-type="bibr" rid="ref6">6</xref>
        ] treats this task as a very large ad hoc
retrieval problem (where query-document scores are computed
via inner products of weighted feature vectors). This
proceeds as follows: First, the entire collection is divided up into
individual blocks of documents; these are treated as blocks
of \queries". For each document block, the parallel retrieval
algorithm in Figure 3 is applied. The input to each
mapper is a term t (the key) and its postings list P (the value).
The mapper loads all the queries at once and processes each
query in turn. If the query does not contain t, no action is
performed. If the query contains t, then the corresponding
postings must be traversed to compute the partial
contributions to the query-document score. For each posting
element, the partial contribution to the score (wt;q wt;d) is
computed and stored in an associative array H, indexed by
the document id a|this structure holds the accumulators.
The mapper emits an intermediate key-value pair with the
query number i as the key and H as the value. The result of
each mapper is all partial query-document scores associated
with term t for all queries that contain the term.
      </p>
      <p>In the reduce phase, all associative arrays belonging to
the same query are brought together. The reducer performs
an element-wise sum of all the associative arrays (denoted
by Merge in the pseudo-code): this adds up the
contributions for each query term across all documents. The
nal result is an associative array holding complete
querydocument scores. In e ect, this algorithm replaces random
access to the postings with a parallel scan of all postings. In
processing a set of queries, each postings list is accessed only
once|each mapper computes partial score contributions for
all queries that contain the term. Pairwise similarity for the
entire collection can be computed by running this algorithm
over all blocks in the collection. For more details, please
refer to additional discussions of this algorithm in the SIGIR
2009 main proceedings paper.
3.2</p>
    </sec>
    <sec id="sec-5">
      <title>Experimental Results</title>
      <p>
        Experiments using the algorithm presented in Figure 3
were conducted on a collection of 4.59m MEDLINE
abstracts (from journals in the life and health sciences domain),
used in the TREC 2005 genomics track [
        <xref ref-type="bibr" rid="ref4">4</xref>
        ]. From the list of
relevant documents for the evaluation, 472 (approximately
one tenth) were selected to serve as the \queries". The
entire text of each abstract was taken verbatim as the query.
On average, each query contained approximately 120 terms
after stopword removal. All runs were performed on a large
cluster running the Hadoop implementation of MapReduce
(version 0.17.3) with Java 1.5; jobs were con gured with 500
mappers and 200 reducers. The parallel queries algorithm
was implemented in pure Java. Although the cluster
contains a large number of machines, each individual machine
is relatively slow, based on informal benchmarks.2
      </p>
      <p>An inverted index was built from the entire collection.3
Figure 4 shows the document frequencies of all 1.3m unique
terms in the collection: on the x-axis, the document
frequency of a term, and on the y-axis, the number of terms
that have that df. Approximately 753k terms appear only
once, and approximately 168k terms appear only twice. The
term with the largest df appeared in 1.62m documents (or
about one in three documents). This distribution is fairly
typical of information retrieval text collections.</p>
      <p>The thick line in Figure 5 plots the progress of the
MapReduce job on the unmodi ed index of the document
collection: wall-clock time (in seconds) on the x-axis and number
of active workers (either mappers or reducers) on the y-axis.
At the beginning of the job, 500 mappers are started by the
MapReduce runtime; the number of running mappers
decreases as the job progresses. When all the mappers have
nished, 200 reducers start up after a short lull (during this
time the framework is copying intermediate key-value pairs
from mappers to reducers). Finally, the job ends when all
reducers complete and the results have been written to disk.</p>
      <p>
        The map phase of execution completes in 1399s; the
reduce phase begins at the 1418s mark, and the entire job
nishes in 1675s. The long tail of the plot in the map phase
graphically illustrates the stragglers problem. Consider the
following statistics, which can be interpreted as checkpoints
corresponding to 98.0%, 99.0%, and 99.8% mapper progress:
At the 467s mark, all except for 10 mappers (2% of
the total) have completed.
2The hardware con guration is the same as the setup in [
        <xref ref-type="bibr" rid="ref6">6</xref>
        ].
3The tokenizer from the open-source Lucene search engine was
adapted for document processing. A list of stopwords from the
Terrier search engine was used.
original postings lists
split 100k postings lists
      </p>
      <p>At the 532s mark, all except for 5 mappers (1% of the
total) have completed.</p>
      <p>At the 1131s mark, all except for one mapper have
nished|the last mapper would run for about another
4.5 minutes before nishing.</p>
      <p>Since all mappers must complete before the reducers can
begin processing intermediate key-value pairs, the running
time of the map phase is dominated by the slowest mapper,
which as shown here takes signi cantly longer than the rest
of the mappers. Repeated trials of the same experiment
produced essentially the same behavior (not shown).</p>
      <p>The behavior of the parallel queries algorithm is explained
by the empirical distribution of the length of the postings
lists (see Figure 4). There are a few very long postings
lists (corresponding to common terms such as \gene" or
\patient"), while the vast majority of the postings lists are very
short. Since for each query term the postings must be
traversed to compute partial document score contributions, the
amount of work involved in processing a query term is on
the order of the length of the postings list. Therefore, the
mappers assigned to process common query terms will run
for a disproportionately long time|these are exactly the
stragglers observed in Figure 5. These empirical results are
consistent with the theoretical model presented in Section 2.
However, the situation is not quite as grim in some cases|in
a retrieval application, user queries are less likely to contain
common terms since they are typically less helpful in
specifying an information need.</p>
      <p>A natural solution to the stragglers problem, in this case,
is to break long postings lists into shorter ones. Exactly
such a solution was implemented: postings lists were split
into 100k segments, so that terms contained in more than
100k documents were associated with multiple postings lists.
Furthermore, the ordering of all the postings segments were
randomized (as opposed to alphabetically sorted by term,
as in the original inverted index).4 Note that this modi
cation to the inverted index did not require any changes to
4This algorithm was straightforwardly implemented in
MapReduce, by mapping over the original inverted index and writing
a new copy.
the parallel queries algorithm. Although partial score
contributions for a single query term might now be computed
in di erent mappers, all partial scores will still be collected
together in the same reducer during the element-wise sum
across associative arrays keyed by the same query id.</p>
      <p>The thin (red) line in Figure 5 plots the progress of the
MapReduce job on the modi ed index. The map phase of
execution completes in 636s; the reduce phase begins at the
665s mark, and the entire job nishes in 831s. With this
simple modi cation to the inverted index, the same algorithm
runs in about half the wall-clock time. Table 1 compares the
98.0%, 99.0%, 99.8%, and 100.0% progress of the mappers
for both the original and segmented postings list. Multiple
trials of the same experiment gave rise to similar results.</p>
      <p>As a follow up, additional experiments were conducted
with even smaller postings segments, but ner splits did
further decrease running time. This is likely due to the
distribution of query terms|some postings lists will never be
traversed no matter how nely segmented they are, since the
query documents contain only a subset of all terms in the
collection (and by implication, some mappers will do little
work regardless).</p>
      <p>Why does this simple manipulation of the input data work
so well? It is important to note that the technique does
not actually reduce the number of computations required to
produce query-document scores. The total amount of work
(i.e., area under the curve) is the same|however, with the
segmented index, work is more evenly distributed across the
mappers. In essence, splitting long postings lists is a simple,
yet e ective, approach to \defeating" Zip an distributions
for this particular application.</p>
    </sec>
    <sec id="sec-6">
      <title>DISCUSSION</title>
      <p>The limits on parallelization imposed by Zip an
distributions is based on one important assumption|that all
instances of the same type of element must be processed
together. The simple approach to overcoming the stragglers
problem is to devise algorithms that do not depend on this
assumption. In the parallel queries case, this required only
manipulating input data and no modi cations to the
algorithm: query-document scores could be computed
independently, since the associative arrays in which they are held
would eventually be brought together and merged in the
reduce stage.</p>
      <p>Although the parallel queries case study dealt with
stragglers in the map phase due to distributional characteristics
of the input data, the same principles can be applied to
stragglers in the reduce phase as well. However, there are
additional complexities that need to be considered. Often,
it is known in advance that intermediate data can be
characterized as Zip an|but devising algorithms to address the
issue may require actually knowing which elements occupy
the head of the distribution. This in turn requires executing
the algorithm itself, which may be slow precisely because of
the stragglers problem. This chicken-and-egg dependency
can be broken by sampling strategies, but at the cost of
greater complexity in algorithm design.</p>
      <p>For solving reduce-phase stragglers, once the distribution
of intermediate data has been characterized, a more
intelligent partitioner can better distribute load across the
reducers. Unfortunately, this may still be insu cient in some
cases, for example, PageRank computations. Recall that in
computing PageRank all contributions from inbound links
must be summed, thereby creating the requirement that all
values associated with the same key (i.e., vertex in graph)
be processed together. The only recourse here is a modi
cation of the original algorithm (e.g., a multi-stage process
for totaling the PageRank contributions of pages with large
in-degrees).</p>
      <p>The upshot of this discussion is that to overcome the e
ciency bottleneck imposed by Zip an distributions,
developers must apply application-speci c knowledge to parallelize
the processing of common elements. This, in turn, depends
on the ingenuity of the individual developer and requires
insight into the problem being tackled.
5.</p>
    </sec>
    <sec id="sec-7">
      <title>CONCLUSION</title>
      <p>This paper explores the stragglers problem in MapReduce
caused by Zip an distributions common in many real-world
datasets. What are the broader implications of these
ndings? I believe that two lessons are apparent:</p>
      <p>First, e cient MapReduce algorithms are not quite as
easy to design as one might think. The allure of
MapReduce is that it presents a simple programming model
for designing scalable algorithms. While this remains an
accurate statement, the deeper truth is that there is still
quite a bit of \art" in designing e cient MapReduce
algorithms for non-toy problems|witness the case study
presented in this paper, where a simple tweak to the input
data cut running time in half.5
Second, MapReduce algorithms cannot be studied in
isolation, divorced from real-world applications|the
stragglers problem is caused by properties of datasets
(critically, not from the processing architecture or inherent
bottlenecks in the algorithm). Furthermore, since there does
not appear to be a general-purpose, universally-applicable
solution to the problem, it is of limited value to discuss
algorithmic performance without reference to speci c
applications.</p>
      <p>Hopefully, these two lessons will be useful to future
designers of MapReduce algorithms.
6.</p>
    </sec>
    <sec id="sec-8">
      <title>ACKNOWLEDGMENTS</title>
      <p>This work was supported by the following sources: the
Intramural Research Program of the NIH, National Library of
Medicine; NSF under awards IIS-0705832 and IIS-0836560
(under the CLuE program); Google and IBM, via the
Academic Cloud Computing Initiative. I am grateful to Esther
and Kiri for their love.
5Although one might argue how obvious this solution is, I think it
is safe to say that the solution requires a degree of understanding
of both information retrieval algorithms and MapReduce that a
novice would be unlikely to have.</p>
    </sec>
  </body>
  <back>
    <ref-list>
      <ref id="ref1">
        <mixed-citation>
          [1]
          <string-name>
            <given-names>G.</given-names>
            <surname>Amdahl</surname>
          </string-name>
          .
          <article-title>Validity of the single processor approach to achieving large-scale computing capabilities</article-title>
          .
          <source>In Proceedings of the AFIPS Spring Joint Computer Conference</source>
          , pages
          <volume>483</volume>
          {
          <fpage>485</fpage>
          ,
          <year>1967</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref2">
        <mixed-citation>
          [2]
          <string-name>
            <given-names>J.</given-names>
            <surname>Dean</surname>
          </string-name>
          and
          <string-name>
            <given-names>S.</given-names>
            <surname>Ghemawat</surname>
          </string-name>
          . MapReduce:
          <article-title>Simpli ed data processing on large clusters</article-title>
          .
          <source>In Proceedings of the 6th Symposium on Operating System Design and Implementation</source>
          (OSDI
          <year>2004</year>
          ), pages
          <fpage>137</fpage>
          {
          <fpage>150</fpage>
          , San Francisco, California,
          <year>2004</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref3">
        <mixed-citation>
          [3]
          <string-name>
            <given-names>S.</given-names>
            <surname>Ghemawat</surname>
          </string-name>
          ,
          <string-name>
            <given-names>H.</given-names>
            <surname>Gobio</surname>
          </string-name>
          , and S.-T. Leung.
          <article-title>The Google File System</article-title>
          .
          <source>In Proceedings of the 19th ACM Symposium on Operating Systems Principles (SOSP</source>
          <year>2003</year>
          ), pages
          <fpage>29</fpage>
          {
          <fpage>43</fpage>
          ,
          <string-name>
            <surname>Bolton</surname>
            <given-names>Landing</given-names>
          </string-name>
          , New York,
          <year>2003</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref4">
        <mixed-citation>
          [4]
          <string-name>
            <given-names>W. R.</given-names>
            <surname>Hersh</surname>
          </string-name>
          ,
          <string-name>
            <given-names>A.</given-names>
            <surname>Cohen</surname>
          </string-name>
          ,
          <string-name>
            <given-names>J.</given-names>
            <surname>Yang</surname>
          </string-name>
          ,
          <string-name>
            <given-names>R.</given-names>
            <surname>Bhupatiraju</surname>
          </string-name>
          ,
          <string-name>
            <given-names>P.</given-names>
            <surname>Roberts</surname>
          </string-name>
          , and
          <string-name>
            <given-names>M.</given-names>
            <surname>Hearst</surname>
          </string-name>
          .
          <article-title>TREC 2005 Genomics Track overview</article-title>
          .
          <source>In Proceedings of the Fourteenth Text REtrieval Conference (TREC</source>
          <year>2005</year>
          ), Gaithersburg, Maryland,
          <year>2005</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref5">
        <mixed-citation>
          [5]
          <string-name>
            <given-names>J.</given-names>
            <surname>Lin</surname>
          </string-name>
          .
          <article-title>Scalable language processing algorithms for the masses: A case study in computing word co-occurrence matrices with mapreduce</article-title>
          .
          <source>In Proceedings of the 2008 Conference on Empirical Methods in Natural Language Processing (EMNLP</source>
          <year>2008</year>
          ), pages
          <fpage>419</fpage>
          {
          <fpage>428</fpage>
          ,
          <string-name>
            <surname>Honolulu</surname>
          </string-name>
          , Hawaii,
          <year>2008</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref6">
        <mixed-citation>
          [6]
          <string-name>
            <given-names>J.</given-names>
            <surname>Lin</surname>
          </string-name>
          .
          <article-title>Brute force and indexed approaches to pairwise document similarity comparisons with mapreduce</article-title>
          .
          <source>In Proceedings of the 32nd Annual International ACM SIGIR Conference on Research and Development in Information Retrieval (SIGIR</source>
          <year>2009</year>
          ), Boston, Massachusetts,
          <year>2009</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref7">
        <mixed-citation>
          [7]
          <string-name>
            <given-names>M.</given-names>
            <surname>Newman</surname>
          </string-name>
          .
          <article-title>Power laws, Pareto distributions and Zipf's law</article-title>
          .
          <source>Contemporary Physics</source>
          ,
          <volume>46</volume>
          (
          <issue>5</issue>
          ):
          <volume>323</volume>
          {
          <fpage>351</fpage>
          ,
          <year>2005</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref8">
        <mixed-citation>
          [8]
          <string-name>
            <given-names>L.</given-names>
            <surname>Page</surname>
          </string-name>
          ,
          <string-name>
            <given-names>S.</given-names>
            <surname>Brin</surname>
          </string-name>
          ,
          <string-name>
            <given-names>R.</given-names>
            <surname>Motwani</surname>
          </string-name>
          , and
          <string-name>
            <given-names>T.</given-names>
            <surname>Winograd</surname>
          </string-name>
          .
          <article-title>The PageRank citation ranking: Bringing order to the Web</article-title>
          . Stanford
          <string-name>
            <surname>Digital Library Working Paper SIDL-WP-</surname>
          </string-name>
          1999-0120, Stanford University,
          <year>1999</year>
          .
        </mixed-citation>
      </ref>
    </ref-list>
  </back>
</article>