    :extractor    {:row {}}
    :transformers [{:csv {:separator "\t"}}
                   {:vertex {:class "MetadataValue"}}
+                  {:field {:fieldName "value" :expression "tid"}}
+                  {:field {:fieldName "tid" :operation "remove"}}
                   {:edge
-                   {:class                "HasMetadataValue"
+                   {:class                "InCategory"
                     :lookup               "MetadataCategory.corpus_cat"
                     :joinValue            "###CORPUS###_tid"
-                    :direction            "in"
                     :unresolvedLinkAction "ERROR"}}]
    :loader       {:orientdb
                   {:dbURL               "remote:localhost/Glossa"

                   :useLightweightEdges true
                   :classes             [{:name "MetadataCategory" :extends "V"}
                                         {:name "MetadataValue" :extends "V"}]
                   :indexes             [{:class "MetadataCategory" :fields ["corpus_cat:string"] :type "UNIQUE"}]}}})

(defn- create-non-tids-config! [config-path tsv-path]
  (spit config-path (-> non-tids-template
                        (cheshire/generate-string {:pretty true})
                        (str/replace "###TSV-PATH###" tsv-path))))

(defn- create-non-tids-tsv! [corpus tsv-path]
  (let [orig-tsv-path (-> (str "data/metadata_values/" corpus ".tsv") io/resource .getPath)]
    (with-open [orig-tsv-file (io/reader orig-tsv-path)
                tsv-file      (io/writer tsv-path)]
      (let [[headers & rows] (utils/read-csv orig-tsv-file)
            [tid-header & other-headers] headers
            non-blank? (complement str/blank?)]
        (assert (= "tid" tid-header)
                (str "Format error: Expected first line to contain column headers "
                     "with 'tid' (text ID) as the first header."))
        (utils/write-csv tsv-file (->> rows
                                       (apply map list)     ; Convert rows to columns
                                       rest                 ; Skip 'tid' column
                                       ;; Startpos and endpos are not metadata values; for the
                                       ;; other columns, construct a [header column] vector
                                       (keep-indexed (fn [index col]
                                                       (let [header (get (vec other-headers) index)]
                                                         (when-not (get #{"startpos" "endpos"} header)
                                                           [header col]))))
                                       (mapcat (fn [[header col-vals]]
                                                 (map (fn [val] [(str corpus "_" header) val]) col-vals)))
                                       set
                                       (filter #(non-blank? (second %)))
                                       (cons ["corpus_cat" "value"])))))))

(defn- create-tid-tsv! [corpus tsv-path]
  (let [orig-tsv-path (-> (str "data/metadata_values/" corpus ".tsv") io/resource .getPath)]

   :source       {:file {:path "###TSV-PATH###"}}
   :extractor    {:row {}}
   :transformers [{:csv {:separator "\t"}}
                  {:vertex {:class "MetadataValue"}}
                  {:edge
                   {:class                "InCategory"
                    :lookup               "MetadataCategory.corpus_cat"
                    :joinFieldName        "corpus_cat"
                    :unresolvedLinkAction "ERROR"}}]
   :loader       {:orientdb
                  {:dbURL               "remote:localhost/Glossa"
