diff --git a/vipra-backend/src/main/java/de/vipra/rest/resource/WordResource.java b/vipra-backend/src/main/java/de/vipra/rest/resource/WordResource.java
new file mode 100644
index 0000000000000000000000000000000000000000..646c64fde3fa65c2490d606f71e123751f4824fa
--- /dev/null
+++ b/vipra-backend/src/main/java/de/vipra/rest/resource/WordResource.java
@@ -0,0 +1,104 @@
+package de.vipra.rest.resource;
+
+import java.io.IOException;
+import java.util.List;
+
+import javax.servlet.ServletContext;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DefaultValue;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+
+import de.vipra.rest.Messages;
+import de.vipra.rest.model.APIError;
+import de.vipra.rest.model.ResponseWrapper;
+import de.vipra.util.Config;
+import de.vipra.util.StringUtils;
+import de.vipra.util.ex.ConfigException;
+import de.vipra.util.model.TopicModel;
+import de.vipra.util.model.WordFull;
+import de.vipra.util.service.MongoService;
+import de.vipra.util.service.Service.QueryBuilder;
+
+@Path("words")
+public class WordResource {
+
+	@Context
+	UriInfo uri;
+
+	final MongoService<WordFull, String> dbWords;
+
+	public WordResource(@Context final ServletContext servletContext) throws ConfigException, IOException {
+		final Config config = Config.getConfig();
+		dbWords = MongoService.getDatabaseService(config, WordFull.class);
+	}
+
+	@GET
+	@Produces(MediaType.APPLICATION_JSON)
+	public Response getWords(@QueryParam("topicModel") final String topicModel, @QueryParam("skip") final Integer skip,
+			@QueryParam("limit") final Integer limit, @QueryParam("sort") @DefaultValue("id") final String sortBy,
+			@QueryParam("fields") final String fields) {
+		final ResponseWrapper<List<WordFull>> res = new ResponseWrapper<>();
+
+		if (res.hasErrors())
+			return res.badRequest();
+
+		try {
+			final QueryBuilder query = QueryBuilder.builder().skip(skip).limit(limit).sortBy(sortBy);
+			if (fields != null && !fields.isEmpty())
+				query.fields(true, StringUtils.getFields(fields));
+
+			if (topicModel != null && !topicModel.isEmpty())
+				query.criteria("topicModel", new TopicModel(topicModel));
+
+			final List<WordFull> words = dbWords.getMultiple(query);
+
+			if ((skip != null && skip > 0) || (limit != null && limit > 0))
+				res.addHeader("total", dbWords.count(null));
+			else
+				res.addHeader("total", words.size());
+
+			return res.ok(words);
+		} catch (final Exception e) {
+			e.printStackTrace();
+			res.addError(new APIError(Response.Status.BAD_REQUEST, "Error", e.getMessage()));
+			return res.badRequest();
+		}
+	}
+
+	@GET
+	@Produces(MediaType.APPLICATION_JSON)
+	@Consumes(MediaType.APPLICATION_JSON)
+	@Path("{id}")
+	public Response getWord(@PathParam("id") final String id, @QueryParam("fields") final String fields) {
+		final ResponseWrapper<WordFull> res = new ResponseWrapper<>();
+		if (id == null || id.trim().length() == 0) {
+			res.addError(new APIError(Response.Status.BAD_REQUEST, "ID is empty", String.format(Messages.BAD_REQUEST, "id cannot be empty")));
+			return res.badRequest();
+		}
+
+		WordFull word;
+		try {
+			word = dbWords.getSingle(id, StringUtils.getFields(fields));
+		} catch (final Exception e) {
+			e.printStackTrace();
+			res.addError(new APIError(Response.Status.BAD_REQUEST, "Error", e.getMessage()));
+			return res.badRequest();
+		}
+
+		if (word != null) {
+			return res.ok(word);
+		} else {
+			res.addError(new APIError(Response.Status.NOT_FOUND, "Resource not found", String.format(Messages.NOT_FOUND, "word", id)));
+			return res.notFound();
+		}
+	}
+
+}
diff --git a/vipra-cmd/src/main/java/de/vipra/cmd/file/Filebase.java b/vipra-cmd/src/main/java/de/vipra/cmd/file/Filebase.java
index 09b461eb8d916b47852c879976e4c5721744a51b..09141da0ab88216799fc84f4a0103eed44dc8242 100644
--- a/vipra-cmd/src/main/java/de/vipra/cmd/file/Filebase.java
+++ b/vipra-cmd/src/main/java/de/vipra/cmd/file/Filebase.java
@@ -97,4 +97,16 @@ public class Filebase {
 		windowIndex.sync();
 	}
 
+	public FilebaseIDDateIndex getIdDateIndex() {
+		return idDateIndex;
+	}
+
+	public FilebaseWordIndex getWordIndex() {
+		return wordIndex;
+	}
+
+	public FilebaseWindowIndex getWindowIndex() {
+		return windowIndex;
+	}
+
 }
diff --git a/vipra-cmd/src/main/java/de/vipra/cmd/file/FilebaseWordIndex.java b/vipra-cmd/src/main/java/de/vipra/cmd/file/FilebaseWordIndex.java
index fc1cb496dd7d6f8d5cb08796b0d478f4fa02ae07..c939f635cdd9dfcd0e6bb2e6b64ceb1563776160 100644
--- a/vipra-cmd/src/main/java/de/vipra/cmd/file/FilebaseWordIndex.java
+++ b/vipra-cmd/src/main/java/de/vipra/cmd/file/FilebaseWordIndex.java
@@ -7,10 +7,12 @@ import java.io.IOException;
 import java.io.OutputStreamWriter;
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.Set;
 
 import de.vipra.util.Constants;
 import de.vipra.util.CountMap;
@@ -26,10 +28,12 @@ public class FilebaseWordIndex implements Iterable<String> {
 	private final List<String> words;
 	private final Map<String, Integer> wordIndex;
 	private final CountMap<String> wordDocumentCount;
+	private final Set<String> newWords;
 	private int nextIndex = 0;
 
 	public FilebaseWordIndex(final File modelDir) throws IOException {
 		file = new File(modelDir, FILE_NAME);
+		newWords = new HashSet<>();
 		if (file.exists()) {
 			final List<String> lines = FileUtils.readFile(file);
 			words = new ArrayList<>(lines.size());
@@ -51,8 +55,8 @@ public class FilebaseWordIndex implements Iterable<String> {
 	public void sync() throws IOException {
 		if (!dirty)
 			return;
-		BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file, false)));
-		for (String word : words) {
+		final BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file, false)));
+		for (final String word : words) {
 			out.write(word);
 			out.write(",");
 			out.write(Integer.toString(wordDocumentCount.get(word)));
@@ -63,14 +67,16 @@ public class FilebaseWordIndex implements Iterable<String> {
 	}
 
 	public void countWords(final List<ArticleWord> articleWords) {
-		for (ArticleWord articleWord : articleWords)
-			wordDocumentCount.count(articleWord.getWord());
+		for (final ArticleWord articleWord : articleWords)
+			wordDocumentCount.count(articleWord.getId());
 	}
 
 	public String transform(final String[] words) {
 		final CountMap<String> countMap = new CountMap<>();
-		for (final String word : words)
+		for (final String word : words) {
 			countMap.count(word);
+			newWords.add(word);
+		}
 
 		final StringBuilder sb = new StringBuilder();
 		sb.append(countMap.size());
@@ -107,6 +113,10 @@ public class FilebaseWordIndex implements Iterable<String> {
 		return words.size();
 	}
 
+	public Set<String> getNewWords() {
+		return newWords;
+	}
+
 	@Override
 	public Iterator<String> iterator() {
 		return words.iterator();
diff --git a/vipra-cmd/src/main/java/de/vipra/cmd/lda/Analyzer.java b/vipra-cmd/src/main/java/de/vipra/cmd/lda/Analyzer.java
index 57775a174799df32a197e30ae759310aa9e20209..1882c49eda2e72ffba6e3640f24725a808c14765 100644
--- a/vipra-cmd/src/main/java/de/vipra/cmd/lda/Analyzer.java
+++ b/vipra-cmd/src/main/java/de/vipra/cmd/lda/Analyzer.java
@@ -300,11 +300,11 @@ public class Analyzer {
 			final List<TopicWord> newTopicWords = new ArrayList<>(modelConfig.getkTopWords());
 			for (final SequenceWord sequenceWord : topTopicWordsList) {
 				final TopicWord newTopicWord = new TopicWord();
-				newTopicWord.setWord(sequenceWord.getWord());
+				newTopicWord.setId(sequenceWord.getId());
 				final List<Double> sequenceProbabilities = new ArrayList<>(windowCount);
 				final List<Double> sequenceProbabilitiesChange = new ArrayList<>(windowCount);
 				double prevProbability = 0;
-				for (final double probability : probabilities[wordIndex.index(sequenceWord.getWord())]) {
+				for (final double probability : probabilities[wordIndex.index(sequenceWord.getId())]) {
 					sequenceProbabilities.add(probability);
 					sequenceProbabilitiesChange.add(probability - prevProbability);
 					prevProbability = probability;
diff --git a/vipra-cmd/src/main/java/de/vipra/cmd/option/DeleteModelCommand.java b/vipra-cmd/src/main/java/de/vipra/cmd/option/DeleteModelCommand.java
index 8c771a0a0835c1e2fd10e10c631ea259aedf5f19..af9f91b3a7bb56fda75ff772459da7d79e3987db 100644
--- a/vipra-cmd/src/main/java/de/vipra/cmd/option/DeleteModelCommand.java
+++ b/vipra-cmd/src/main/java/de/vipra/cmd/option/DeleteModelCommand.java
@@ -3,10 +3,18 @@ package de.vipra.cmd.option;
 import java.io.File;
 import java.util.Arrays;
 
+import org.bson.types.ObjectId;
+
 import de.vipra.util.Config;
 import de.vipra.util.ConsoleUtils;
+import de.vipra.util.model.ArticleFull;
+import de.vipra.util.model.SequenceFull;
+import de.vipra.util.model.TopicFull;
 import de.vipra.util.model.TopicModel;
+import de.vipra.util.model.WindowFull;
+import de.vipra.util.model.WordFull;
 import de.vipra.util.service.MongoService;
+import de.vipra.util.service.Service.QueryBuilder;
 
 public class DeleteModelCommand implements Command {
 
@@ -20,6 +28,11 @@ public class DeleteModelCommand implements Command {
 	public void run() throws Exception {
 		final Config config = Config.getConfig();
 		final MongoService<TopicModel, String> dbTopicModels = MongoService.getDatabaseService(config, TopicModel.class);
+		final MongoService<ArticleFull, ObjectId> dbArticles = MongoService.getDatabaseService(config, ArticleFull.class);
+		final MongoService<TopicFull, ObjectId> dbTopics = MongoService.getDatabaseService(config, TopicFull.class);
+		final MongoService<WindowFull, Integer> dbWindows = MongoService.getDatabaseService(config, WindowFull.class);
+		final MongoService<SequenceFull, ObjectId> dbSequences = MongoService.getDatabaseService(config, SequenceFull.class);
+		final MongoService<WordFull, String> dbWords = MongoService.getDatabaseService(config, WordFull.class);
 
 		for (final String name : names) {
 			final File modelDir = new File(config.getDataDirectory(), name);
@@ -28,7 +41,17 @@ public class DeleteModelCommand implements Command {
 				ConsoleUtils.info("model deleted: " + name);
 			}
 		}
+
 		dbTopicModels.deleteMultiple(Arrays.asList(names));
+
+		for (final String name : names) {
+			final QueryBuilder builder = QueryBuilder.builder().criteria("topicModel", new TopicModel(name));
+			dbArticles.deleteMultiple(builder);
+			dbTopics.deleteMultiple(builder);
+			dbWindows.deleteMultiple(builder);
+			dbSequences.deleteMultiple(builder);
+			dbWords.deleteMultiple(builder);
+		}
 	}
 
 }
diff --git a/vipra-cmd/src/main/java/de/vipra/cmd/option/ImportCommand.java b/vipra-cmd/src/main/java/de/vipra/cmd/option/ImportCommand.java
index 17a18c6cccc48ef0dff6613698e000cc56022d8d..c6220dcc38b1440be8d4dd498fe3b7ddd6b64d88 100644
--- a/vipra-cmd/src/main/java/de/vipra/cmd/option/ImportCommand.java
+++ b/vipra-cmd/src/main/java/de/vipra/cmd/option/ImportCommand.java
@@ -17,6 +17,7 @@ import org.json.simple.parser.ParseException;
 
 import de.vipra.cmd.file.Filebase;
 import de.vipra.cmd.file.FilebaseException;
+import de.vipra.cmd.file.FilebaseWordIndex;
 import de.vipra.cmd.text.ProcessedText;
 import de.vipra.cmd.text.Processor;
 import de.vipra.cmd.text.ProcessorException;
@@ -37,6 +38,7 @@ import de.vipra.util.model.TextEntity;
 import de.vipra.util.model.TopicModel;
 import de.vipra.util.model.TopicModelConfig;
 import de.vipra.util.model.TopicModelFull;
+import de.vipra.util.model.WordFull;
 import de.vipra.util.service.MongoService;
 
 public class ImportCommand implements Command {
@@ -71,6 +73,7 @@ public class ImportCommand implements Command {
 	private Config config;
 	private MongoService<ArticleFull, ObjectId> dbArticles;
 	private MongoService<TopicModelFull, String> dbTopicModels;
+	private MongoService<WordFull, String> dbWords;
 	private TopicModelConfig modelConfig;
 	private SpotlightAnalyzer spotlightAnalyzer;
 	private Filebase filebase;
@@ -260,6 +263,19 @@ public class ImportCommand implements Command {
 		 */
 		filebase.sync();
 
+		/*
+		 * add new words
+		 */
+		final FilebaseWordIndex wordIndex = filebase.getWordIndex();
+		final List<WordFull> newWords = new ArrayList<>(wordIndex.getNewWords().size());
+		final TopicModel topicModelRef = new TopicModel(topicModel.getId());
+		for (final String word : wordIndex.getNewWords()) {
+			final WordFull newWord = new WordFull(word);
+			newWord.setTopicModel(topicModelRef);
+			newWords.add(newWord);
+		}
+		dbWords.createMultiple(newWords);
+
 		/*
 		 * run information
 		 */
@@ -271,6 +287,7 @@ public class ImportCommand implements Command {
 		config = Config.getConfig();
 		dbArticles = MongoService.getDatabaseService(config, ArticleFull.class);
 		dbTopicModels = MongoService.getDatabaseService(config, TopicModelFull.class);
+		dbWords = MongoService.getDatabaseService(config, WordFull.class);
 		processor = new Processor();
 		for (final TopicModelConfig modelConfig : config.getTopicModelConfigs(models)) {
 			importForModel(modelConfig);
diff --git a/vipra-ui/app/html/directives/word-link.html b/vipra-ui/app/html/directives/word-link.html
index 0c2dff7ccf68eafa959c3e130c27b1e41e741286..73cc32b89ac34457edabe71bfba083099e2b9c45 100644
--- a/vipra-ui/app/html/directives/word-link.html
+++ b/vipra-ui/app/html/directives/word-link.html
@@ -1,4 +1,4 @@
 <span>
   <word-menu word="word" />
-  <span ng-bind="word.word"></span>
+  <a ui-sref="words.show({id: word.id})" ng-bind="word.id"></a>
 </span>
\ No newline at end of file
diff --git a/vipra-ui/app/html/directives/word-menu.html b/vipra-ui/app/html/directives/word-menu.html
index fe6a7ef3940ebc348eded14b24a8384d20429333..103531b1bdf35424d72d8e2f229ec0b716aac5f8 100644
--- a/vipra-ui/app/html/directives/word-menu.html
+++ b/vipra-ui/app/html/directives/word-menu.html
@@ -3,7 +3,7 @@
     <i class="fa fa-caret-down"></i>
   </a>
   <ul class="dropdown-menu" ng-class="{'dropdown-menu-right':dropdownRight}">
-    <li><a ui-sref="words.topics({word:word.word})">Topics</a></li>
-    <li><a ui-sref="words.articles({word:word.word})">Articles</a></li>
+    <li><a ui-sref="words.show.topics({id:word.id})">Topics</a></li>
+    <li><a ui-sref="words.show.articles({id:word.id})">Articles</a></li>
   </ul>
 </div>
\ No newline at end of file
diff --git a/vipra-ui/app/html/topics/show.html b/vipra-ui/app/html/topics/show.html
index 387f7bda18f177dba20300c994944cfe6e64aeae..5c74517925bcaa8a75c9497a4d49374503e9157e 100644
--- a/vipra-ui/app/html/topics/show.html
+++ b/vipra-ui/app/html/topics/show.html
@@ -90,8 +90,8 @@
                 <ul class="list-unstyled">
                   <li ng-repeat="word in topic.words">
                     <div class="checkbox checkbox-condensed" ng-class="{selected:word.selected}">
-                      <input tabindex="0" type="checkbox" ng-model="word.selected" ng-attr-id="{{::word.word}}" ng-change="redrawWordEvolutionChart()">
-                      <label class="check" ng-attr-for="{{::word.word}}">
+                      <input tabindex="0" type="checkbox" ng-model="word.selected" ng-attr-id="{{::word.id}}" ng-change="redrawWordEvolutionChart()">
+                      <label class="check" ng-attr-for="{{::word.id}}">
                         <word-link word="word" />
                       </label>
                     </div>
@@ -123,8 +123,7 @@
             <tbody>
               <tr ng-repeat="word in sequence.words | orderBy:topicsShowModels.seqSortWords">
                 <td>
-                  <word-menu word="word"/>
-                  <span ng-bind="::word.word"></span>
+                  <word-link word="word" />
                 </td>
                 <td ng-bind="word.probability.toFixed(4)"></td>
               </tr>
diff --git a/vipra-ui/app/html/words/articles.html b/vipra-ui/app/html/words/articles.html
index 03dce56951193bb886e94512579c39a675f4f5e5..3674b93e2fb6e7888564e4ca49c9988f4feed8b0 100644
--- a/vipra-ui/app/html/words/articles.html
+++ b/vipra-ui/app/html/words/articles.html
@@ -1,4 +1,4 @@
-<div class="container" ng-cloak ng-hide="!rootModels.topicModel || state.name !== 'words.articles'">
+<div class="container" ng-cloak ng-hide="!rootModels.topicModel || state.name !== 'words.show.articles'">
   <div class="row">
     <div class="col-md-12">
       <div class="page-header">
diff --git a/vipra-ui/app/html/words/index.html b/vipra-ui/app/html/words/index.html
new file mode 100644
index 0000000000000000000000000000000000000000..16a03a7f1a5257919683c26f594ec07c999660a3
--- /dev/null
+++ b/vipra-ui/app/html/words/index.html
@@ -0,0 +1,42 @@
+<div class="container" ng-cloak ng-hide="!rootModels.topicModel || state.name !== 'words'">
+  <div class="row">
+    <div class="col-md-12 text-center">
+      <pagination total="wordsTotal" page="wordsIndexModels.page" limit="wordsIndexModels.limit" />
+    </div>
+  </div>
+  <div class="row">
+    <div class="col-md-12">
+      <div class="panel panel-default">
+        <div class="panel-heading">
+          Found
+          <ng-pluralize count="wordsTotal||0" when="{0:'no words',1:'1 word',other:'{} words'}"></ng-pluralize> in the database.
+          <span ng-show="wordsTotal">
+          Sort by
+          <ol class="nya-bs-select nya-bs-condensed" ng-model="wordsIndexModels.sortkey">
+            <li value="id" class="nya-bs-option"><a>Word</a></li>
+          </ol>
+          <sort-dir ng-model="wordsIndexModels.sortdir" />
+        </span>
+        </div>
+        <table class="table table-hover table-condensed">
+          <tbody>
+            <tr ng-repeat="word in words">
+              <td>
+              	<word-link word="word" />
+              </td>
+            </tr>
+          </tbody>
+        </table>
+        <div class="panel-footer">
+          Page <span ng-bind="wordsIndexModels.page||1"></span> of <span ng-bind="maxPage||1"></span>
+        </div>
+      </div>
+    </div>
+  </div>
+  <div class="row">
+    <div class="col-md-12 text-center">
+      <pagination total="wordsTotal" page="wordsIndexModels.page" limit="wordsIndexModels.limit" />
+    </div>
+  </div>
+</div>
+<div ng-cloak ui-view></div>
diff --git a/vipra-ui/app/html/words/show.html b/vipra-ui/app/html/words/show.html
new file mode 100644
index 0000000000000000000000000000000000000000..515f6e9c2fecc07d0d800cdd89681a47a92ce6e0
--- /dev/null
+++ b/vipra-ui/app/html/words/show.html
@@ -0,0 +1,4 @@
+<div class="container" ng-cloak ng-hide="!rootModels.topicModel || state.name !== 'words.show'">
+	<h1 ng-bind="word.id"></h1>
+</div>
+<div ng-cloak ui-view></div>
diff --git a/vipra-ui/app/html/words/topics.html b/vipra-ui/app/html/words/topics.html
index 46a20f18289a83eeeaf1dae8f614fa67aac1f987..f96c969688c897993e79b626cf2ed51319a43aea 100644
--- a/vipra-ui/app/html/words/topics.html
+++ b/vipra-ui/app/html/words/topics.html
@@ -1,4 +1,4 @@
-<div class="container" ng-cloak ng-hide="!rootModels.topicModel || state.name !== 'words.topics'">
+<div class="container" ng-cloak ng-hide="!rootModels.topicModel || state.name !== 'words.show.topics'">
   <div class="row">
     <div class="col-md-12">
       <div class="page-header">
diff --git a/vipra-ui/app/index.html b/vipra-ui/app/index.html
index fb7e6846ca7daaa0f0dacfd6d6abe7e6d21956a8..ddb769d732a3e0a1fbc3b308571acac77027fd50 100644
--- a/vipra-ui/app/index.html
+++ b/vipra-ui/app/index.html
@@ -64,6 +64,9 @@
           <li ui-sref-active="active">
             <a tabindex="0" ui-sref="topics"><span class="mnemonic">T</span>opics</a>
           </li>
+          <li ui-sref-active="active">
+            <a tabindex="0" ui-sref="words"><span class="mnemonic">W</span>ords</a>
+          </li>
         </ul>
         <form class="navbar-form navbar-left" role="search" ng-hide="state.name === 'index'">
           <div class="form-group has-feedback">
diff --git a/vipra-ui/app/js/app.js b/vipra-ui/app/js/app.js
index 94aefbb11a67505e3cabaf212b6a8e24960174e5..64b34a2d4b85c76a288ad9f635509bc89cfe524c 100644
--- a/vipra-ui/app/js/app.js
+++ b/vipra-ui/app/js/app.js
@@ -91,18 +91,24 @@
       // states: words
 
       $stateProvider.state('words', {
-        abstract: true,
-        url: '/words/:word',
-        template: '<ui-view/>'
+        url: '/words?p',
+        templateUrl: 'html/words/index.html',
+        controller: 'WordsIndexController'
       });
 
-      $stateProvider.state('words.topics', {
+      $stateProvider.state('words.show', {
+        url: '/:id',
+        templateUrl: 'html/words/show.html',
+        controller: 'WordsShowController'
+      });
+
+      $stateProvider.state('words.show.topics', {
         url: '/topics',
         templateUrl: 'html/words/topics.html',
         controller: 'WordsTopicsController'
       });
 
-      $stateProvider.state('words.articles', {
+      $stateProvider.state('words.show.articles', {
         url: '/articles',
         templateUrl: 'html/words/articles.html',
         controller: 'WordsArticlesController'
diff --git a/vipra-ui/app/js/controllers.js b/vipra-ui/app/js/controllers.js
index d466d9afb7c06207c25c94eda0d2aaac62b87d27..92b9c03c8acd3003408ff37b0829dfc52643d8e4 100644
--- a/vipra-ui/app/js/controllers.js
+++ b/vipra-ui/app/js/controllers.js
@@ -9,8 +9,8 @@
 
   var app = angular.module('vipra.controllers', []);
 
-  app.controller('RootController', ['$scope', '$state', '$location', '$window', 'hotkeys', 'TopicModelFactory',
-    function($scope, $state, $location, $window, hotkeys, TopicModelFactory) {
+  app.controller('RootController', ['$scope', '$state', '$window', 'hotkeys', 'TopicModelFactory',
+    function($scope, $state, $window, hotkeys, TopicModelFactory) {
 
       $scope.rootModels = {
         topicModel: null,
@@ -94,6 +94,15 @@
         }
       });
 
+      hotkeys.add({
+        combo: 'w',
+        description: 'Go to words',
+        callback: function() {
+          if ($scope.rootModels.topicModel && $state.current.name !== 'words')
+            $state.transitionTo('words');
+        }
+      });
+
       hotkeys.add({
         combo: 'm',
         description: 'Choose a topic model',
@@ -803,7 +812,7 @@
             probs.push([new Date($scope.topic.sequences[j].window.startDate).getTime(), prob]);
           }
           evolutions.push({
-            name: word.word,
+            name: word.id,
             data: probs
           });
         }
@@ -904,13 +913,13 @@
   /**
    * Topic Show Articles route
    */
-  app.controller('TopicsArticlesController', ['$scope', '$stateParams', '$location', 'TopicFactory',
-    function($scope, $stateParams, $location, TopicFactory) {
+  app.controller('TopicsArticlesController', ['$scope', '$stateParams', 'TopicFactory',
+    function($scope, $stateParams, TopicFactory) {
 
       $scope.topicsArticlesModels = {
         sortkey: 'title',
         sortdir: true,
-        page: Math.max($location.search().page || 1, 1),
+        page: 1,
         limit: 100
       };
 
@@ -934,10 +943,48 @@
    * Word Controllers
    ****************************************************************************/
 
+  app.controller('WordsIndexController', ['$scope', '$state', 'WordFactory',
+    function($scope, $state, WordFactory) {
+
+      // page was reloaded, choose topic model
+      if (!$scope.rootModels.topicModel && $state.current.name === 'words')
+        $scope.chooseTopicModel();
+
+      $scope.wordsIndexModels = {
+        sortkey: 'id',
+        sortdir: true,
+        page: 1,
+        limit: 100
+      };
+
+      $scope.$watchGroup(['wordsIndexModels.page', 'wordsIndexModels.sortkey', 'wordsIndexModels.sortdir', 'rootModels.topicModel'], function() {
+        if (!$scope.rootModels.topicModel) return;
+
+        WordFactory.query({
+          topicModel: $scope.rootModels.topicModel.id,
+          skip: ($scope.wordsIndexModels.page - 1) * $scope.wordsIndexModels.limit,
+          limit: $scope.wordsIndexModels.limit,
+          sort: ($scope.wordsIndexModels.sortdir ? '' : '-') + $scope.wordsIndexModels.sortkey
+        }, function(data, headers) {
+          $scope.words = data;
+          $scope.wordsTotal = headers("V-Total");
+          $scope.maxPage = Math.ceil($scope.wordsTotal / $scope.wordsIndexModels.limit);
+        });
+      });
+
+    }
+  ]);
+
+  app.controller('WordsShowController', ['$scope',
+    function($scope) {
+
+    }
+  ]);
+
   app.controller('WordsTopicsController', ['$scope', '$state', '$stateParams', 'TopicFactory',
     function($scope, $state, $stateParams, TopicFactory) {
 
-      $scope.word = $stateParams.word;
+      $scope.word = $stateParams.id;
 
       // page was reloaded, choose topic model
       if (!$scope.rootModels.topicModel && $state.current.name === 'words.topics')
@@ -972,7 +1019,7 @@
   app.controller('WordsArticlesController', ['$scope', '$state', '$stateParams', 'ArticleFactory',
     function($scope, $state, $stateParams, ArticleFactory) {
 
-      $scope.word = $stateParams.word;
+      $scope.word = $stateParams.id;
 
       // page was reloaded, choose topic model
       if (!$scope.rootModels.topicModel && $state.current.name === 'words.articles')
diff --git a/vipra-ui/app/js/factories.js b/vipra-ui/app/js/factories.js
index 31f9b64b4016ec220007ca70220b2990cc375541..b331235d3af51ceed292382395325e7a49d0eb7d 100644
--- a/vipra-ui/app/js/factories.js
+++ b/vipra-ui/app/js/factories.js
@@ -72,4 +72,8 @@
     return $myResource(Vipra.config.restUrl + '/topicmodels/:id');
   }]);
 
+  app.factory('WordFactory', ['$myResource', function($myResource) {
+    return $myResource(Vipra.config.restUrl + '/words/:id');
+  }]);
+
 })();
\ No newline at end of file
diff --git a/vipra-util/src/main/java/de/vipra/util/model/ArticleFull.java b/vipra-util/src/main/java/de/vipra/util/model/ArticleFull.java
index 96c0407fb9722640778574c0fb2ab6e39a9c2e1d..3feb126a7662f10e97a0b0cff905e01ad2a992cc 100644
--- a/vipra-util/src/main/java/de/vipra/util/model/ArticleFull.java
+++ b/vipra-util/src/main/java/de/vipra/util/model/ArticleFull.java
@@ -175,7 +175,7 @@ public class ArticleFull implements Model<ObjectId>, Serializable {
 
 	public void setTopics(final List<TopicShare> topics) {
 		this.topics = topics;
-		this.topicsCount = topics == null ? 0 : topics.size();
+		topicsCount = topics == null ? 0 : topics.size();
 	}
 
 	public int getTopicsCount() {
diff --git a/vipra-util/src/main/java/de/vipra/util/model/ArticleWord.java b/vipra-util/src/main/java/de/vipra/util/model/ArticleWord.java
index f0fc0cab9160b32f79601e622d08e5566b01d253..7aa0f7becc05544b61d6a0411e7e54f1807c51d6 100644
--- a/vipra-util/src/main/java/de/vipra/util/model/ArticleWord.java
+++ b/vipra-util/src/main/java/de/vipra/util/model/ArticleWord.java
@@ -11,23 +11,23 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
 @Embedded
 public class ArticleWord implements Comparable<ArticleWord>, Serializable {
 
-	private String word;
+	private String id;
 
 	private Integer count;
 
 	public ArticleWord() {}
 
-	public ArticleWord(final String word, final int count) {
-		this.word = word;
+	public ArticleWord(final String id, final int count) {
+		this.id = id;
 		this.count = count;
 	}
 
-	public String getWord() {
-		return word;
+	public String getId() {
+		return id;
 	}
 
-	public void setWord(final String word) {
-		this.word = word;
+	public void setId(final String id) {
+		this.id = id;
 	}
 
 	public Integer getCount() {
@@ -45,7 +45,7 @@ public class ArticleWord implements Comparable<ArticleWord>, Serializable {
 
 	@Override
 	public String toString() {
-		return "ArticleWord [word=" + word + ", count=" + count + "]";
+		return "ArticleWord [id=" + id + ", count=" + count + "]";
 	}
 
 }
diff --git a/vipra-util/src/main/java/de/vipra/util/model/SequenceWord.java b/vipra-util/src/main/java/de/vipra/util/model/SequenceWord.java
index 7499f8b8da606ff71dea08bd1274941d90638916..3e1637741e1c95ff6d2b1f2f914e5f319f3a7186 100644
--- a/vipra-util/src/main/java/de/vipra/util/model/SequenceWord.java
+++ b/vipra-util/src/main/java/de/vipra/util/model/SequenceWord.java
@@ -11,23 +11,23 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
 @Embedded
 public class SequenceWord implements Comparable<SequenceWord>, Serializable {
 
-	private String word;
+	private String id;
 
 	private Double probability;
 
 	public SequenceWord() {}
 
 	public SequenceWord(final String word, final Double probability) {
-		this.word = word;
+		id = word;
 		this.probability = probability;
 	}
 
-	public String getWord() {
-		return word;
+	public String getId() {
+		return id;
 	}
 
-	public void setWord(final String word) {
-		this.word = word;
+	public void setId(final String id) {
+		this.id = id;
 	}
 
 	public Double getProbability() {
@@ -45,14 +45,14 @@ public class SequenceWord implements Comparable<SequenceWord>, Serializable {
 
 	@Override
 	public String toString() {
-		return "SequenceWord [word=" + word + ", probability=" + probability + "]";
+		return "SequenceWord [id=" + id + ", probability=" + probability + "]";
 	}
 
 	@Override
 	public int hashCode() {
 		final int prime = 31;
 		int result = 1;
-		result = prime * result + ((word == null) ? 0 : word.hashCode());
+		result = prime * result + ((id == null) ? 0 : id.hashCode());
 		return result;
 	}
 
@@ -65,10 +65,10 @@ public class SequenceWord implements Comparable<SequenceWord>, Serializable {
 		if (getClass() != obj.getClass())
 			return false;
 		final SequenceWord other = (SequenceWord) obj;
-		if (word == null) {
-			if (other.word != null)
+		if (id == null) {
+			if (other.id != null)
 				return false;
-		} else if (!word.equals(other.word))
+		} else if (!id.equals(other.id))
 			return false;
 		return true;
 	}
diff --git a/vipra-util/src/main/java/de/vipra/util/model/TopicFull.java b/vipra-util/src/main/java/de/vipra/util/model/TopicFull.java
index c687c3b228bf545559c00c45006f3ca11ea6bd10..337e3b88c5265f97dbd237fdd43218e206e1ea29 100644
--- a/vipra-util/src/main/java/de/vipra/util/model/TopicFull.java
+++ b/vipra-util/src/main/java/de/vipra/util/model/TopicFull.java
@@ -154,7 +154,7 @@ public class TopicFull implements Model<ObjectId>, Serializable {
 		return articlesCount;
 	}
 
-	public void setArticlesCount(int articlesCount) {
+	public void setArticlesCount(final int articlesCount) {
 		this.articlesCount = articlesCount;
 	}
 
@@ -187,7 +187,7 @@ public class TopicFull implements Model<ObjectId>, Serializable {
 			final int size = Math.min(wordsNum, words.size());
 			final List<String> topWords = new ArrayList<>(size);
 			for (int i = 0; i < size; i++) {
-				topWords.add(words.get(i).getWord());
+				topWords.add(words.get(i).getId());
 			}
 			name = StringUtils.join(topWords);
 		}
diff --git a/vipra-util/src/main/java/de/vipra/util/model/TopicModelConfig.java b/vipra-util/src/main/java/de/vipra/util/model/TopicModelConfig.java
index 58dc063a49b2f7ed0f7f584b91228c2bfbae8714..e0dee92240bc839ad886df3563629761a8cca3b4 100644
--- a/vipra-util/src/main/java/de/vipra/util/model/TopicModelConfig.java
+++ b/vipra-util/src/main/java/de/vipra/util/model/TopicModelConfig.java
@@ -166,7 +166,7 @@ public class TopicModelConfig implements Serializable {
 		return minTopicShare;
 	}
 
-	public void setMinTopicShare(double minTopicShare) {
+	public void setMinTopicShare(final double minTopicShare) {
 		this.minTopicShare = minTopicShare;
 	}
 
diff --git a/vipra-util/src/main/java/de/vipra/util/model/TopicModelFull.java b/vipra-util/src/main/java/de/vipra/util/model/TopicModelFull.java
index 308336f42f465f2513065ae56635e187bb1f7017..a12ee4fede85b97f16863a448a06ad9b8af6286b 100644
--- a/vipra-util/src/main/java/de/vipra/util/model/TopicModelFull.java
+++ b/vipra-util/src/main/java/de/vipra/util/model/TopicModelFull.java
@@ -98,7 +98,7 @@ public class TopicModelFull implements Model<String>, Comparable<TopicModelFull>
 		return lastGenerated;
 	}
 
-	public void setLastGenerated(Date lastGenerated) {
+	public void setLastGenerated(final Date lastGenerated) {
 		this.lastGenerated = lastGenerated;
 	}
 
diff --git a/vipra-util/src/main/java/de/vipra/util/model/TopicWord.java b/vipra-util/src/main/java/de/vipra/util/model/TopicWord.java
index 74bbe6cf814e31d8bc606ab8c363268bad171741..6fa9aaf2c12cb57278347ce9867d0b07de655bf6 100644
--- a/vipra-util/src/main/java/de/vipra/util/model/TopicWord.java
+++ b/vipra-util/src/main/java/de/vipra/util/model/TopicWord.java
@@ -9,18 +9,18 @@ import org.mongodb.morphia.annotations.Embedded;
 @Embedded
 public class TopicWord implements Comparable<TopicWord>, Serializable {
 
-	private String word;
+	private String id;
 
 	private List<Double> sequenceProbabilities;
 
 	private List<Double> sequenceProbabilitiesChange;
 
-	public String getWord() {
-		return word;
+	public String getId() {
+		return id;
 	}
 
-	public void setWord(final String word) {
-		this.word = word;
+	public void setId(final String id) {
+		this.id = id;
 	}
 
 	public List<Double> getSequenceProbabilities() {
@@ -35,13 +35,13 @@ public class TopicWord implements Comparable<TopicWord>, Serializable {
 		return sequenceProbabilitiesChange;
 	}
 
-	public void setSequenceProbabilitiesChange(List<Double> sequenceProbabilitiesChange) {
+	public void setSequenceProbabilitiesChange(final List<Double> sequenceProbabilitiesChange) {
 		this.sequenceProbabilitiesChange = sequenceProbabilitiesChange;
 	}
 
 	@Override
 	public int compareTo(final TopicWord o) {
-		return word.compareTo(o.getWord());
+		return id.compareTo(o.getId());
 	}
 
 }
diff --git a/vipra-util/src/main/java/de/vipra/util/model/WordFull.java b/vipra-util/src/main/java/de/vipra/util/model/WordFull.java
new file mode 100644
index 0000000000000000000000000000000000000000..504deeef1dd27080d49d8e03b69f0fca497bbbf1
--- /dev/null
+++ b/vipra-util/src/main/java/de/vipra/util/model/WordFull.java
@@ -0,0 +1,51 @@
+package de.vipra.util.model;
+
+import java.io.Serializable;
+
+import org.mongodb.morphia.annotations.Entity;
+import org.mongodb.morphia.annotations.Id;
+import org.mongodb.morphia.annotations.Reference;
+
+import de.vipra.util.an.QueryIgnore;
+
+@SuppressWarnings("serial")
+@Entity(value = "words", noClassnameStored = true)
+public class WordFull implements Model<String>, Comparable<WordFull>, Serializable {
+
+	@Id
+	private String id;
+
+	@Reference
+	@QueryIgnore(multi = true)
+	private TopicModel topicModel;
+
+	public WordFull() {}
+
+	public WordFull(final String word) {
+		id = word;
+	}
+
+	@Override
+	public String getId() {
+		return id;
+	}
+
+	@Override
+	public void setId(final String id) {
+		this.id = id;
+	}
+
+	public TopicModel getTopicModel() {
+		return topicModel;
+	}
+
+	public void setTopicModel(final TopicModel topicModel) {
+		this.topicModel = topicModel;
+	}
+
+	@Override
+	public int compareTo(final WordFull o) {
+		return id.compareTo(o.getId());
+	}
+
+}