-
Notifications
You must be signed in to change notification settings - Fork 63
A Step By Step Guide For Adding A New Algorithm Type (With Example)
Do you want to add a new Algorithm Type but don't know where to start? Look no further, this guide will show you all the Classes and Interfaces you'll have to go through in order to successfully add a new Algorithm Type which should be displayed on the list of algorithms on the Metanome frontpage.
In this guide, we'll add the new Type Conditional Inclusion Dependency
to the project. If you want a reference, see the corresponding pull request but caution: Some code could be outdated due to refactorings. Always check a file's status in the master branch.
Since Metanome is a giant Maven project with every algorithm being its own smaller Maven project, we first have to ensure that our algorithm is being included when building.
- Clone the
metanome-algorithms
-repository - Add a new folder to the root directory. Its name should be the first letter of each word of your Algorithm Type. So for `Conditional Inclusion Dependency` we'll add a folder named `cid`.
- Create a pom file named `pom.xml` and a folder named
src
. The folder will contain the source code and tests itself while the pom file is responsible for building our Algorithm. - For the contents of
pom.xml
, please refer to this wiki page.
├── metanome-algorithms/ │ ├── cid/ │ │ ├── pom.xml │ │ ├── target/ (after initial Maven build) │ │ ├── src/ │ │ │ ├── test/ │ │ │ │ ├── java/ │ │ │ ├── main/ │ │ │ │ ├── java/ │ │ │ │ ├── resources/
Every Algorithm Type implements the Algorithm
-Interface which returns a Result
for a ResultReceiver
to receive and process further. Before we can implement our algorithm itself, we have to extend these interfaces with our own implementation first.
So, we need to go to the main Metanome
-repository which you should clone if not already done.
Instead of flooding the guide with code for our Conditional Inclusion Dependency
example, the belonging example files will be linked at the start of each step.
- We'll start by implementing our
Result
. This class is returned after anAlgorithm
was executed. Go tode.metanome.algorithm_integration.results
and add your own Result-Class which implements theResult
-Interface. Name the class after the name of the Algorithm Type you want to add, eg.ConditionalInclusionDependency
. Specify all the variables the result of your algorithm should return. ImplementsendResultTo
byresultReceiver.receiveResult(this)
. Make sure theJsonTypeName
-Annotation matches the one of your class. - So we send our result to an
OmniscientResultReceiver
inde.metanome.algorithm_integration.result_receiver
which extends all of the Algorithms`ResultReceiver
`s. Add your own, upcoming one by adding the suffix ResultReceiver to the name of your Algorithm and create the class, eg.ConditionalInclusionDependencyResultReceiver
. - Write your
ResultReceiver
interface in the same package. It should at least specify the methods shown in the example so you can receive and evaluate a result. - Add a new interface to
de.metanome.algorithm_integration.algorithm_types
which extends theAlgorithm
-Interface that you can find inde.metanome.algorithm_integration
, eg.ConditionalInclusionDependencyAlgorithm
. Define the method shown in the example to set yourResultReceiver
in the implementation.
After everything we need to use is set up, go back to your folder in metanome-algorithms
and create a class named after the abbreviation of your algorithm which implements at least your added Algorithm
-Class. Here you can implement the algorithm's logic. execute()
can be seen as the main
-method of the class and is called when performing the algorithm.
As any good programmer would, you shouldn't forget about testing your code. So, go into src/test and write your tests using the junit framework. Consider naming your tests like test<Method Name><Input><Expected Outcome>
for convenience when debugging. When done, go back to your algorithm`s pom file and ensure that you've added
<dependency> <groupId>junit</groupid> <artifactId>junit</artifactid> <version>4.12</version> <scope>test</scope> </dependency>
in the <dependencies>
-tag. If you've copied the pom file layout from the previous step, you already have it included. To run your tests, either run mvn test
in your algorithm`s root folder (eg metanome-algorithms/cid in our example) or directly run it in the IDE of your choice.
Now that we've implemented the algorithm itself, we've got to include it to Metanome's backend in order for the server to be able to execute it as well. The required steps can be divided into two parts: one that requires you to implement additional logic to your algorithm and another that extends existing constructs which are rather copy-paste-ish. For them, just use the same structure as the already existing algorithms and change the names.
For the first few points, go to the package de.metanome.backend.results_db
. As the name suggests, this package defines the database for an Algorithm Type's result which we defined earlier. Since a result is dependent from an Algorithm Type, we have to add which algorithm produces which result.
-
AlgorithmType
:
Add your Algorithm Type to the enumeration. As a convention, an item should be named as the abbreviation of your Algorithm Type in all caps, eg.CID
. -
Resulttype
:
Add your result type to the enumeration. As a convention, an item should be named as the abbreviation of your Algorithm Type in all caps, eg.CID
. -
Algorithm
:
At the beginning of the class under OUTPUT, add a protected boolean named after your Algorithm Type. In the constructorAlgorithm(String fileName, Set<Class<?>> algorithmInterfaces)
under INPUT, set that boolean by checking ifalgorithmInterfaces
contains your Algorithm Type's interface. Add a getter and setter for your boolean. To ensure correct mapping from the set to your variable, adjust the setter to look like the other ones. Additionally, add an if-statement insetAlgorithmTypeProperty(AlgorithmType algorithmType, boolean hasAlgorithmType)
. -
de.metanome.backend.algorithm_execution.AlgorithmExecutor
:
InexecuteAlgorithm(...)
add an if-statement for your Algorithm Type. -
de.metanome.backend.resources.AlgorithmResource
:
Import your Algorithm Type. Add the methodlist<YourAlgorithmTypeName>s()
and adjust the annotations.
de.metanome.backend.result_receiver
. This package is responsible for outputting an Algorithm Type's result.
-
ResultReceiver
:
Add the overloaded functionacceptResult(YourAlgorithmType result)
. -
ResultCache
:
Add the overloaded functionreceiveResult(YourAlgorithmType yourAlgorithmType)
. -
ResultCounter
:
Add the overloaded functionreceiveResult(YourAlgorithmType yourAlgorithmType)
. -
ResultPrinter
:
Add the overloaded functionreceiveResult(YourAlgorithmType yourAlgorithmType)
. -
ResultReader
:
InconvertString(...)
add an if-statement for your Algorithm Type. You can either use your own format or use JSON. Using JSON might be slower.
In the post processing, one can define additional information their Algorithm Type should collect after excution about the gotten result, eg. dependant column ratio. Our example has added a few values to show how it could look like. If you don't want any, you might want to check out all post processing classes of Matching Dependency
. If you want many, we recommend Functional Dependency
. For more information about post processing, go here.
-
de.metanome.backend.result_postprocessing.result_comparator
:
Add your own class which extendsResultComparator<YourAlgorithmTypeResult>
. Define the variables for the information you want to calculate as static final Strings. Add the required constructor and the compare method which should compare every attribute of the parameters on equality. -
de.metanome.backend.result_postprocessing.results
:
Add your own class which extendsRankingResult
. Here you specify accessors for your previously defined variables. Add an empty constructor, one which initializes your variables for an instance of your Algorithm Type and add getters and setters. Overwritingequals(...)
andhashCode()
is not required, but good practice. -
de.metanome.backend.result_postprocessing.result_analyzer
:
Add your own class which extendsResultAnalyzer<YourAlgorithmType, YourAlgorithmTypeResult>
. OverrideanalyzeResultsDataIndependent(...)
,analyzeResultsDataDependent(...)
andconvertResults(...)
. If you're not doing any analysing at all, you can do it just like in the example. If not, we recommend to look intoFunctionalDependencyResultAnalyzer
. -
de.metanome.backend.result_postprocessing.result_store
:
Add your own class which extendsResultStore<YourAlgorithmTypeResult>
. OverridegetResultComparator(...)
by creating and returning a new YourAlgorithmResultComparator from the given parameters. -
de.metanome.backend.result_postprocessing.result_ranking
:
Add your own class which extendsRanking
. Add a full constructor, overridecalculateIndependentRankings(...)
andcalculateDependentRankings(...)
. -
de.metanome.backend.result_postprocessing.ResultPostProcessor
:
Add an if-statement inanalyzeAndStoreResults(...)
. It's structure can be taken from existing Algorithm Types and adjusted for your one.
To test all the addditions you just made, we also have to extend existing test classes. For that, we first have to create an Example Algorithm for your Algorithm Type on which the tests are executed on.
- Go to
Metanome/testing_algorithms
and add a folder for your Algorithm Type. Make sure to also include it in the rootpom.xml
. - In your subdirectory, set up a new Maven Project by creating your own
pom.xml
. Its contents can mostly be the same as the example's - just make sure to adjust<artifactId>
,<name>
and<Algorithm-Bootstrap-Class>
to your Algorithm Type. - Add a
.gitignore
andpom.xml.versionsBackup
to your subdirectory. These can be copied from the example. - In
src/main
, write anExampleAlgorithm
-class, which extends your Algorithm Type's Algorithm and all the Interfaces fromde.metanome.algorithm_integration
your Algorithm Type is depended on. - In
src/test
, write anExampleAlgorithmTest
-class, which should at least test your Example Algorithm on execution and if its configuration requirements are properly set. - After that, build the Maven Project of your subdirectory.
- Go to
/target/pom.xml
and add your example algorithm in<plugin>
anddependencies
.
jar
you just added. For the tests, you should at least include the following:
-
de.metanome.backend.algorithm_execution.AlgorithmExecutorTest
:
Add a methodtestExecuteYourAlgorithmTypeAlgorithm
which tests if your Algorithm is even executed. -
de.metanome.backend.resources.AlgorithmResourceTest
:
Add a methodtestListYourAlgorithmTypeAlgorithms
which testsde.metanome.backende.resources.AlgorithmResource getAll()
. -
de.metanome.backend.result_receiver.ResultPrinterTest
:
Add a methodtestWriteYourAlgorithmType
which tests the functionality of your Algorithm Type'sResultPrinter
. - Add classes to the
de.metanome.backend.result_postprocessing
-packages if your algorithm performs post processing. Since the example doesn't, it's left out.
To Display your Algorithm Type on the website, we have to modify a few files in the Frontend. If not already done, set it up as a submodule. For that, go to src/app
. Again, most of what you have to do is copy the structure of the existing ones and adjust it to your Algorithm Type.
-
/history/history.controller.js
:
InloadExecution()
add an if-statement for your Algorithm Type and push it to$scope.content
. -
/new/new.controller.js
:
IninitializeAlgorithmList()
add a list element for your Algorithm Type toalgorithmCategoryNames
. InopenNewAlgorithm()
add a map element for your Algorithm Type toobj
. InexecuteAlgorithm()
add a string concatenation for your Algorithm Type tourl
. -
/result/result.controller.js
:
At the start of the class under VARIABLE DEFINITIONS add an element for your Algorithm Type to$scope
and define its properties. Write a methodloadYourAlgorithmType()
which you call by adding an if-statement Ininit()
. Write a methodonPageYourAlgorithmType'sAbbrevation()
. -
/result/result.html
:
Add amd-card
for your Algorithm Type to add it as a new element in the table.
After all these steps, your Algorithm Type is successfully integrated into the Metanome Project. Congrats! 🎉 All that's left to do is build the Maven project and see it appearing on the front page.