      (doall (map #(load-category-resources %) categories)))))
 
 
+(defn- build-category-words
+  [{:keys [id words] :as category}]
+  (trace-message "Building words for category '" id "'")
+  (assoc category :words
+    (map-indexed
+     (fn [i w] {:no i
+                :text w
+                :lexical-form w
+                :confidence 1})
+     words)))
+
+
+(defn- build-category-index
+  [job category]
+  (trace-message "Building index for category '" (:id category) "'")
+  (let [index (proc/category-index category :predicate (word-predicate job))]
+    (assoc category :index index)))
+
+
 (defn analyze-categories
   "Analyzes the categories and generates the index structures."
   [job]
-  (println "TODO: tasks/analyze-categories")
-  job)
+  (trace-block
+   "Analyzing categories"
+   (let [job* (update-in
+               job [:categories]
+               (fn [categories]
+                 (vec ((map-fn)
+                       (fn [category]
+                         (build-category-index
+                          job
+                          (build-category-words category)))
+                       categories))))]
+     job*)))
+
+
+;; #### Speech Recognition Results
 
 
 (defn- load-speech-recognition-result


;; ### Preprocessing, Analysis

(defn- load-category-resource
  "Loads a single resource for a category."
  [{:keys [id]} {:keys [type url] :as resource}]

      :word-count (count (proc/words results))
      :confidence (mean (map :confidence results))
      :duration duration)))


(defn- build-video-index
