An open API service indexing awesome lists of open source software.

https://github.com/ntnu-ai-lab/mycbr-rest


https://github.com/ntnu-ai-lab/mycbr-rest

Last synced: about 1 month ago
JSON representation

Awesome Lists containing this project

README

        

* Introduction
:PROPERTIES:
:CUSTOM_ID: introduction
:END:

This project puts myCBR into Spring.io and provides the created REST
calls through a Swagger API

* How to
:PROPERTIES:
:CUSTOM_ID: how-to
:END:
- Build and install the newest [[https://github.com/ntnu-ai-lab/mycbr-sdk][myCBR-SDK]]
- Clone this project
- Add myCBR to the API
- To build it go into its root folder and run:

** Deploying the myCBR Rest API
Next you will have to download and build the Rest API. As the Rest API uses the myCBR SDK you need to install is using the following command:
#+BEGIN_EXAMPLE
cd ../mycbr-rest
mvn install:install-file -Dfile=../mycbr-sdk/target/myCBR-x.x-SNAPSHOT.jar -DpomFile=../mycbr-sdk/pom.xml -DlocalRepositoryPath=lib/no/ntnu/mycbr/mycbr-sdk/
#+END_EXAMPLE
For these calls we assume that both the mycbr-sdk and mycbr-rest are located in the same folder:
#+BEGIN_EXAMPLE
root
|__ mycbr-sdk
|__pom.xml
|__src
|__target
|__myCBR-x.x-SNAPSHOT.jar
|__ mycbr-rest
|__pom.xml
|__src
|__target
|__mycbr-rest-x.x-SNAPSHOT.jar
|__lib/no/ntnu/mycbr/mycbr-sdk/
#+END_EXAMPLE

** Building and Running the API
#+BEGIN_EXAMPLE
mvn clean install
or
mvn clean install -DskipTests=True
#+END_EXAMPLE

- In order to deploy the Spring app, run:

#+BEGIN_EXAMPLE
java -DMYCBR.PROJECT.FILE={path to the project file} -jar ./target/mycbr-rest-2.0.jar
#+END_EXAMPLE

- After Spring has started, you can find the API documentation here:
[[http://localhost:8080/swagger-ui.html#!/]]
- Greeting controller is the sample I used to build the app
- CBR Controller contains the myCBR bits
- ctrl + C shuts down the server

* Functionalities
:PROPERTIES:
:CUSTOM_ID: functionalities
:END:

- The goal is to provide the entire retrieval, however, so far only the
model is working ## GET Requests
- /case provides the case content
- /concepts provides all concept names in the project
- /casebase provides the name(s) of the case bases associated with the
project
- /retieval provides the similarity-based retrieval either by specifying
symbols or an id of existing cases
- /attributes provides a list of attributes and their value types
- /values provides the list of allowed values for SymbolDesc attributes
and min/max for IntegerDesc/DoubleDesc/FloatDesc ## POST Requests
- /retrieval allows you to post a query with a number of attributes,
e.g.:\\
={"Doors": 4, "Model": "e_300_diesel", "Manufacturer": "mercedes-benz","Color":"yellow, blue"}=
- Currently only Symbol, Integer, Double and Float attributes are
supported.
- Currently only Multiple Symbol attributes are supported
- the number of returned cases can be set, use -1 for returning all

* Customization to other myCBR projects
:PROPERTIES:
:CUSTOM_ID: customization-to-other-mycbr-projects
:END:

- The app requires a myCBR project, which should be put into
mycbr-rest-example/src/main/resources
- In order to detect the project file, CBREngine.java has to be adapted:
- private static String projectName = "used\_cars\_flat.prj" should be
changed to the project file's name
- The rest of the API is independent from the project, hence only the
parameters such as case base and comcept names have to be adapted to
the new project

* REST API
The REST API created for the mycbr backend is trying to adhere to the REST semantics.

- POST: POST operations should be used when the REST api user does not know exactly
where the item in question should be located. Typically due to undefined
behaviour or bad documentation. This operation shold return a URL that
contains an ID for that item, that also gives the user the location the REST
server moved the item to.
- PUT: Instead PUT should be used to put an item at the exact location. This
operation should typically contain a ID/name given by the REST api user. It
should return a failure if the item already exists.
- UPDATE: Both of the above URLs (returned by REST server on the first instance, and
specified by the user on the second) should accept UPDATE operations on the
item in question.
- DELETE: this also goes for deleting items from that URL.

Some concepts in mycbr is not so easy to represent in REST, such as one-to-many
relations such as those between casebases and concepts. One concept could have
one or more casebases for segmenting instances of that concept into more case
bases.

Also recursive attributes, such as concepts that are attributes of other
concepts, which could result in circular dependencies, which should be
restricted on the REST server. Right now directed acyclic graph of concepts are
supported, and DELETE operations are now supported for those types of
structures.

However not everything representable in mycbr has been implemented to that
standard yet.

** Semantics
#+BEGIN_SRC
/instances
/casebases
/concepts
/concepts/{conceptID}/amalgamationFunction
/concepts/{conceptID}/attribute
/concepts/{conceptID}/attribute/{attributeID}
/concepts/{conceptID}/attribute/{attributeID}/similarityFunctions
/concepts/{conceptID}/attribute/{attributeID}/similarityFunctions/{similarityFunctionID}
/concepts/{conceptID}/instances
#+END_SRC

Semantically one can PUT and DELETE to each of these endpoints, such that a HTTP
DELETE to "http://host:port/casbases" would delete all casebases. Each PUT
operation has it's own associated JSON format, e.g. for describing a instances
or a similarity function of a concept or attribute. Below we describe the JSON
format for each of the PUT operations.

** Not yet implemented..

#+BEGIN_EXAMPLE
/concepts/{conceptID}/concepts
#+END_EXAMPLE
Could be implemented in ConceptController.java like this..
#+BEGIN_SRC java
@RequestMapping("/concepts/{conceptID}/**")
public void foo(@PathVariable("conceptID") int id, HttpServletRequest request) {
String restOfTheUrl = (String) request.getAttribute(
HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
...
}
#+END_SRC
* Examples
Using the REST api from other programming languages is quite easy, below we
provide an example of how to do this in python. This is just a base class used
to build unit tests for mycbr from python. More example code can be found in
[[./examples/]]

#+BEGIN_SRC python
from mycbrwrapper.rest import getRequest
import unittest

__name__ = "test_base"

defaulthost = "localhost:8080"
"""
The model of the case base for the unit tests are simple
id,name,doubleattr1,doubleattr2
"""

class CBRTestCase(unittest.TestCase):
casesJSON = """{"cases" : [
{
"wind_speed": "0",
"wind_from_direction": "0",
"wind_effect": "0"
},
{
"wind_speed": "5.2",
"wind_from_direction": "279",
"wind_effect": "5.3"
},
{
"wind_speed": "2.1",
"wind_from_direction": "339",
"wind_effect": "1.05"
}
]}"""
localSimID = "testLocalSimilarityFunction"
localSimJSON = """{{
"id"="{}"
"type"="Double"
"subtype"="Polywidth"
"parameters"="4.5"
}}""".format(localSimID)

amalgamationSimID = "testAmalgmamationSimilarityFunction1"

# here type can be either of MINIMUM, MAXIMUM, WEIGHTED_SUM, EUCLIDEAN, NEURAL_NETWORK_SOLUTION_DIRECTLY,SIM_DEF;

def __init__(self, *args, **kwargs):
super(CBRTestCase, self).__init__(*args, **kwargs)
@classmethod
def getAttributeParamterJSON(cls,min,max):
return """
{{
"type": "Double",
"min": "{}",
"max": "{}"
}}
""".format(min,max)

@classmethod
def setUpClass(cls):
print("in super setupclass")
cls.createTestCaseBase()
cls.createConcept()
cls.createAttributes()
cls.createLocalSimilarityFunctions()
cls.createAmalgamationFunctions()
cls.createCases()

@classmethod
def tearDownClass(cls):
print("in super teardownclass")
cls.destroyCases()
cls.destroyLocalSimilarityFunctions()
cls.destroyAmalgamationFunctions()
cls.destroyAttributes()
cls.destroyConcept()
cls.destroyTestCaseBase()

@classmethod
def createTestCaseBase(cls, host=defaulthost):
print("in createTestCaseBase")
api = getRequest(host)
call = api.casebases
result = call.PUT("unittestCB")
print("url : {}".format(call._url))
print("result : {}".format(result))

@classmethod
def createConcept(cls, host=defaulthost):
"""
This is now working, it creates a concept.
"""
print("in createconcept")
api = getRequest(host)
call = api.concepts
result = call.PUT("testconcept")
print("url : {}".format(call._url))
print("result : {}".format(result))

@classmethod
def createAttributes(cls, host=defaulthost):
api = getRequest(host)
api.concepts("testconcept").attributes\
.PUT("wind_speed",params={"attributeJSON":cls.getAttributeParamterJSON(0,25)})
api.concepts("testconcept").attributes\
.PUT("wind_from_direction",params={"attributeJSON":cls.getAttributeParamterJSON(0,361)})
api.concepts("testconcept").attributes\
.PUT("wind_effect",params={"attributeJSON":cls.getAttributeParamterJSON(0,40)})

@classmethod
def createLocalSimilarityFunctions(cls, host=defaulthost):
api = getRequest(host)
api.concepts("testconcept").attributes("wind_speed")\
.similarityfunctions\
.PUT(cls.localSimJSON)

@classmethod
def createAmalgamationFunctions(cls, host=defaulthost):
api = getRequest(host)
call = api.concepts("testconcept").amalgamationFunctions(cls.amalgamationSimID)

result = call.PUT(params={"amalgamationFunctionType":"NEURAL_NETWORK_SOLUTION_DIRECTLY"})
print("add alg url {} result {}".format(call._url,result))

@classmethod
def createCases(cls, host=defaulthost):
print("in createcases")
api = getRequest(host)
call = api.concepts("testconcept").casebases("unittestCB").instances
call.PUT(params={'cases':cls.casesJSON})

print("url: {} ".format(call._url))

@classmethod
def destroyTestCaseBase(cls, host=defaulthost):
api = getRequest(host)
api.casebases("unittestCB").DELETE()

@classmethod
def destroyConcept(cls, host=defaulthost):
api = getRequest(host)
call = api.concepts("testconcept")
call.DELETE()
print("in delete concept url is: {}".format(call._url))

@classmethod
def destroyAttributes(cls, host=defaulthost):
api = getRequest(host)
api.concepts("testconcept").attributes("wind_speed").DELETE()
api.concepts("testconcept").attributes("wind_from_direction").DELETE()
api.concepts("testconcept").attributes("wind_effect").DELETE()

@classmethod
def destroyLocalSimilarityFunctions(cls, host=defaulthost):
api = getRequest(host)
api.concepts("testconcept").attributes("wind_speed")\
.similarityfunction(cls.localSimID)\
.DELETE()

@classmethod
def destroyAmalgamationFunctions(cls, host=defaulthost):
api = getRequest(host)
api.concepts("testconcept")\
.amalgamationFunctions(cls.amalgamationSimID).DELETE()

@classmethod
def destroyCases(cls, host=defaulthost):
api = getRequest(host)
api.concepts("testconcept").casebases("unittestCB").instances.DELETE()

if __name__ == "__main__":
unittest.main()

#+END_SRC