REBOL

Relations Engine

Contents:

About
Usage
Finding a Relation
Multiple Levels
Adding Relations
Bulk Add Relations
Removing Relations
Replacing Relations
Fully Replace Relations
Two-way Relations
Errors
Examples
The Relations Object
Reference
get-relation
add-relation
remove-relation
replace-relation
relations
Future

The documentation is far from finished, but this should give you a general idea of what's going on.

About

The Relations Engine is a small collection of functions to create, lookup and maintain a structured relations object, like the one you can see below:

This can be good for relating words to a single or multiple values (one-to-one or one-to-many relations) at multiple levels and can be used as a fast search engine or a way to build intricate relationships between data.

There are only a few loose rules and so it's easy to build the set of relations you want. Therefore it's up to you to build a rule system on top of these functions in your own program.

The Relations Engine is released under the BSD License and is currently in version 0.0.2.

Usage

To start using the Relations Engine, do this:

do http://www.hmkdesign.dk/rebol/relationsengine/relations.r

and you're set to go.

GET-RELATION is the function used to get the relations for any word. The argument is the path block which is used to dive into the object.

The path block is an alternating set of words and values which is composed internally in the relation functions.

Finding a Relation

Lets say you have a customer number 45. This customer has bought from you 4 times, which means there are 4 separate invoices. In the relations object, this could be looked up as:

>> get-relation [customers 45 invoices]
== [34 46 79 124]

What happens is the following:

  1. First you ask the parser to look in the customers block in the relations object.
  2. Then the parser tries to find customer 45.
  3. If customer 45 is found, it'll see if an object is right next to it. If there is, it can contain another set of keywords, one of which can be invoices.
  4. The relation to invoices is then returned.

The returned block contains the IDs of the invoices, which can be any value as long as it isn't a word!, block! or object! type.

If a relation doesn't exist, NONE is returned.

To find which relations are made for a specific customer, you can look that up like this:

>> get-relation [customers 45]
== [invoices]

This means that customer 45 has some kind of relation to invoices.

Multiple Levels

The trick now is that you can dig even deeper. You can ask for which articles are used in invoice 124:

>> get-relation [customers 45 invoices 124 articles]
== [34 23 15 67 31]

What you can't see here, is how many there are of each article. Through the amount of freedom you have in this system, you can add an amount word to the related articles. Let's say that has already happened:

>> get-relation [customers 45 invoices 124 articles 23 amount]
== [3]

This is an example of using a value as the relation result. It doesn't have to be, since the value 3 could be a reference to some other place.

Adding Relations

To add a relation, you can traverse down a path of relations and then append a new one using the ADD-RELATION function. You could say that the customer now has bought something a 5th time and a new invoice is made. A reference needs to be made:

add-relation [customers 45 invoices 160]

This will add the invoice with ID 160 to the block.

A nice aspect of it, is that it can progress all the way down a range of unknowns, thus creating the path, if the values don't exist.

This way you could add the invoice ID, say that the ID is related to articles and that article 44 is used in the invoice all in one pass:

add-relation [customers 45 invoices 160 articles 44]

From there to adding multiple article relations, you don't need to go far:

added-articles-block: [44 23 11 2]

foreach a added-articles-block [
  add-relation [customers 45 invoices 160 articles (a)]
]

To add a new relation keyword, simply append it to your path block:

add-relation [customers 45 articles]

This could for example mean, which articles this customer has bought from you.

Bulk Add Relations

(not implemented yet)

You can add multiple relations in one pass, by using a block of values or words. This is faster than using the above loop, because the Relations Engine only needs to search for the right location once:

add-relation [
  customers 45 invoices 160 articles [44 23 11 2]
]

This also works for words:

add-relation [
  customers 45 invoices 160 [articles payments reports]]
]

You can even create multiple relations below the block. The values and words given after the block, are set for each of the words given in the block.

add-relation [
  customers 45 invoices 160 [articles payments reports] 14]
]

This also works for values:

add-relation [
  customers 45 invoices 160 articles [44 23 11 2] prices 45
]

Removing Relations

To remove a relation, use the REMOVE-RELATION function to specify the end point you wish to remove. The endpoint can be a single value or a whole tree branch.

Removing a single value:

>> remove-relation [customers 45 invoices 160 articles 44]

This will remove the relation between article 44 and invoice 160.

Removing a whole branch involves in specifying the path down to the point you wish to remove:

>> remove-relation [customers 45 invoices 160]

This will remove all article relations to invoice 160.

Replacing Relations

With REPLACE-RELATION you can replace a keyword or a single value at a specific location in the relations object. The value or keyword you want to replace, must be given as the last element in the path block.

Examples

You want to relate customer 45 to invoice 159 instead of invoice 160

>> replace-relation [customers 45 invoices 160] 159

You can also rename a branch. The contents of that branch won't be touched.

>> add-relation [storage 4 raticles] ; oops!
>> replace-relation [storage 4 raticles] 'articles ; much better!

Fully Replace Relations

(not implemented yet as this has many implications)

By using the /full refinement in REPLACE-RELATION, you can fully replace a branch in one pass.

Two-way Relations

Normally a relation is only created one way. This means that it's easy to relate from the invoice to an article, but you can't easily relate from the article to a specific invoice without doing a lot of time consuming searching. Therefore you need to create both ways manually.

There are no functions to create two-way relations at this point, but here's an example on how to create such a relation:

add-relation [customers 44 articles 23]
add-relation [articles 23 customers 44]

It's very simple and you can shape these two-way relations entirely yourself.

Errors

If you accidentally use non-word values on odd positions in the path block, GET-RELATION will return FALSE. This depends on if the path is valid up to that position. If it's not, NONE is returned.

The same counts for ADD-RELATION, REMOVE-RELATION and REPLACE-RELATION

Examples

You can also use strings, URLs, filenames, etc. A few examples:

add-relation [
  pages "Frontpage"
  links "REBOL Manual"
  url http://www.rebol.com/docs/manual.html
]

A query could then be:

get-relation [pages "Frontpage" links "REBOL Manual" url]
== [http://www.rebol.com/docs/manual.html]

Or:

get-relation [pages "Frontpage" links]
== ["REBOL Manual" "Downloads" "License Page" "About REBOL"]

To get the URLs for all those links (not implemented yet):

get-relation/each [pages "Frontpage" links] 'url
== [
  http://www.rebol.com/docs/manual.html
  http://www.rebol.com/downloads.html
  http://www.rebol.com/license.html
  http://www.rebol.com/about.html
]

To pair the URLs with the link strings (not implemented yet):

get-relation/each/pair [pages "Frontpage" links] 'url
== [
  "REBOL Manual" http://www.rebol.com/docs/manual.html
  "Downloads" http://www.rebol.com/downloads.html
  "License Page" http://www.rebol.com/license.html
  "About REBOL" http://www.rebol.com/about.html
]

The Relations Object

The relations object is entirely processed internally, so you don't need to worry about it, except be aware of its existence. The Relations Object is stored in RELATIONS. For now that is the quick and dirty solution.

The relations object is constructed like this:

make object! [
  <word1>: [
    <id2> make object! [
      <word2>: [<id4> <id5>]
    ]
    <id3> make object! [
      <word3>: [
        <id6> make object! [
          <word4>: [<id7>]
        ]
      ]
    ]
    <id4> make object! [
      <word5>: [<id8> <id9>]
    ]
  ]
  <word6>: [<id10>]
]

Each object contains a set of associative words, which all link to a block, which can contain values. Each of these values can be linked to another object, but they don't have to be.

Reference

get-relation

Function to parse the relation object and search for the values specified in the path block.

 rel-objRelations Object to get data from
 path blockBlock with path description
 /pairWorks only with the /each refinement
 /eachSelect a word to get for each of the block values
 wordWord to get in the child object

add-relation

Function to add a relation or a branch of relations.

 path blockBlock with path description

remove-relation

Function to remove a relation or a branch of relations.

 path blockBlock with path description

replace-relation

Function to replace a relation or rename a branch in the relations object.

 path blockBlock with path description with the element to be replaced/renamed as the last.
 newNew keyword or value

relations

Object which contains all relations. Used internally to manage relations. You shouldn't need to touch it, except, don't overwrite it. :-)

Future

  • Finish functions as mentioned in the docs
  • Finish docs
  • Maybe put the whole thing inside an object, so multiple relations objects can be maintained.
MakeDoc2 by REBOL - 3-Feb-2006