Search code examples
titantinkerpop3janusgraph

Indexing fails on enabling force index in Titan/Janus


I've written a JUnit Test to check against the generate-modern.groovy graph if marko exists.
My gremlin query being

"g.V().has('name','marko')";

As you can see in the generate-modern.groovy file that indexing is already applied on the name property of the person. I later made the following

query.force-index=true

property true in the dynamodb.properties file which blocks whole graph scan thereby making indexing mandatory. However it throws me the following exception

org.janusgraph.core.JanusGraphException: Could not find a suitable index to answer graph query and graph scans are disabled: [(name = marko)]:VERTEX

The above exception is raised from the following StandardJanusGraphTx class's method

    @Override
    public Iterator<JanusGraphElement> execute(final GraphCentricQuery query, final JointIndexQuery indexQuery, final Object exeInfo, final QueryProfiler profiler) {
        Iterator<JanusGraphElement> iter;
        if (!indexQuery.isEmpty()) {
            List<QueryUtil.IndexCall<Object>> retrievals = new ArrayList<QueryUtil.IndexCall<Object>>();
            for (int i = 0; i < indexQuery.size(); i++) {
                final JointIndexQuery.Subquery subquery = indexQuery.getQuery(i);

                retrievals.add(new QueryUtil.IndexCall<Object>() {
                    @Override
                    public Collection<Object> call(int limit) {
                        final JointIndexQuery.Subquery adjustedQuery = subquery.updateLimit(limit);
                        try {
                            return indexCache.get(adjustedQuery, new Callable<List<Object>>() {
                                @Override
                                public List<Object> call() throws Exception {
                                    return QueryProfiler.profile(subquery.getProfiler(), adjustedQuery, q -> indexSerializer.query(q, txHandle));
                                }
                            });
                        } catch (Exception e) {
                            throw new JanusGraphException("Could not call index", e.getCause());
                        }
                    }
                });
            }


            List<Object> resultSet = QueryUtil.processIntersectingRetrievals(retrievals, indexQuery.getLimit());
            iter = com.google.common.collect.Iterators.transform(resultSet.iterator(), getConversionFunction(query.getResultType()));
        } else {
            if (config.hasForceIndexUsage()) throw new JanusGraphException("Could not find a suitable index to answer graph query and graph scans are disabled: " + query);
            log.warn("Query requires iterating over all vertices [{}]. For better performance, use indexes", query.getCondition());

            QueryProfiler sub = profiler.addNested("scan");
            sub.setAnnotation(QueryProfiler.QUERY_ANNOTATION,indexQuery);
            sub.setAnnotation(QueryProfiler.FULLSCAN_ANNOTATION,true);
            sub.setAnnotation(QueryProfiler.CONDITION_ANNOTATION,query.getResultType());

            switch (query.getResultType()) {
                case VERTEX:
                    return (Iterator) getVertices().iterator();

                case EDGE:
                    return (Iterator) getEdges().iterator();

                case PROPERTY:
                    return new VertexCentricEdgeIterable(getInternalVertices(),RelationCategory.PROPERTY).iterator();

                default:
                    throw new IllegalArgumentException("Unexpected type: " + query.getResultType());
            }
        }

        return iter;
    }

};

As you can observe from the method that the exception is raised when the JointIndexQuery object is empty(arrayList being empty) and force index is true.
The problem is why the list is empty? when we have specified the indexing query against the name property in the generate-modern.groovy while querying from a JUnit Test.This works fine meaning the list is not empty when the same data is being preloaded into the gremlin server with the same file.


Solution

  • The personByName index definition uses a label constraint.

    def personByName = mgmt.buildIndex("personByName", Vertex.class).addKey(name).indexOnly(person).buildCompositeIndex()
    

    In order to take advantage of that index, you must use the label and the property. For example:

    g.V().has('person', 'name', 'marko')
    

    You can read more about this in the JanusGraph documentation http://docs.janusgraph.org/latest/indexes.html#_label_constraint