diff --git a/README.md b/README.md index 9ce6c4f0..f4359e31 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,10 @@ to be composed with other services. It is part of my PatientCare v4 development; previous versions have been operational within NHS Wales since 2007. +You can have a working terminology server running by typing only a few lines at a terminal. There's no need +for any special hardware, or any special dependencies such as setting up your own elasticsearch or solr cluster. +You just need a filesystem! Many other tools take hours to import the SNOMED data; you'll be finished in less than +10 minutes! ### A. How to download and build a terminology service @@ -275,9 +279,10 @@ or is a disease affecting the central nervous system without further server round-trips. Each relationship also includes the transitive closure tables for that relationship, making it easier to execute logical inference. Note how the list of descriptions includes a convenient -`acceptable-in` and `preferred-in` so you can easily display the preferred -term for your locale. - +`acceptableIn` and `preferredIn` so you can easily display the preferred +term for your locale. If you provide an Accept-Language header, then +you will also get a preferredDescription that is the best choice for those +language preferences given what is installed. ```shell HTTP/1.1 200 OK @@ -294,7 +299,7 @@ Date: Mon, 08 Mar 2021 22:01:13 GMT }, "descriptions": [ { - "acceptable-in": [], + "acceptableIn": [], "active": true, "caseSignificanceId": 900000000000448009, "conceptId": 24700007, @@ -302,7 +307,7 @@ Date: Mon, 08 Mar 2021 22:01:13 GMT "id": 41398015, "languageCode": "en", "moduleId": 900000000000207008, - "preferred-in": [ + "preferredIn": [ 900000000000509007, 900000000000508004, 999001261000000100 @@ -316,7 +321,7 @@ Date: Mon, 08 Mar 2021 22:01:13 GMT "typeId": 900000000000013009 }, { - "acceptable-in": [], + "acceptableIn": [], "active": false, "caseSignificanceId": 900000000000020002, "conceptId": 24700007, @@ -324,13 +329,13 @@ Date: Mon, 08 Mar 2021 22:01:13 GMT "id": 41399011, "languageCode": "en", "moduleId": 900000000000207008, - "preferred-in": [], + "preferredIn": [], "refsets": [], "term": "Multiple sclerosis, NOS", "typeId": 900000000000013009 }, { - "acceptable-in": [], + "acceptableIn": [], "active": false, "caseSignificanceId": 900000000000020002, "conceptId": 24700007, @@ -338,13 +343,13 @@ Date: Mon, 08 Mar 2021 22:01:13 GMT "id": 41400016, "languageCode": "en", "moduleId": 900000000000207008, - "preferred-in": [], + "preferredIn": [], "refsets": [], "term": "Generalized multiple sclerosis", "typeId": 900000000000013009 }, { - "acceptable-in": [], + "acceptableIn": [], "active": false, "caseSignificanceId": 900000000000020002, "conceptId": 24700007, @@ -352,13 +357,13 @@ Date: Mon, 08 Mar 2021 22:01:13 GMT "id": 481990016, "languageCode": "en", "moduleId": 900000000000207008, - "preferred-in": [], + "preferredIn": [], "refsets": [], "term": "Generalised multiple sclerosis", "typeId": 900000000000013009 }, { - "acceptable-in": [], + "acceptableIn": [], "active": true, "caseSignificanceId": 900000000000448009, "conceptId": 24700007, @@ -366,7 +371,7 @@ Date: Mon, 08 Mar 2021 22:01:13 GMT "id": 754365011, "languageCode": "en", "moduleId": 900000000000207008, - "preferred-in": [ + "preferredIn": [ 900000000000509007, 900000000000508004, 999001261000000100 @@ -380,7 +385,7 @@ Date: Mon, 08 Mar 2021 22:01:13 GMT "typeId": 900000000000003001 }, { - "acceptable-in": [ + "acceptableIn": [ 900000000000509007, 900000000000508004, 999001261000000100 @@ -392,7 +397,7 @@ Date: Mon, 08 Mar 2021 22:01:13 GMT "id": 1223979019, "languageCode": "en", "moduleId": 900000000000207008, - "preferred-in": [], + "preferredIn": [], "refsets": [ 900000000000509007, 900000000000508004, @@ -402,7 +407,7 @@ Date: Mon, 08 Mar 2021 22:01:13 GMT "typeId": 900000000000013009 }, { - "acceptable-in": [ + "acceptableIn": [ 900000000000509007, 900000000000508004, 999001261000000100 @@ -414,7 +419,7 @@ Date: Mon, 08 Mar 2021 22:01:13 GMT "id": 1223980016, "languageCode": "en", "moduleId": 900000000000207008, - "preferred-in": [], + "preferredIn": [], "refsets": [ 900000000000509007, 900000000000508004, @@ -424,7 +429,7 @@ Date: Mon, 08 Mar 2021 22:01:13 GMT "typeId": 900000000000013009 }, { - "acceptable-in": [ + "acceptableIn": [ 900000000000509007, 900000000000508004, 999001261000000100 @@ -436,7 +441,7 @@ Date: Mon, 08 Mar 2021 22:01:13 GMT "id": 1223981017, "languageCode": "en", "moduleId": 900000000000207008, - "preferred-in": [], + "preferredIn": [], "refsets": [ 900000000000509007, 900000000000508004, @@ -446,7 +451,7 @@ Date: Mon, 08 Mar 2021 22:01:13 GMT "typeId": 900000000000013009 } ], - "direct-parent-relationships": { + "directParentRelationships": { "116676008": [ 409774005, 32693004 @@ -463,7 +468,7 @@ Date: Mon, 08 Mar 2021 22:01:13 GMT 769247005 ] }, - "parent-relationships": { + "parentRelationships": { "116676008": [ 138875005, 107669003, diff --git a/src/com/eldrix/hermes/impl/search.clj b/src/com/eldrix/hermes/impl/search.clj index fb23c938..ad95455a 100644 --- a/src/com/eldrix/hermes/impl/search.clj +++ b/src/com/eldrix/hermes/impl/search.clj @@ -82,18 +82,18 @@ (.add (StoredField. "concept-id" ^long (get-in ed [:concept :id]))) (.add (LongPoint. "concept-id" (long-array [(get-in ed [:concept :id])]))) (.add (StoredField. "preferred-term" (str (:preferred-term ed)))))] - (doseq [[rel concept-ids] (get-in ed [:concept :parent-relationships])] + (doseq [[rel concept-ids] (get-in ed [:concept :parentRelationships])] (let [relationship (str rel)] ;; encode parent relationships as relationship type concept id (doseq [concept-id concept-ids] ;; and use a transitive closure table for the defining relationship (.add doc (LongPoint. relationship (long-array [concept-id])))))) - (doseq [[rel concept-ids] (get-in ed [:concept :direct-parent-relationships])] + (doseq [[rel concept-ids] (get-in ed [:concept :directParentRelationships])] (.add doc (IntPoint. (str "c" rel) (int-array [(count concept-ids)]))) ;; encode count of direct parent relationships by type as ("c" + relationship type = count) (let [relationship (str "d" rel)] ;; encode direct parent relationships as ("d" + relationship type = concept id) (doseq [concept-id concept-ids] (.add doc (LongPoint. relationship (long-array [concept-id])))))) - (doseq [preferred-in (:preferred-in ed)] + (doseq [preferred-in (:preferredIn ed)] (.add doc (LongPoint. "preferred-in" (long-array [preferred-in])))) - (doseq [acceptable-in (:acceptable-in ed)] + (doseq [acceptable-in (:acceptableIn ed)] (.add doc (LongPoint. "acceptable-in" (long-array [acceptable-in])))) (doseq [refset (get-in ed [:concept :refsets])] (.add doc (LongPoint. "concept-refsets" (long-array [refset])))) diff --git a/src/com/eldrix/hermes/impl/store.clj b/src/com/eldrix/hermes/impl/store.clj index 4551b915..a7ce2159 100644 --- a/src/com/eldrix/hermes/impl/store.clj +++ b/src/com/eldrix/hermes/impl/store.clj @@ -522,8 +522,8 @@ "Get the refsets and language applicability for a description. Returns a map containing: - refsets : a set of refsets to which this description is a member - - preferred-in : refsets for which this description is preferred - - acceptable-in : refsets for which this description is acceptable. + - preferredIn : refsets for which this description is preferred + - acceptableIn : refsets for which this description is acceptable. Example: (map #(merge % (get-description-refsets store (:id %))) @@ -534,8 +534,8 @@ preferred-in (into #{} (map :refsetId (filter #(= snomed/Preferred (:acceptabilityId %)) refset-items))) acceptable-in (into #{} (map :refsetId (filter #(= snomed/Acceptable (:acceptabilityId %)) refset-items)))] {:refsets refsets - :preferred-in preferred-in - :acceptable-in acceptable-in})) + :preferredIn preferred-in + :acceptableIn acceptable-in})) (defn get-preferred-description "Return the preferred description for the concept specified as defined by @@ -636,7 +636,7 @@ (contains? (get-all-parents store (:id concept)) parent-id)) (defmethod is-a? ExtendedConcept [_ extended-concept parent-id] - (contains? (get-in extended-concept [:parent-relationships snomed/IsA]) parent-id)) + (contains? (get-in extended-concept [:parentRelationships snomed/IsA]) parent-id)) (defmulti has-property? (fn [_store concept _property-id _value-id] (class concept))) @@ -647,7 +647,7 @@ (contains? (get-parent-relationships-of-type store (:id concept) property-id) value-id)) (defmethod has-property? ExtendedConcept [_ extended-concept property-id value-id] - (contains? (get-in extended-concept [:parent-relationships property-id]) value-id)) + (contains? (get-in extended-concept [:parentRelationships property-id]) value-id)) (comment (set! *warn-on-reflection* true) diff --git a/src/com/eldrix/hermes/server.clj b/src/com/eldrix/hermes/server.clj index f4c480d1..c95cb44a 100644 --- a/src/com/eldrix/hermes/server.clj +++ b/src/com/eldrix/hermes/server.clj @@ -118,7 +118,7 @@ (when-let [concept (svc/getExtendedConcept svc concept-id)] (let [langs (or (get-in context [:request :headers "accept-language"] (.toLanguageTag (Locale/getDefault)))) preferred (svc/getPreferredSynonym svc concept-id langs)] - (assoc context :result (assoc concept :preferred-description preferred)))))))}) + (assoc context :result (assoc concept :preferredDescription preferred)))))))}) (def get-concept-descriptions {:name ::get-concept-descriptions diff --git a/src/com/eldrix/hermes/snomed.clj b/src/com/eldrix/hermes/snomed.clj index e30f88af..fd24320f 100644 --- a/src/com/eldrix/hermes/snomed.clj +++ b/src/com/eldrix/hermes/snomed.clj @@ -203,8 +203,8 @@ ;; convenient structure, that can then be cached and used for inference. (defrecord ExtendedConcept [concept descriptions - parent-relationships - direct-parent-relationships + parentRelationships + directParentRelationships refsets]) (defn parse-concept [v]