2

I am trying use document collection for fast lookup, sample document document Person {

...
groups: ["admin", "user", "godmode"],
contacts: [
   {
     label: "main office",
     items: [
        { type: "phone", value: '333444222' },
        { type: "phone", value: '555222555' },
        { type: "email", value: '[email protected]' }
     ]
   }
]
...
}
  1. Create Hash index for "groups" field

    Query: For P in Person FILTER "admin" IN P.groups RETURN P Result: Working, BUT No index used via explain query Question: How use queries with arrays filter and indexes ? performance is main factor

  2. Create Hash index for "contacts[].items[].value"

    Query: For P in Person FILTER "333444222" == P.contacts[*].items[*].value RETURN P Result: Double usage of wildcard not supported?? Index not used, query empty Question: How organize fast lookup with for this structure with indexes ?

P.S. also tried MATCHES function, multi lever for-in, hash indexed for arrays never used ArangoDB version 2.6.8

2 Answers 2

3

Indexes can be used from ArangoDB version 2.8 on. For the first query (FILTER "admin" IN p.groups), an array hash index on field groups[*] will work:

db._create("persons");
db.persons.insert(personDateFromOriginalExample);
db.persons.ensureIndex({ type: "hash", fields: [ "groups[*]" ] });

This type of index does not exist in versions prior to 2.8. With an array index in place, the query will produce the following execution plan (showing that the index is actually used):

Execution plan:
 Id   NodeType          Est.   Comment
  1   SingletonNode        1   * ROOT
  6   IndexNode            1     - FOR p IN persons   /* hash index scan */
  3   CalculationNode      1       - LET #1 = "admin" in p.`groups`   /* simple expression */   /* collections used: p : persons */
  4   FilterNode           1       - FILTER #1
  5   ReturnNode           1       - RETURN p

Indexes used:
 By   Type   Collection   Unique   Sparse   Selectivity   Fields            Ranges
  6   hash   persons      false    false       100.00 %   [ `groups[*]` ]   "admin" in p.`groups`

The second query will not be supported by array indexes, as it contains multiple levels of nesting. The array indexes in 2.8 are restricted to one level, e.g. groups[*] or contacts[*].label will work, but not groups[*].items[*].value.

Sign up to request clarification or add additional context in comments.

Comments

2

about 1.) this is Work-in-progress and will be included in one of the next releases (most likely 2.8). We have not yet decided about the AQL syntax to retrieve the array, but FILTER "admin" IN P.groups is among the most likely ones.

about 2.) having implemented 1. this will work out of the box as well, the index will be able to cover several depths of nesting.

Neither of the above can be properly indexed in the current release (2.6)

The only alternative i can offer is to externalize the values and use edges instead of arrays. In your code the data would be the following (in arangosh). I used fixed _key values for simplicity, works without them as well:

db._create("groups"); // saves the group elements
db._create("contacts"); // saves the contact elements
db._ensureHashIndex("value") // Index on contacts.value
db._create("Person"); // You already have this
db._createEdgeCollection("isInGroup"); // Save relation group -> person
db._createEdgeCollection("hasContact"); // Save relation item -> person
db.Person.save({_key: "user"}) // The remainder of the object you posted
// Now the items
db.contacts.save({_key:"phone1", type: "phone", value: '333444222' });
db.contacts.save({_key:"phone2", type: "phone", value: '555222555' });
db.contacts.save({_key:"mail1", type: "email", value: '[email protected]'});
// And the groups
db.groups.save({_key:"admin"});
db.groups.save({_key:"user"});
db.groups.save({_key:"godmode"});

// Finally the relations
db.hasContact.save({"contacts/phone1", "Person/user", {label: "main office"});
db.hasContact.save({"contacts/phone2", "Person/user", {label: "main office"});
db.hasContact.save({"contacts/mail1", "Person/user", {label: "main office"});
db.isInGroup.save("groups/admin", "Person/user", {});
db.isInGroup.save("groups/godmode", "Person/user", {});
db.isInGroup.save("groups/user", "Person/user", {});

Now you can execute the following queries:

  1. Fetch all admins:

    RETURN NEIGHBORS(groups, isInGroup, "admin")

  2. Get all users having a contact with value 333444222:

    FOR x IN contacts FILTER x.value == "333444222" RETURN NEIGHBORS(contacts, hasContact, x)

1 Comment

Big thanks! mchacki Question 1 - requires at every step, I will use compare asis and wait impatiently for 2.8 Question 2 - The decision to transfer contacts in a very complicated modification of the data, all the same in a separate table copy contact = owner to quickly lookup. Good news after upgrade to 2.7, this AQL: For P in Person FILTER "333 444 222" pieces P.contacts []. Items []. Value P RETURN now works! Maybe hash index in 2.8 will be used for this query too :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.