Definitely work elephant-unstable if you want to test the new functionality. Most of the activity in the main branch has been in and around the postmodern interface. The limiting factor in merging the branches is getting support for the new data store API (i.e. for btrees w/ duplicate keys) in CL-SQL and Postmodern. Robert has made some good progress on CL-SQL but we haven't had any work done on this in Postmodern yet.

I just merged out everything from the main elephant branch into unstable, so you won't be missing anything; except of course it only works for the BDB data store now.

Ian

On May 3, 2008, at 3:56 AM, Marc wrote:

Marc wrote:
Ian Eslick wrote:
Great! Actually in writing the following e-mail, I realized that this had forced me to think through a bunch of things and so I wrote a version of the functionality in associations.lisp and just checked it in.

Start playing with, reading and commenting on what's wrong with it. For example, I'd like a better API for adding/removing items from slots than overloading (setf (accessor instance) related- instance). I left a commented API proposal in the source code for you to look at.

There are still bugs that I haven't thought through that will crop up when you change classes, redefine classes, etc. Let me know what you think.
Thanks for the file and the documentation in this mail. Starting from this I'll now begin to dig into it and try to grope my way around.

As to timing: this week is somewhat busy due to a conference, but I still hope for some time in between sessions.
I fear that the delay has been much longer than anticipated --- it has been very busy ever after the conference ---, but no w I hope finally to find some time --- provided that the issue is not long obsolete.

Best regards,

Marc

P. S.: I've noticed that there have been few changes in the unstable branch lately, but many more in the stable one. Which one is the one to work on for this right now?


========================

Download the elephant-unstable branch:

darcs get http://www.common-lisp.net/project/elephant/darcs/elephant-unstable

It's probably best to spend a little time reading and experimenting, then write up a proposal so we can discuss it a bit. The support for defining association slots (but not implementing them) is already implemented in metaclasses.lisp.

The idea of an association is that instances of class A can find instances of class B that are 'associated' with it. Association relations can be undirected or directed, typically called many-to- many or 1-to-many. 1-to-many is a kind of inverse indexing and many-to-many requires a separate btree/class/table to maintain the undirected relation. Hopefully the following description will help clarify what I mean.


One-to-Many associations:

If class B has a slot that stores a single instance of A, then class A would like to have a method that returns the set of instances of B that refer to the instance of A.

If A is person and B is job, then job->owner is a reference to A and A->jobs is a method (no slot storage) that refers to an index on job->owner. The index keys are A oids.

If you look in indexed-slots.lisp, you'll get a sense of how indices work. set-valued-slots.lisp is also useful as it puts a btree in each instance's slot to store sets of objects using the pset abstraction in pset.lisp. Reading these three files should help alot to see how we use btrees and dup-btrees to maintain sets of objects and relations.


One challenge is how to specify an association implicitly in slot definitions. Ideally you want it to be on the object that you are most often going to use to add and remove relations:

(defpclass person ()
 ((jobs :accessor jobs :association (job owner))))

(defpclass job ()
 ((title :accessor title ...)
  (company :accessor company ...)))

But this means that person has to change the definition of job and that can be problematic. So you could require agreement...

(defpclass person ()
 ((jobs :accessor jobs :association (job owner)))

(defpclass job ()
 ((title ...)
  (company ...)
  (owner :accessor owner :association person)))

This means that job has a slot owner who's values are instances of the class person. This slot is also effectively indexed. A person has a method jobs which looks up the index in (job owner) and returns the list of instances of job that have the instance of A in the owner slot.


Many-to-Many:

To add many-to-many relations, any A->B relation also requires that we can find the relation from the other direction B->A. Typically this requires a special table to keep track of pairs of related objects. You can then query on either column to get the set of related objects.

many-to-many association: A<->B
(A1 B1)
(A1 B2)
(A2 B1)
(A2 B3)

(get-related assoc A1)->B1,B2
(get-related assoc B1)->A1,A2

We can simply stick with the index model and just ensure that there are indexes on both classes instead of one. When we add an element to one side, we also add it to the other. (This is what is implemented now)


Optimizations/Alternatives:

One optimization for one-to-many is to return a standard object implementing the pset protocol that just keeps a reference to the index and supports map operations over the appropriate subset of the objects in the index.

Regards,
Ian

On Mar 19, 2008, at 2:42 AM, Marc wrote:
Hi Ian,

My best guess is weeks, not months. We're hoping for April sometime, but it depends on a number of factors. Elephant is getting quite complex to test so the last few bugs can take some time.

You can speed this process up if you want to help develop and test the association facility (most of the hooks are there so it shouldn't be too hard, even if you don't fully understand the elephant internals). If not, we have plenty of new features that need tests written against them!
Since we need this feature anyway for our application, I'm quite prepared to join in the work on the association facility. Any pointer on what would be the best entry point into that task?

Best regards,

Marc

On Mar 18, 2008, at 12:50 AM, Marc wrote:

Ian Eslick wrote:
The pset is probably your best bet. Other collection objects have more performance impact. With a pset you can ask:

is X a friend of Y?  (find-item X (friends Y)) => X | nil

all people that X is friends of:

(remove-nulls
(map-class 'people (lambda (y)
                     (when (find-item X (friends Y))
                        Y))
          :collect t))

This requires walking all person objects. For larger DB's, you can build your own 'many-to-many' relation table or waiting for the next release which should do this for you.
Is there a time line (however preliminary) when this release might be
available?

(defpclass friend-relation ()
((first :accessor first :initarg :first :index t)
 (second :accessor second :initarg :second :index t)))

(defmethod add-friend-relation (x y)
(make-instance 'friend-relation :first x :second y))

(defmethod friends-of (x)
(union (mapcar #'second (get-instances-by-slot 'friend- relation 'first x)) (mapcar #'first (get-instances-by-slot 'friend-relation 'second x))))

Of course there are ways to do this more efficiently, but I think this is the idea.

Many thanks for this guidance. That does, indeed, give me an idea of the
best way forward in our application.


Best regards,

Marc



On Mar 16, 2008, at 11:06 PM, Marc wrote:

Hello!

I fear that this may be a rather stupid newbie question, but neither from the documentation nor from the mailing list posts I got an idea as to the best practice for the following type of searches. Let's use an example akin to the one in the tutorial:

(defpclass person ()
((name :accessor name :index t)
(friends :accessor friends)) ;collection with names (say as strings) of the friends of this person
)

Given a similar structure, what is the recommended way to handle queries of the type "find all persons that X is a friend of?" (i.e. queries on individual entries in slots that contain collections)? What would be the best data structure for the friends slot, assuming that the collection remains fairly stable over time (psets, lists or other collections)?

Thanks in advance for any hint!

Best regards,

Marc




_______________________________________________
elephant-devel site list
elephant-devel@common-lisp.net
http://common-lisp.net/mailman/listinfo/elephant-devel

_______________________________________________
elephant-devel site list
elephant-devel@common-lisp.net
http://common-lisp.net/mailman/listinfo/elephant-devel






_______________________________________________
elephant-devel site list
elephant-devel@common-lisp.net
http://common-lisp.net/mailman/listinfo/elephant-devel

_______________________________________________
elephant-devel site list
elephant-devel@common-lisp.net
http://common-lisp.net/mailman/listinfo/elephant-devel





_______________________________________________
elephant-devel site list
elephant-devel@common-lisp.net
http://common-lisp.net/mailman/listinfo/elephant-devel

_______________________________________________
elephant-devel site list
elephant-devel@common-lisp.net
http://common-lisp.net/mailman/listinfo/elephant-devel





_______________________________________________
elephant-devel site list
elephant-devel@common-lisp.net
http://common-lisp.net/mailman/listinfo/elephant-devel





_______________________________________________
elephant-devel site list
elephant-devel@common-lisp.net
http://common-lisp.net/mailman/listinfo/elephant-devel

_______________________________________________
elephant-devel site list
elephant-devel@common-lisp.net
http://common-lisp.net/mailman/listinfo/elephant-devel

Reply via email to