elyciteapi.js

Elycite - Routing - Main Module

(c) 2013-2014 Luis Rei, Josef Stefan Institute MIT License

var analytics = require('analytics.js');
var restf = require('restf.js');
var stores = require('stores.js');
var documents = require('documents.js');
var concepts = require('concepts.js');
var al = require('activelearning.js');
var cls = require('classifiers.js');

Introductory Notes

Options

/languageoptions/

Method: GET

Description: Get Language Options

Returns: Options for stemmers and stopword lists

{ stemmer: [“none”, “porter”], stopwords: [“none”, “en8”, …] }

http.onRequest("languageoptions", "GET", function(req, res) {
  console.say("elycite API - Language Options");

  var LangOpts = analytics.getLanguageOptions();
  res.send(LangOpts);
});

Stores

/stores/

METHOD: GET

Description: Get List of available Data (Document) Stores

Returns: A list of qminer store definitions

http.onRequest("stores", "GET", function(req, res) {
  console.say("elycite API - GET Stores");
  stores.listStores(res);
});

METHOD: POST

Description: Create a data (document) store with records

JSON DATA:


 {
   storeName: "exampleName",
   records: [{RecVal1}, ...]
 }
http.onRequest("stores/", "POST", function(req, res) {
  console.say("elycite API - POST Stores");
  var data = restf.requireJSON(req, res, "storeName", "records");
  if(data === null) { return; }

  stores.createStore(res, data);
});

Get a single store definition by name @TODO: NOT IMPLEMENTED

http.onRequest("stores/<store>", "GET", function(req, res) {
  console.say("elycite API - GET Stores");
  res.setStatusCode(501);
  res.send();
});

Ontologies

Example ontology document (JSON representation):


 {
     $id: 3,
     name: "textmining",
     docStore: "news",
     classifierStore: "textmining_cls",
     isDeleted: false,
     links: {
       self: "/elyciteapi/ontologies/textmining/",
       concepts: "/elyciteapi/ontologies/textmining/concepts/"
     }
   }

/ontologies/

METHOD: GET

Description: Get List of Existing Ontologies

Returns: list of ontology documents

[OntologyDocument1, OntologyDocument2, …]

http.onRequest("ontologies", "GET", function(req, res) {
  console.say("elycite API - GET Existing Ontologies");
  stores.listOntologies(res);
});

METHOD: POST

Description: Create a new ontology

JSONDATA:


 {
   ontologyName: "new_ontology", 
   dataStore:"news_data"
 }

Returns: the ontology

Example Request:


   curl -H "Content-Type: application/json" -d \
   '{"ontologyName":"textmining","dataStore":"news"}' \
   http://localhost:8080/elyciteapi/ontologies
http.onRequest("ontologies", "POST", function(req, res) {
  console.say("elycite API - Create Ontology: ");
  var data = restf.requireJSON(req, res, "ontologyName", "dataStore");
  if(data === null) { return; }
  stores.createOntology(res, data);
});

/ontologies/[ontology]/

METHOD: GET

Description: Read ontology definition

PARAMS:

Returns: the ontology JSON representation. See above.

http.onRequest("ontologies/<ontology>/", "GET", function (req, res) {
  console.say("elycite API - Concept ontology def");
  var params = restf.requireParams(req, res, "ontology");
  if(params === null) { return; }
  var store = stores.requireExists(res, params.ontology);
  if(store === null) { return; }

  stores.getOntology(res, store);
});

Documents

A document is a record from the data store associated with the ontology. It includes all fields in the data (qminer( record. Text fields can optionally be summarized (truncated).

/ontologies/[ontology]/documents/

METHOD: GET

Description: Get All Documents - Summaries only by default

PARAMS:

ARGS:

RETURNS: list of documents (see above).

Example:


 curl -X GET \
 "http://localhost:8080/elyciteapi/ontologies/test/documents/?page=3&per_page=2&summarize=true?"
http.onRequest("ontologies/<ontology>/documents/", "GET", function (req, res) {
  console.say("elycite API - Document GET ALL (summaries)");
  var params = restf.requireParams(req, res, "ontology");
  if(params === null) { return; }
  var store = stores.requireExists(res, params.ontology);
  if(store === null) { return; }
  documents.getDocuments(req, res, store);
});

/ontologies/[ontology]/documents/[did]/

METHOD: GET

Description: Read Document

PARAMS:

RETURNS: a single document

http.onRequest("ontologies/<ontology>/documents/<did>/", "GET", 
               function (req, res) {
  console.say("elycite API - Document <did> GET");
  var params = restf.requireParams(req, res, "ontology", "did");
  if(params === null) { return; }
  var store = stores.requireExists(res, params.ontology);
  if(store === null) { return; }
  var docId = restf.requireInt(res, "did", params.did);
  if(docId === null) { return; }

  documents.getDocument(res, store, params.ontology, docId);
});

Concepts


 {
   $id: 0,
   name: "root",
   keywords: "",
   stopwords: "none",
   stemmer: "none",
   isDeleted: false,
   classifiers: [ ],
   parentId: -1,
   ontology: "textmining",
   links: {
             self: "/elyciteapi/ontologies/textmining/concepts/0/",
             ontology: "/elyciteapi/ontologies/textmining/"
          }
 }

/ontologies/[ontology]/concepts/

METHOD: GET

Description: Get all concepts (see above)

PARAMS:

ARGS:

RETURNS: a list of concepts

http.onRequest("ontologies/<ontology>/concepts/", "GET", function (req, res) {
  console.say("elycite API - Concept GET ALL");
  var params = restf.requireParams(req, res, "ontology");
  if(params === null) { return; }
  var store = stores.requireExists(res, params.ontology);
  if(store === null) { return; }

  concepts.getConcepts(res, store, params.ontology);
});

METHOD: POST

Description: Create a concept

PARAMS:

JSONDATA: A JSON representation of non-calculated concept properties.

EXAMPLE REQUEST:


 curl -H "Content-Type: application/json" -d \
 '{"name":"testc", "parentId":0, "docs":[0,1,3]}' \
 http://localhost:8080/elyciteapi/ontologies/textmining/concepts/
http.onRequest("ontologies/<ontology>/concepts/", "POST", 
               function (req, res) {
  console.say("elycite API - Concept POST");
  var params = restf.requireParams(req, res, "ontology");
  if(params === null) { return; }
  var store = stores.requireExists(res, params.ontology);
  if(store === null) { return; }
  var data = restf.requireJSON(req, res, "name", "parentId");
  if(data === null) { return; }

  concepts.createConcept(res, data, store, params.ontology);
});

/ontologies/[ontology]/concepts/[cid]/

METHOD: GET

Description: Get a single concept

PARAMS:

RETURNS: the concept

http.onRequest("ontologies/<ontology>/concepts/<cid>/", "GET",
               function (req, res) {
  console.say("elycite API - Concept GET");
  var params = restf.requireParams(req, res, "ontology", "cid");
  if(params === null) { return; }
  var store = stores.requireExists(res, params.ontology);
  if(store === null) { return; }
  var conceptId = restf.requireInt(res, "cid", params.cid);
  if(conceptId === null) { return; }
  var concept = stores.requireRecord(res, store, "concept", conceptId);
  if(concept === null) { return; }

  concepts.getConcept(res, store, concept);
});

METHOD: PUT

Description: Edit a concept

PARAMS:

EXAMPLE REQUEST:


 curl -X PUT -H "Content-Type: application/json" -d '{"name":"hello"}' \ 
 http://localhost:8080/elyciteapi/ontologies/textmining/concepts/1/
http.onRequest("ontologies/<ontology>/concepts/<cid>/", "PUT", 
               function (req, res) {
  console.say("elycite API - Concept edit PUT");
  var params = restf.requireParams(req, res, "ontology", "cid");
  if(params === null) { return; }
  var store = stores.requireExists(res, params.ontology);
  if(store === null) { return; }
  var data = restf.requireJSON(req, res);
  if(data === null) { return; }
  var conceptId = restf.requireInt(res, "cid", params.cid);
  if(conceptId === null) { return; }
  var concept = stores.requireRecord(res, store, "concept", conceptId);
  if(concept === null) { return; }

  concepts.editConcept(res, concept, data, store, params.ontology);
});

METHOD: DELETE

Description: Delete this concept including subconcepts (recursively).

PARAMS:

EXAMPLE REQUEST:


 curl -X DELETE \
 http://localhost:8080/elyciteapi/ontologies/textmining/concepts/1/
http.onRequest("ontologies/<ontology>/concepts/<cid>/", "DELETE",
               function (req, res) {
  console.say("elycite API - Concept DELETE");
  var params = restf.requireParams(req, res, "ontology", "cid");
  if(params === null) { return; }
  var store = stores.requireExists(res, params.ontology);
  if(store === null) { return; }
  var conceptId = restf.requireInt(res, "conceptId", params.cid);
  if(conceptId === null) { return; }
  var concept = stores.requireRecord(res, store, "concept", conceptId);
  if(concept === null) { return; }

  concepts.deleteConcept(res, concept, store);
});

/ontologies//concepts/[cid]/subconcepts/

METHOD: GET

Description: get a list of concepts that are subsconcepts (children) of this concept

PARAMS:

RETURNS: an array containing concepts that are the concept‘s subconcepts (children)

http.onRequest("ontologies/<ontology>/concepts/<cid>/subconcepts/", "GET",
               function (req, res) {
  console.say("elycite API - GET SUB CONCETPS");
  var params = restf.requireParams(req, res, "ontology", "cid");
  if(params === null) { return; }
  var store = stores.requireExists(res, params.ontology);
  if(store === null) { return; }
  var conceptId = restf.requireInt(res, "cid", params.cid);
  if(conceptId === null) { return; }
  var concept = stores.requireRecord(res, store, "concept", conceptId);
  if(concept === null) { return; }

  concepts.getSubConcepts(res, concept, store, params.ontology);
});

/ontologies/[ontology]/concepts/[cid]/docs/

METHOD: GET

Description: Get a list of document record ids that are in the concept

PARAMS:

RETURNS: an array of document record ids (ints)

http.onRequest("ontologies/<ontology>/concepts/<cid>/docs/", "GET", 
               function (req, res) {
  console.say("elycite API - Concept GET docs");
  var params = restf.requireParams(req, res, "ontology", "cid");
  if(params === null) { return; }
  var store = stores.requireExists(res, params.ontology);
  if(store === null) { return; }
  var conceptId = restf.requireInt(res, "conceptId", params.cid);
  if(conceptId === null) { return; }
  var concept = stores.requireRecord(res, store, "concept", conceptId);
  if(concept === null) { return; }

  concepts.getConceptDocuments(req, res, concept, store);
});

METHOD: PATCH

DESCRIPTION: Edit the list of document record ids in the concept (Select, DeSelect)

PARAMS:

JSONDATA:

RETURNS: an array with the document record ids in the concept

EXAMPLE REQUEST:


 curl -X PATCH -H "Content-Type: application/json" \
 -d '{"docId":20, "operation":"add"}' \
 http://localhost:8080/elyciteapi/ontologies/demo/concepts/1/docs/
http.onRequest("ontologies/<ontology>/concepts/<cid>/docs/", "PATCH",
               function (req, res) {
  console.say("elycite API - Concept Edit doc list");
  var params = restf.requireParams(req, res, "ontology", "cid");
  if(params === null) { return; }
  var store = stores.requireExists(res, params.ontology);
  if(store === null) { return; }
  var conceptId = restf.requireInt(res, "conceptId", params.cid);
  if(conceptId === null) { return; }
  var concept = stores.requireRecord(res, store, "concept", conceptId);
  if(concept === null) { return; }
  concept = restf.requireNotDeleted(concept, "concept");
  if(concept === null) { return; }
  var data = restf.requireJSON(req, res, "operation", "docId");
  if(data === null) { return; }
  var docId = restf.requireInt(res, "docId", data.docId);
  if(docId === null) { return; }

  concepts.editConceptDocuments(res, docId, data.operation, concept, store);
});

/ontologies/[ontology]/concepts/[cid]/suggestkeywords/

METHOD: GET

Description: Get keyword suggestions for a concept

PARAMS:

ARGS:

RETURNS: a JSON object with a keywords string property consisting of the suggested keywords separated by a comma an a space. Example:


 {
   "keywords":"services, bank, business, management, markets"
 }
http.onRequest("ontologies/<ontology>/concepts/<cid>/suggestkeywords/", "GET", 
               function (req, res) {
  console.say("elycite API - Concept/suggeskeywords");
  var params = restf.requireParams(req, res, "ontology", "cid");
  if(params === null) { return; }
  var store = stores.requireExists(res, params.ontology);
  if(store === null) { return; }
  var conceptId = restf.requireInt(res, "conceptId", params.cid);
  if(conceptId === null) { return; }
  var concept = stores.requireRecord(res, store, "concept", conceptId);
  if(concept === null) { return; }
  concept = restf.requireNotDeleted(concept, "concept");
  if(concept === null) { return; }

  var args = req.args || {};
  concepts.getKeywordSuggestions(res, args, concept);
});

/ontologies/[ontology]/concepts/[cid]/search/

METHOD: GET

Description: Suggest a subconcept based on search

PARAMS:

ARGS:

RETURNS: a concept suggestion (concept without id or generated properties). Example:


 {
   name: "software",
   keywords: "services, solutions, systems, management, technology, network",
   parentId: 0,
   docs: [3, 5, ...]
 }
http.onRequest("ontologies/<ontology>/concepts/<cid>/search/", "GET", 
               function (req, res) {
  console.say("elycite API - Concept/Search");
  var params = restf.requireParams(req, res, "ontology", "cid");
  if(params === null) { return; }
  var store = stores.requireExists(res, params.ontology);
  if(store === null) { return; }
  var conceptId = restf.requireInt(res, "conceptId", params.cid);
  if(conceptId === null) { return; }
  var concept = stores.requireRecord(res, store, "concept", conceptId);
  if(concept === null) { return; }
  concept = restf.requireNotDeleted(concept, "concept");
  if(concept === null) { return; }
  var args = restf.requireArgs(req, res, "query");
  if(args === null) { return; }

  concepts.getConceptSuggestionFromQuery(res, concept, store, args.query);
});

/ontologies/[ontology]/concepts/[cid]/suggest/

METHOD: GET

Description: Suggest subconcepts (clustering based)

PARAMS:

ARGS:

RETURNS: an array of concept suggestions (concepts without id or generated properties). See the return of /search/ above.

http.onRequest("ontologies/<ontology>/concepts/<cid>/suggest/", "GET",
               function (req, res) {
  console.say("elycite API - Concept GET suggestions");
  var params = restf.requireParams(req, res, "ontology", "cid");
  if(params === null) { return; }
  var store = stores.requireExists(res, params.ontology);
  if(store === null) { return; }
  var conceptId = restf.requireInt(res, "conceptId", params.cid);
  if(conceptId === null) { return; }
  var concept = stores.requireRecord(res, store, "concept", conceptId);
  if(concept === null) { return; }
  concept = restf.requireNotDeleted(concept, "concept");
  if(concept === null) { return; }

  concepts.getConceptSuggestionsByClustering(req, res, concept, store);
});

Active Learning

While there is no actual “active learner document”, there is a question document where the id attribute refers to the AL and the questionId is the id of the data associated with the question:


 {
   “questionId”:128,
   “id”:”medical_1936769238”,
   “links”:{
     “self”:”/elyciteapi/ontologies/undefined/concepts/0/al/medical_1936769238/“
   },
   “text”:”Develops and manages medical facilities…”,
   “mode”:false
 }
If mode is true, the question also includes all necessary information to create a new concept


 {
   …
   “mode”:true,
   “count”:518,
   “docs”:[75,…],
   “name”: “medical, services, products”,
   “keywords”:, “medical, …”
 }

/ontologies/[ontology]/concepts/[cid]/al/

METHOD: POST

Description: Create Active Learner for a given query

PARAMS:

JSONDATA:

RETURNS: An initial question.

http.onRequest("ontologies/<ontology>/concepts/<cid>/al/", "POST",
               function (req, res) {
  console.say("elycite API - AL Create - POST");
  var params = restf.requireParams(req, res, "ontology", "cid");
  if(params === null) { return; }
  var store = stores.requireExists(res, params.ontology);
  if(store === null) { return; }
  var conceptId = restf.requireInt(res, "conceptId", params.cid);
  if(conceptId === null) { return; }
  var concept = stores.requireRecord(res, store, "concept", conceptId);
  if(concept === null) { return; }
  concept = restf.requireNotDeleted(concept, "concept");
  if(concept === null) { return; }
  var data = restf.requireJSON(req, res, "query");
  var query = data.query;

  al.create(res, data, concept, store, query);
});

/ontologies/[ontology]/concepts/[cid]/al/[alid]/

METHOD: GET

Description: Get a question from an active learner.

PARAMS:

RETURNS: A question.

http.onRequest("ontologies/<ontology>/concepts/<cid>/al/<alid>/", "GET",
               function (req, res) {
  console.say("elycite API - AL/name/ GET");
  var params = restf.requireParams(req, res, "ontology", "cid", "alid");
  if(params === null) { return; }
  var store = stores.requireExists(res, params.ontology);
  if(store === null) { return; }
  var conceptId = restf.requireInt(res, "conceptId", params.cid);
  if(conceptId === null) { return; }
  var concept = stores.requireRecord(res, store, "concept", conceptId);
  if(concept === null) { return; }
  concept = restf.requireNotDeleted(concept, "concept");
  if(concept === null) { return; }

  var name = params.alid;

  al.getQuestion(res, name, concept, params.ontology);
});

METHOD: PATCH

Description: Answer a question from an active learner.

PARAMS:

JSONDATA:

RETURNS: The next question.

http.onRequest("ontologies/<ontology>/concepts/<cid>/al/<alid>/", "PATCH",
               function (req, res) {
  console.say("elycite API - AL/name/ PATCH");
  var params = restf.requireParams(req, res, "ontology", "cid", "alid");
  if(params === null) { return; }
  var store = stores.requireExists(res, params.ontology);
  if(store === null) { return; }
  var conceptId = restf.requireInt(res, "conceptId", params.cid);
  if(conceptId === null) { return; }
  var concept = stores.requireRecord(res, store, "concept", conceptId);
  if(concept === null) { return; }
  concept = restf.requireNotDeleted(concept, "concept");
  if(concept === null) { return; }
  var data = restf.requireJSON(req, res, "answer", "did");
  var did = restf.requireInt(res, "did", data.did); // actually did
  var name = params.alid;

  al.answerQuestion(res, name, concept, params.ontology, did, data.answer);
});

METHOD: DELETE

Description: Cancel (DELETE) active learner.

PARAMS:

http.onRequest("ontologies/<ontology>/concepts/<cid>/al/<alid>/", "DELETE",
               function (req, res) {
  console.say("elycite API - AL/name/ DELETE");
  var params = restf.requireParams(req, res, "ontology", "cid", "alid");
  if(params === null) { return; }
  var store = stores.requireExists(res, params.ontology);
  if(store === null) { return; }
  var conceptId = restf.requireInt(res, "conceptId", params.cid);
  if(conceptId === null) { return; }
  var concept = stores.requireRecord(res, store, "concept", conceptId);
  if(concept === null) { return; }
  concept = restf.requireNotDeleted(concept, "concept");
  if(concept === null) { return; }

  var name = params.alid;
  al.cancel(res, name);
});

METHOD: POST

Description: Get Concept: finish active learning and create the concept

PARAMS:

RETURNS: The concept created.

http.onRequest("ontologies/<ontology>/concepts/<cid>/al/<alid>/", 
               "POST", function (req, res) {
  console.say("elycite API - AL/name/ POST");
  var params = restf.requireParams(req, res, "ontology", "cid", "alid");
  if(params === null) { return; }
  var store = stores.requireExists(res, params.ontology);
  if(store === null) { return; }
  var conceptId = restf.requireInt(res, "conceptId", params.cid);
  if(conceptId === null) { return; }
  var concept = stores.requireRecord(res, store, "concept", conceptId);
  if(concept === null) { return; }
  concept = restf.requireNotDeleted(concept, "concept");
  if(concept === null) { return; }
  var name = params.alid;
 
  al.finish(res, name, concept);
});

Classifiers (SVM)


 {
   “id”:”classifier_name”,
   “links”:{
     “self”:”/elyciteapi/ontologies/blahblah/classifiers/classifier_name/“,
     “ontology”:”/elyciteapi/ontologies/blahblah/“
   }
 }

/ontologies/[ontology]/classifiers/

METHOD: POST

Description: List existing classifiers (models).

PARAMS:

RETURNS: A list of classifiers.

http.onRequest("ontologies/<ontology>/classifiers/", "GET",
               function (req, res) {
  console.say("elycite API - Classifiers  Get");
  var params = restf.requireParams(req, res, "ontology");
  if(params === null) { return; }
  var store = stores.requireExists(res, params.ontology);
  if(store === null) { return; }

  cls.list(res, store);
});

METHOD: POST

Description: Create classifier for a Concept.

PARAMS:

JSONDATA:

RETURNS: The classifier created.

http.onRequest("ontologies/<ontology>/classifiers/", "POST", 
               function (req, res) {
  console.say("elycite API - Concept Classifier - POST");
  var params = restf.requireParams(req, res, "ontology");
  if(params === null) { return; }
  var store = stores.requireExists(res, params.ontology);
  if(store === null) { return; }
  var data = restf.requireJSON(req, res, "name", "cid");
  var conceptId = restf.requireInt(res, "conceptId", data.cid);
  if(conceptId === null) { return; }
  var concept = stores.requireRecord(res, store, "concept", conceptId);
  if(concept === null) { return; }
  concept = restf.requireNotDeleted(concept, "concept");
  if(concept === null) { return; }

  cls.create(res, data, concept, store, params.ontology);
});

/ontologies/[ontology]/classifiers/[mid]/

METHOD: POST

Description: Classify array of documents.

PARAMS:

RETURNS: An array of decision functions (negative or positive numbers).

Example:


 curl -X POST -H “Content-Type: application/json” \
 -d ‘[“this is about networks”, “this is dog”]’ \
 http://localhost:8080/elyciteapi/ontologies/worktest/classifiers/worktest_network/

http.onRequest("ontologies/<ontology>/classifiers/<mid>/", "POST", 
               function (req, res) {
  console.say("elycite API - Classify with model POST");
  var params = restf.requireParams(req, res, "ontology", "mid");
  if(params === null) { return; }
  var store = stores.requireExists(res, params.ontology);
  if(store === null) { return; }
  var data = restf.requireJSON(req, res);

  cls.classify(res, params.mid, data, store);
});

METHOD: DELETE

Description: Delete a classifier (with ontology parameter).

PARAMS:

http.onRequest("ontologies/<ontology>/classifiers/<mid>/", "DELETE",
               function (req, res) {
  console.say("elycite API - DELETE Classifier");
  var params = restf.requireParams(req, res, "mid");
  if(params === null) { return; }
  var mid = params.mid;
  cls.deleteClassifier(mid);
  res.send();
});

/ontologies/[ontology]/classifiers/[mid]/

METHOD: POST

Description: Get (binary) subsconcepts from classifier.

PARAMS:

RETURNS: Array with positive and negative subconcepts.

http.onRequest("ontologies/<ontology>/concepts/<cid>/classify/<mid>/", "GET", 
               function (req, res) {
  console.say("elycite API - GET SUB CONCETPS FROM CLASSIFIER");
  var params = restf.requireParams(req, res, "ontology", "cid", "mid");
  if(params === null) { return; }
  var store = stores.requireExists(res, params.ontology);
  if(store === null) { return; }
  var conceptId = restf.requireInt(res, "conceptId", params.cid);
  if(conceptId === null) { return; }
  var concept = stores.requireRecord(res, store, "concept", conceptId);
  if(concept === null) { return; }
  concept = restf.requireNotDeleted(concept, "concept");
  if(concept === null) { return; }
  var args = req.args || {};
  var threshold = restf.optionalFloat(args, "thresh", 0);
  var mid = params.mid;

  cls.subConcepts(res, mid, threshold, concept, store);
});

/classifiers/

METHOD: GET

Description: List existing classifiers (models) for ALL ontologies

RETURNS: A list of classifiers.

http.onRequest("classifiers/", "GET", function (req, res) {
  console.say("elycite API - Classifiers  Get ALL");
  cls.listAll(res);
});

/classifiers/[mid]/

METHOD: DELETE

Description: Delete a classifier (without ontology parameter)

PARAMS:

http.onRequest("classifiers/<mid>/", "DELETE", function (req, res) {
  console.say("elycite API - DELETE Classifier");
  var params = restf.requireParams(req, res, "mid");
  if(params === null) { return; }
  var mid = params.mid;
  cls.deleteClassifier(mid);
  res.send();
});
h