Adding index schema

Adding index database schema.

All index schema is based on previously created properties and vertex labels and added to existing schema with add().

Procedure

Materialized index

  1. Create a materialized view index for a global index:
    schema.vertexLabel('person').index('byName').materialized().by('name').add()

    Identify the vertex label and property key for the index, in the vertexLabel() and by() steps, respectively. In the index() step, name the index. The materialized() step identifies the index as a materialized view index.

  2. Create a materialized view for an edge index. Edges indexes are vertex-centric to a particular vertex label. For instance, the example below indexes anything that a reviewer rates.
    schema.vertexLabel('person').index('ratedByStars').outE('reviewed').
      by('stars').ifNotExists().add()
    Identify the vertex label and property keys for the index, in the vertexLabel() and by() steps, respectively. In the index() step, name the index. The outE() step is used to define the direction of the edge.
    Note: For edge and property indexes, the materialized() step is not included, because all edge indexes are created as materialized views.
  3. Create an edge index that indexes both incoming and outgoing edges:
    schema.vertexLabel('person').index('ratedByStars').bothE('reviewed').
      by('stars').ifNotExists().add()

    Identify the vertex label and property keys for the index, in the vertexLabel() and by() steps, respectively. In the index() step, name the index. The bothE() step is used to define the direction of the edge.

  4. Create a materialized view for a property index:
    schema.vertexLabel('person').index('byStartYear').
      property('country').by('startYear').add()
    Identify the vertex label for the index in the vertexLabel() step. In the index() step, name the index. The property() and by() steps identify the property key and its meta-property, respectively.
    Note: For edge and property indexes, the materialized() step is not included, because all edge indexes are created as materialized views.

Search index

  1. Most commonly, a search index is created with multiple columns, chained together as multiple by() steps in one statement:
    schema.vertexLabel('recipe').index('search').search().by('name').by('instructions').add()

    Identify the vertex label and property keys for the index, in the vertexLabel() and by() steps, respectively. In the index() step, name the index search; only this naming convention can be used. The search() step identifies the index as a search index. Since no option is specified, the property will be indexed both as Text and String.

    Tip: Only one search index can be created per vertex label.

    Textual search indexes are by default indexed in both tokenized (TextField) and non-tokenized (StrField) forms. This means that all textual predicates (token, tokenPrefix, tokenRegex, eq, neq, regex, prefix) will be usable with all textual vertex properties indexed. Practically, search indexes should be created using the asString() method only in cases where there is absolutely no use for tokenization and text analysis, such as for inventory categories (silverware, shoes, clothing). The asText() method is used if searching tokenized text, such as long multi-sentence descriptions. The query optimizer will choose whether to use analyzed or non-analyzed indexing based on the textual predicate used.

  2. Create a search index with only one property key indexed as Text():
    schema.vertexLabel('recipe').index('search').search().by('instructions').asText().add()
  3. A search index can specify the string indexing option along with the text indexing option:
    schema.vertexLabel('recipe').index('search').search().by('instructions').asString().by('name').asText().add()

    This example specifically states how the search index will be constructed for each property.

  4. Search indexes can also include non-text data types:
    schema.vertexLabel('recipe').index('search').search().by('year').by('name').asString().add()
    Data types other than text are inferred from the schema and DSE Search uses a comparable Solr data type. In this example, year is indexed as an integer.
    CAUTION: The Decimal data type will index as a SolrDecimalStrField. Use Int, Long, Float, or Double to ensure that the Solr data types are used for sorting and range querying.
  5. Create a search index for geospatial data:
    schema.propertyKey("coordinates").Point().single().create()
    schema.propertyKey("name").Text().single().create()
    
    schema.vertexLabel("place").properties("coordinates", "name").create()
    schema.vertexLabel("place").index("search").search().by("name").asText().by("coordinates").add()
    

    In this example, the property coordinates is a point defining a longitude and latitude. The search index includes coordinates without a qualifying asText() or asString() method. See Geospatial Schema for additional information.

  6. While DSE Graph natively supports geospatial searches, performing them without a Search index does not scale as the number of vertices in the graph increases. Doing such queries without a search index results in very inefficient query performance because full scans are required. DSE Search indexes can index points and linestrings, but not polygons.
    //SEARCH INDEX ONLY WORKS FOR POINT AND LINESTRING
    schema.vertexLabel('location').index('search').search().by('point').add()
    schema.vertexLabel('lineLocation').index('search').search().by('line').add()
    Without a search index, spatial queries always return exact results. DSE Search indexes, however, can trade off performance for accuracy.
    Note: A point of confusion can occur if the same geospatial query is run with or without a DSE Search index. Without a search index, geospatial queries always return exact results. DSE Search indexes, however, trade off write performance and index size for query accuracy with two tunable parameters, maxDistErr (default: 0.000009) and distErrPct (default: 0.025). Inconsistent results in these two cases are due to the distance calculation algorithm variation of the default values of these parameters. DSE Graph can pass values for these two parameters when creating the search index. Change maxDistErr in withError(maxDistErr, distErrPct) to 0.0 to force both index-backed and non-index-backed queries to yield the same value:
    schema.vertexLabel('location').index('search').search().by('point').withError(0.000009,0.0).add()
    
  7. Create a search index for timestamp data:
    schema. propertyKey('review_ts).Timestamp().create()
    schema.propertyKey('name').Text().create()
    schema.vertexLabel('rating').properties('name', 'review_ts').create()
    schema.vertexLabel('rating').index('search').search().by('name','review_ts').add()

Secondary index

  1. Create a global index as a secondary index:
    schema.vertexLabel('recipe').index('byRecipe').secondary().by('name').add()

    Identify the vertex label and property key for the index, in the vertexLabel() and by() steps, respectively. In the index() step, name the index. The secondary() step identifies the index as a secondary index.

Example

The edge labels used for the DSE QuickStart example used throughout the documentation:
// ********
// VERTEX INDEX
// ********
// SYNTAX:
// index('index_name').
//    [secondary() | materialized() | search()].
//    by('propertykey_name').
//    [ asText() | asString() ].
//    add()
// ********

schema.vertexLabel('person').index('byName').materialized().by('name').add()
schema.vertexLabel('meal_item').index('byName').materialized().by('name').add()
schema.vertexLabel('ingredient').index('byName').materialized().by('name').add()
//schema.vertexLabel('recipe').index('byCuisine').materialized().by('cuisine').add()
//schema.vertexLabel('book').index('byName').materialized().by('name').add()

schema.vertexLabel('meal').index('byType').secondary().by('type').add()

schema.vertexLabel('recipe').index('search').search().
  by('instructions').by('name').by('cuisine').add()
schema.vertexLabel('book').index('search').search().
  by('name').by('publishYear').add()
schema.vertexLabel('location').index('search').search().
  by('geoPoint').withError(0.000009,0.0).add()
schema.vertexLabel('store').index('search').search().by('name').add()
schema.vertexLabel('home').index('search').search().by('name').add()
schema.vertexLabel('fridgeSensor').index('search').search().
  by('cityId').by('sensorId').by('name').add()

// ********
// EDGE INDEX
// ********
// SYNTAX:
// index('index_name').
//    [outE('edgeLabel') | inE('edgeLabel') ].
//    by('propertykey_name').
//    add()
// ********

schema.vertexLabel('recipe').index('byStars').inE('reviewed').
  by('stars').ifNotExists().add()
schema.vertexLabel('person').index('ratedByStars').outE('reviewed').
  by('stars').ifNotExists().add()
schema.vertexLabel('person').index('ratedByDate').outE('reviewed').
  by('year').ifNotExists().add()
schema.vertexLabel('person').index('ratedByComments').outE('reviewed').
  by('comment').ifNotExists().add()
schema.vertexLabel('recipe').index('byPersonOrRecipe').bothE('created').
  by('createDate').ifNotExists().add()

// ********
// PROPERTY INDEX using meta-property 'livedIn'
// ********
// SYNTAX:
// index('index_name').
//    property('propertykey_name').
//    by('meta-propertykey_name').
//    add()
// ********

schema.vertexLabel('person').index('byStartYear').
  property('country').by('startYear').add()
schema.vertexLabel('person').index('byEndYear').
  property('country').by('endYear').add()