Need help with wordnet?
Click the “chat” button below for chat support from the developer who created it, or find similar developers for support.

About the developer

151 Stars 21 Forks 252 Commits 14 Opened issues


Lexical database of any language

Services available


Need anything else?

Contributors list


Open Source browsing application for Wordnet database


  • Ruby 2.1.10
  • PostgreSQL 9
  • Neo4J 2
  • MySQL (for WordnetSQL import)


# Load wordnet database to MySQL

rbenv install 2.1.10 rbenv use 2.1.10 bundle install

bin/rake db:create db:migrate bin/rake wordnet:import

Ubuntu 12.04 deployment


  • Create hosting account (e.g. digitalocean)
  • Create user with sudo permissions
  • Remember to
    your public key to this new user account
  • Add your public key to
  • Ensure ansible is installed on your machine
  • Run
    bin/setup-host [email protected]:PORT
    command to setup your server. It installs:
    • common tools
    • ruby, java
    • mysql, postgresql, neo4j
    • deployment framework
  • ssh [email protected] -p PORT
    and run
  • download mysql database to server
  • import database to mysql via
    mysql -D wordnet < wordnet.sql
  • go to current deployment location (cd production/current) and run:
    • RAILS_ENV=production bin/rake wordnet:import
      (imports mysql to postgresql)
    • RAILS_ENV=production bin/rake wordnet:export
      (exports postgresql to neo4j)
    • RAILS_ENV=production bin/rake wordnet:translations
      (generates translations)
    • RAILS_ENV=production bin/rake wordnet:stats
      (generates statistics)
  • to change url prefix of application:
    • add
      file in application's deployment directory
    • touch tmp/restart.txt to restart an application

Project overview

Słowosieć is a Polish equivalent of Princeton Wordnet, a lexical database of word senses and relations between them.

The purpose of this document is to describe a successful effort of making the web interface of Polish Wordnet more performant and user-friendly. In particular we'll elaborate on developed architecture, used components, and database designs.

The front-end and back-end of application were rebuilt from scratch. As as result the browsing latency dropped from 30 seconds in some cases to 110ms on average.


Following decisions has been made:

  • Data is stored in normalised form using relational database
  • Data is indexed and queried using graph database
  • Data is rendered on client-side using templates
  • Data is loaded through a well-crafted API endpoint

Given multiple issues with MySQL database and performance issues with handling UUIDs, the PostgreSQL were chosen as relational database backend. This has an additional advantage of storing data in Hstore and Array types (where sensible), avoiding unnecessary

statements for data retrieval.

Neo4J has been chosen as relational database backend. The main reasons included being open-source, mature, and reliable graph store. Neo4J is one of the few graph databases providing declarative way of querying data, using Cypher language (similar in some ways to SQL).

On front-end an Angular.js framework is used. It is relatively new, but popular product developed and maintained by Google. It allows for easy decoupling of application logic and template rendering using unique concepts of directives, services, and controllers.

Rails 4 web-framework is used for both API endpoint, and serving front-end. Rails is mature software, allowing for robust development of modern web applications. Made in Ruby, allows us to use use tens of thousands of Ruby Gems, significantly boosting the development.

API allows for disjoint development of front-end and back-end.

Other technologies used

Experience made us choose following set of tool for application development:

  • CoffeeScript replacing plain JavaScript
  • SASS replacing plain CSS stylesheets
  • SLIM for rendering front-end HTML markup


  • Lexeme - unit of lexical meaning that exists regardless of the number of inflectional endings it may have or the number of words it may contain (e.g. run, ran, runs)
  • Lemma - particular form of a lexeme that is chosen by convention to represent a canonical form of a lexeme (e.g. run)
  • Sense - a Lexeme associated with particular meaning. Each Lexeme can have multiple Senses. In Wordnet each Sense is associated with number to easily distinguish (e.g. I can write
    run 4
    meaning an unbroken series of events, or
    run 5
    meaning the act of running)
  • Synset - a set of Senses (not Lexemes) with similar meaning, i.e. synonyms (e.g.
    run 2
    forms Synset with following Senses:
    bunk 3
    escape 6
    , turn
    tail 1
  • Sense Relation - a relationship between two Senses, i.e. relationship between two particular meanings of words (e.g.
    big 1
    is antonym of
    little 1
  • Synset Relation - a relationship between two Synsets, i.e. relationship between two groups of Senses (e.g.
    Synset { act 10, play 25 }
    is hyponym of
    Synset { overact 1, overplay 1 }
  • Relation Type - each SenseRelation and SynsetRelation has its type, it can be among others: antonym, hyponym, hyperonym, meronym, ...

In summary: Each Lexeme is represented by Lemma. Each Lexeme has multiple Senses. Each Sense forms Synset with other Senses. Each Sense can be in SenseRelation to other Senses. Each Synset can be in SynsetRelation to other Synsets. Each Relation has its own RelationType.

Above concepts of Wordnet are modelled in application in following way:

Class Diagram

Relational Database

Introducing Relational Database as primary store had two purposes: 1. Reliably and economically storing data in normalised form 2. Ability to use de-normalised graph database as index

The data is imported to normalised form from Polish Wordnet, but the process allows for importing arbitrary Wordnet-alike database.

Non-conventionally the primary keys of database tables are UUIDs, instead of auto-incrementing values. It has few advantages: - Plays well with graph databases, each node has its own unique ID - UUIDs for records can be generated by application code what makes inserting interconnected data into the database easier & performant. - Makes replication of relational database trivial - Allows for easy merging of two databases with same schema

The overall schema closely reassembles concepts described earlier:


  • id
    : The UUID identifier
  • synset_id
    : The UUID of connected Synset
  • external_id
    : The ID from external database, used for importing
  • lemma
    : The lemma of Lexeme that Sense belongs to (e.g. car)
  • sense_index
    : The index of sense in context of its Synset (e.g. 1)
  • comment
    : The short comment, used in UI (e.g. transporting machine)
  • language
    : Currently can be
  • part_of_speech
    : The part of speech of Sense (noun etc.)
  • domain_id
    : The ID of the Domain of Sense (not used yet)


  • id
    : The UUID identifier
  • external_id
    : The ID from external database, used for importing
  • comment
    : The short comment by Słowosieć, used in UI
  • definition
    : The short comment by Princeton Wordnet, used in UI
  • examples
    : The examples of usage of synset from Princeton Wordnet


  • name
    : Name of the relation
  • reverse_relation
    : Name of reverse relation (see: normalisation)
  • parent_id
    : Name of parent RelationType (inheritance-like)
  • priority
    : It is used for sorting relation types in UI (lower-better)
  • description
    : Description of the relation (not used yet)

sense_relations and synset_relations

  • parent_id
    : UUID of base sense (or synset)
  • child_id
    : UUID of of related sense (or synset)
  • relation_id
    : UUID of relation in which child is toward parent (e.g. UUID hyponymy relation means child is hyponym of parent)

Normalisation of Relations

Imported relations are normalised in few ways:

  1. For reverse relation types we leave only one relation type (by convention the one where where are more children than parents, e.g. hyponymes, not hyperonymes).
  2. The name of removed reverse relation is assigned to reverse_name
  3. Name and reverse_name are in plural form for for UI purposes
  4. Even name has it’s parent, the name describes full relation type name (for example “Meronymes (place)”, not “place”)


Graph Database

Graph Database Graph database has slightly different structure than relational database. Most importantly Sense and Synset nodes don’t contain any data except their IDs. The relationships of type

exist only between Synset and Senses. All data displayed in UI columns is hold in Data nodes.

Each Synset and each Sense is represented by connected Data node in UI.

Data node holds following data from Sense model: * lemma * senseindex * comment * language * partofspeech * domainid

Importing data from external Wordnets

Wordnet uses internal, normalised representation of database. The normalised structure is defined in Relational Database section.

The data mapping is done by 5 classes inherited from Importer class:

  • WordnetPl::RelationType
  • WordnetPl::Sense
  • WordnetPl::Synset
  • WordnetPl::SenseRelation
  • WordnetPl::SynsetRelation

Each class is responsible for importing data to corresponding models.

Importer class processes data in batches for performance reasons. It handles progress bar rendering, parallelising import process, and synchronising writes. It expects following methods to be defined in descendants:

  • total_count
    : The total count of items to be imported
  • load_entities(limit, offset)
    : This method should load
    records from external database with given
    and return hash consumed later by
  • process_entities!(entities)
    : This method is responsible for processing data returned from
    and passing them to
    method described below

persist_entities!(table_name, collection, unique_attributes)
uses Upsert method to insert or update data in database in performant way. It accepts table in database where the record should be inserted/updated, the actual
of records as array of hashes where keys are column names (see relational database schema) and values are row values. The
is an array of column names that upsert method will use for selecting data to merge (usually “id”, but can be for example
[“parent_id”, “child_id”]
for relations.

Import process can be triggered by issuing command:

bin/rake wordnet:import

The source database defaults to

mysql2://[email protected]/wordnet
, but you can change it by passing
environment variable.

Exporting to Neo4J index

The same way importer classes inherit from Importer, exporter classes inherit from Exporter. The are only 4 exporter classes:

  • Neo4J::Sense
  • Neo4J::Synset
  • Neo4J::SenseRelation
  • Neo4J::SynsetRelation

Each exporter is supposed to define 2 methods:

  • export_index!
    : that ensures at the beginning of export that proper indexes are present in Neo4J database
  • process_batch(entities)
    : method that accepts array of entity hashes, just like
    and returns array of queries to execute in batch request by Neography gem.

Export process can be triggered by issuing command:

bin/rake wordnet:export

The destination defaults to
, but you can change it by passing
environment variable.


Application is supposed to be run on at least 3 servers:

  1. Application server
  2. PostgreSQL server
  3. Neo4J server

On application server the Rails application should be deployed, using any method. At least Node.js, Ruby 2.0, and development libraries of Postgresql and Mysql are required to be installed on system.

The addresses of PostgreSQL database and Neo4J database are passed by

environment variable, and database information is configured in

The assets need to be precompiled before deploying app on production:

RAILS_ENV=production bin/rake assets:precompile

The server can be started by hand with:

RAILS_ENV=production bin/rails server --port 80

Or by tool you choose (Capistrano or other).


Wordnet is released under the MIT License.

We use cookies. If you continue to browse the site, you agree to the use of cookies. For more information on our use of cookies please see our Privacy Policy.