Skip to content


Subversion checkout URL

You can clone with
Download ZIP
Example server for Chapter 16 of Mahout in Action
branch: master
Failed to load latest commit information.
src/main Sample server farm
README Sample server farm
pom.xml Sample server farm


To use this example, you will need Java 6 and mvn to be installed already.  Open JDK is fine.

0. Download, compile and install mahout libraries

       svn co
       mv trunk mahout
       cd mahout
       mvn -DskipTests install

    The first time you do this it will download half of the western world.  This gets better with use.

1. Compile this code including client, server and model trainer

    Use this command
       mvn -DskipTests package
    to compile everything.  This creates target/ch16-1.0-jar-with-dependencies.jar.
2. Install, configure and start Zookeeper

    Download and run Apache Zookeeper from this page:
       tar zxvf zookeeper-3.3.3.tar.gz
       cp ./zookeeper-3.3.3/conf/zoo_sample.cfg ./zookeeper-3.3.3/conf/zoo.cfg
       sudo ./zookeeper-3.3.3/bin/ start
3. Start the server with no model yet

    In a separate window, go to the directory where you extracted this software and start the server
       java -cp target/ch16-1.0-jar-with-dependencies.jar  com.tdunning.ch16.server.Server
    This will produce error messages because Zookeeper doesn't have a model URL in it.  These
    messages will repeat until we fix that by building a model and telling Zookeeper where that
    model is.
4. Train a model

    To build a model for the 20 news groups data, download the data:
       tar zxvf 20news-bydate.tar.gz
    Then run the training program:
       java -mx1000m -cp target/ch16-1.0-jar-with-dependencies.jar com.tdunning.ch16.train.TrainNewsGroups 20news-bydate-train/
    This will produce lots of output.  It will take a few minutes to finish completely but will produce interim model
    results along the way.  Once you see a file called /tmp/news-group-3000.model you will be ready to tell the server
    to load that model.  The final result should give you the most accuracy.  It is stored in /tmp/news-group.model
5. Tell the server about the new model via Zookeeper

    Run the Zookeeper command line interface:
           ... log output lines ...
       [zk: localhost:2181(CONNECTED) 0] create /model-service/model-to-serve file:/tmp/news-group-3000.model
       Created /model-service/model-to-serve
       [zk: localhost:2181(CONNECTED) 1]
    Over in the server window you should see something like this within a few seconds of putting the model into
       11/05/27 20:48:27 WARN server.Server: Loading model from file:/tmp/news-group-3000.model
       11/05/27 20:48:27 INFO server.Server: done loading version 0
    You can mess with the server a little bit by giving it a different model to load or a bad file name:
       [zk: localhost:2181(CONNECTED) 1] set /model-service/model-to-serve file:/tmp/news-group-2500.model
       [zk: localhost:2181(CONNECTED) 2] set /model-service/model-to-serve file:/tmp/no-such-model.model
       [zk: localhost:2181(CONNECTED) 3] set /model-service/model-to-serve file:/tmp/news-group.model
    Each time you change this file on Zookeeper, the server should respond.  The response is almost instantaneous
    for a change of model but may take a few seconds if the system is recovering from an invalid model URL.
    The server output should look something like this:
       11/05/27 20:50:31 WARN server.Server: Loading model from file:/tmp/news-group-2500.model
       11/05/27 20:50:31 INFO server.Server: done loading version 1
       11/05/27 20:50:51 WARN server.Server: Loading model from file:/tmp/no-such-model.model
       11/05/27 20:50:51 ERROR server.Server: Failed to load model from file:/tmp/no-such-model.model /tmp/no-such-model.model (No such file or directory)
    	at Method)
    	at com.tdunning.ch16.server.Server$1.process(
    	at org.apache.zookeeper.ClientCnxn$
       11/05/27 20:51:06 WARN server.Server: Loading model from file:/tmp/news-group-3000.model
       11/05/27 20:51:06 INFO server.Server: done loading version 3
    Likewise, you can emulate a session expiration by using control-Z (unix only) to pause the server
    for 5-10 seconds.  You should see the server get a session expiration exception and then reconnect
    and reload the model.
6. Classify some data

    You can send a few classification requests to the server by running the sample client program.
       java -cp target/ch16-1.0-jar-with-dependencies.jar com.tdunning.ch16.client.Client
    This should produce something a lot like the following output:
       [0.05483312524126582, 0.053387027084160675, 0.05795630872834058, 0.04814920647604757, 0.04887495120450682, 0.05698449034115856, 0.052402388767486686, 0.03649784548083628, 0.04226219872179097, 0.049113831862600925, 0.038592728765213045, 0.06002963714513155, 0.049295643929958714, 0.06970468082142053, 0.04716914240563989, 0.07185404022050569, 0.0380260644141448, 0.046699086048427596, 0.035600312091787614, 0.04256729024957558]
       [0.06330439515922226, 0.056560054064692764, 0.02343542325381652, 0.05177427523603212, 0.036665787679528015, 0.05178567849176077, 0.02683583498898842, 0.08456194834549986, 0.026447663784874308, 0.04003566819867149, 0.032012526444505175, 0.16526835135003673, 0.0507057974805552, 0.04553203091882379, 0.0669502827598342, 0.041071210037759195, 0.04465434770121597, 0.026757171129609885, 0.03789223925903782, 0.027749313715535663]
       Highest score at index 11 which corresponds to sci.crypt
    The last line there is the important one.  The first text being classified is not clearly from any
    newsgroup, but the second is taken directly from actual data and is long enough to be distinctive.
    If the server is not running or doesn't have a live model to offer, you should see output like this
      Exception in thread "main" java.lang.IllegalStateException: No servers to query
    	at com.tdunning.ch16.client.Client.main(
    Note that if the server ever loads a valid model then deleting or corrupting the model url
    in Zookeeper won't make the server stop serving requests.  Instead, the server will keep the
    last valid model it saw.
Something went wrong with that request. Please try again.