Answer 2 :
The real problem is to link body's elements together.
For this case we have only two types : muscles and bones [here, grouped in body part].
So if we begin to develop group (of bones) we certainly will be able to detail them to bones granularity.
It is obvious that add a new group of nerves will not be difficult if link model between bones and muscles is adequate.
I'm thinking in Java with OODB to give sample.
I use the OpenSource db4objects, it is also Java, possibility to use EmbeddedObjectContainer loaded with the API, no server, no DBA's problem.
Think it like a disk with useful database tools to manage complex I/O like Transparent Activation/Transparent Persistence, and other powerful tools like a manager, and it is able to migrate to huge Versant professional OODB.
Your job : work with a unique class with three fields :
package ElemBody; import java.util.HashSet; import java.util.Set; public final class ElementBody { // In true life fields are 'private' with getters and setters public int typ; // TYP_ELEM.BONES.ordinale() Indexed public String name; // indexed with UniqueKey // HashSet (and not SortedSet for optimization) Element linked public Set<ElementBody> linkedElem = new HashSet<ElementBody>(); // Print utility @Override public final String toString() { final StringBuilder sb = new StringBuilder(); sb.append(name); sb.append(" - "); for (final ElementBody el : linkedElem) { sb.append(el.name); sb.append(", "); } sb.append(linkedElem.size()); sb.append("."); return sb.toString(); } }
The main, (tedious) loading/linking data and quering :
package ElemBody; import java.io.File; import java.util.Iterator; import com.db4o.Db4oEmbedded; import com.db4o.EmbeddedObjectContainer; import com.db4o.ObjectSet; import com.db4o.config.EmbeddedConfiguration; import com.db4o.constraints.UniqueFieldValueConstraint; import com.db4o.query.Query; public class PrmBody { public enum TYP_ELEM { BONES, MUSCLES, NERVES // here, place for futur types } public static void main(final String[] args) { // one of possible db4o's configuration final EmbeddedConfiguration config = Db4oEmbedded.newConfiguration(); // Managing index and unique key config.common().objectClass(ElementBody.class).objectField("type") .indexed(true); config.common().objectClass(ElementBody.class).objectField("name") .indexed(true); config.common().add( new UniqueFieldValueConstraint(ElementBody.class, "name")); // You have also an InMemory option, here the file one // Because of name's uniqueKey option, delete for test, in true live // read before create/update new File("Q:/tmp/ElementBody.db4o").delete(); final EmbeddedObjectContainer eoc = Db4oEmbedded.openFile(config, // "ElementBody.db4o"); // in "user.home" directory "Q:/tmp/ElementBody.db4o"); // Tedious option to load database. // Use .properties ou CSV files // Create BONES for (final String s : new String[]{"Arms", "Torso Front", "Torso Back", "LowerBody"}) { final ElementBody el = new ElementBody(); el.typ = TYP_ELEM.BONES.ordinal(); el.name = s; eoc.store(el); // save new instance } // Create MUSCLES final String[] muscles = {"Biceps", "Triceps", "Forearms",// "Abs", "Chest", "Shoulders", // "Trapezius", "Lats", "Rear Shoulders", "Lower Back", // "Quads", "Hams", "Hip & Butt", "Calves"}; for (final String s : muscles) { final ElementBody el = new ElementBody(); el.typ = TYP_ELEM.MUSCLES.ordinal(); el.name = s; eoc.store(el); } // Simplified control of read type form db4o final Query queryA = eoc.query(); queryA.constrain(ElementBody.class); queryA.descend("name").constrain("Arms").equal(); final ElementBody arm = (ElementBody) queryA.execute().iterator() .next(); for (final String s : new String[]{"Biceps", "Triceps", "Forearms", "Shoulders"}) { final Query query = eoc.query(); query.constrain(ElementBody.class); query.descend("name").constrain(s).equal(); final ObjectSet<ElementBody> musT = query.execute(); musT.get(0).linkedElem.add(arm); arm.linkedElem.add(musT.get(0)); eoc.store(musT.get(0)); } eoc.store(arm); final Query queryB = eoc.query(); queryB.constrain(ElementBody.class); queryB.descend("name").constrain("Torso Front").equal(); final ElementBody tf = (ElementBody) queryB.execute().get(0); for (final String s : new String[]{"Abs", "Chest", "Shoulders"}) { final Query query = eoc.query(); query.constrain(ElementBody.class); query.descend("name").constrain(s).equal(); final ElementBody mus = (ElementBody) query.execute().get(0); mus.linkedElem.add(tf); tf.linkedElem.add(mus); eoc.store(mus); } eoc.store(tf); final Query queryC = eoc.query(); queryC.constrain(ElementBody.class); queryC.descend("name").constrain("Torso Back").equal(); final ElementBody tb = (ElementBody) queryC.execute().get(0); for (final String s : new String[]{"Trapezius", "Lats", "Rear Shoulders", "Lower Back", "Shoulders"}) { final Query query = eoc.query(); query.constrain(ElementBody.class); query.descend("name").constrain(s).equal(); final ElementBody mus = (ElementBody) query.execute().get(0); mus.linkedElem.add(tb); tb.linkedElem.add(mus); eoc.store(mus); } eoc.store(tb); eoc.commit(); // End load part // // // // Two samples of request final Query r1 = eoc.query(); r1.constrain(ElementBody.class); r1.descend("typ").constrain(TYP_ELEM.BONES.ordinal()).equal(); for (final Object obj : r1.execute()) { final ElementBody el = (ElementBody) obj; System.out.println("\n" + TYP_ELEM.BONES + "\t" + el.name); final Iterator<ElementBody> it = el.linkedElem.iterator(); while (it.hasNext()) { System.out.println("\t" + it.next()); } } final Query r2 = eoc.query(); r2.constrain(ElementBody.class); r2.descend("typ").constrain(TYP_ELEM.MUSCLES.ordinal()).equal(); r2.descend("name").constrain("Q").smaller(); r2.descend("name").orderAscending(); final ObjectSet<ElementBody> osEl = r2.execute(); System.out.println("---------------\n" + osEl.size() + " muscles in db with A to P prime letter name."); final Iterator<ElementBody> itEl = osEl.iterator(); int sumLink = 0; while (itEl.hasNext()) { final ElementBody elTmp = itEl.next(); System.out.print(elTmp.name + ", "); sumLink += elTmp.linkedElem.size(); } System.out.println("\nThose muscles have " + sumLink + " links to bones, LowerBody's ones excluded."); eoc.close(); } }
I've add “Shoulders” in two 'Torso' to show how you can feed back your links.
With samples of (SODA) query, you will be able to pick all needed groups.
Console:
BONES Arms Forearms - Arms, 1. Triceps - Arms, 1. Shoulders - Arms, Torso Back, Torso Front, 3. Biceps - Arms, 1. BONES Torso Front Abs - Torso Front, 1. Shoulders - Arms, Torso Back, Torso Front, 3. Chest - Torso Front, 1. BONES Torso Back Lower Back - Torso Back, 1. Trapezius - Torso Back, 1. Rear Shoulders - Torso Back, 1. Shoulders - Arms, Torso Back, Torso Front, 3. Lats - Torso Back, 1. BONES LowerBody --------------- 9 muscles in db with A to P prime letter name. Abs, Biceps, Calves, Chest, Forearms, Hams, Hip & Butt, Lats, Lower Back, Those muscles have 6 links to bones, LowerBody's ones excluded.
In my sense, it is not a mathematical model, but an intuitive one :
- what is the real question? → where are real objects? (do not begin with abstraction, or technical solution, if no needed, and decrypt the real problem, behind the beautiful requirements paper)
- who really works? → what is done? (take the place of the objects, then imagine how you are now represented : hum, not so good representation doesn't it?)
- who and what is really needed (a lazy developer want to verify/test less possible objects and more simple objects than an 'all home made' one)
- we manage data? → a database is needed,
- can we be more simple? → this take time, a night is generally a good elapse time
- is request the only problem for final user? → right! look him working, he is the only men able to understand what he want, here the problem : experience will show you how decrypt those 'not said but critical' things.
If all [or part] of this is already made → use it
Unless it is for highly stress usage (or OS only known by one genius) all is already written, and often well written and optimized, and secure.
Here I've used something like 'internal reverse index model' (Perhaps exists under another official name) :
Database have indexes on fields (columns for SGBDRs) as all database you know
In OODB we add list/set/BTree/.. to link an instance of an object type to another one of same type, or to another instance of a different type (but always the same instances type linked in one list).
If your project came bigger and more complex you will be able to use such methods without difficulties.
No complexity to load numerous CSV files, no real difficulties to add queries,
- One class, three fields, and basic methods (your job, already made, only add query for an object before create or update if you do not want delete database each tim - and other pitfall to avoid, listen in reference doc)
- One OODB (imported) (just configure it, add TA/TP, you can put it inMemory)
- One class for CSV file (import CsvReader)
- One class to load Csv in DB (Little job, model in PrmBody)
- Some simple classes for dedicated queries (not painfull if you understand SODA query)
- I use JSON, but take your prefered web tool for presentation (may be time eater for all public usage).
Feel free to tell us if it convenient for you.