Weβre overhauling Dgraphβs docs to make them clearer and more approachable. If
you notice any issues during this transition or have suggestions, please
let us know.
The @search
directive tells Dgraph what search to build into your GraphQL API.
When a type contains an @search
directive, Dgraph constructs a search input
type and a query in the GraphQL Query
type. For example, if the schema
contains
then Dgraph constructs a queryPost
GraphQL query for querying posts. The
@search
directives in the Post
type control how Dgraph builds indexes and
what kinds of search it builds into queryPost
. If the type contains
type Post {
...
datePublished: DateTime @search
}
then itβs possible to filter posts with a date-time search like:
query {
queryPost(filter: { datePublished: { ge: "2020-06-15" }}) {
...
}
}
If the type tells Dgraph to build search capability based on a term (word) index
for the title
field
type Post {
...
title: String @search(by: [term])
}
then, the generated GraphQL API will allow search by terms in the title.
query {
queryPost(filter: { title: { anyofterms: "GraphQL" }}) {
...
}
}
Dgraph also builds search into the fields of each type, so searching is
available at deep levels in a query. For example, if the schema contained these
types
type Post {
...
title: String @search(by: [term])
}
type Author {
name: String @search(by: [hash])
posts: [Post]
}
then Dgraph builds GraphQL search such that a query can, for example, find an
author by name (from the hash search on name
) and return only their posts that
contain the term βGraphQLβ.
queryAuthor(filter: { name: { eq: "Diggy" } } ) {
}
}
Dgraph can build search types with the ability to search between a range. For
example, with the preceding Post type with the datePublished
field, a query
can find publish dates within a range.
query {
queryPost(filter: { datePublished: { between: { min: "2020-06-15", max: "2020-06-16" }}}) {
...
}
}
Dgraph can also build GraphQL search ability to find match a value from a list.
For example with the preceding Author type with the name field, a query can
return the Authors that match a list
queryAuthor(filter: { name: { in: ["Diggy", "Jarvis"] } } ) {
...
}
Thereβs different search possible for each type as explained below.
Int, float and dateTime
argument | constructed filter |
---|
none | lt , le , eq , in , between , ge , and gt |
Search for fields of types Int
, Float
and dateTime
is enabled by adding
@search
to the field with no arguments. For example, if a schema contains:
type Post {
...
numLikes: Int @search
}
Dgraph generates search into the API for numLikes
in two ways: a query for
posts and field search on any post list.
A field queryPost
is added to the Query
type of the schema.
type Query {
...
queryPost(filter: PostFilter, order: PostOrder, first: Int, offset: Int): [Post]
}
PostFilter
will contain less than lt
, less than or equal to le
, equal
eq
, in list in
, between range between
, greater than or equal to ge
, and
greater than gt
search on numLikes
. Allowing for example:
query {
queryPost(filter: { numLikes: { gt: 50 }}) {
...
}
}
Also, any field with a type of list of posts has search options added to it. For
example, if the input schema also contained:
type Author {
...
posts: [Post]
}
Dgraph would insert search into posts
, with
type Author {
...
posts(filter: PostFilter, order: PostOrder, first: Int, offset: Int): [Post]
}
That allows search within the GraphQL query. For example, to find Diggyβs posts
with more than 50 likes.
queryAuthor(filter: { name: { eq: "Diggy" } } ) {
...
posts(filter: { numLikes: { gt: 50 }}) {
title
text
}
}
dateTime
argument | constructed filters |
---|
year , month , day , or hour | lt , le , eq , in , between , ge , and gt |
As well as @search
with no arguments, DateTime
also allows specifying how
the search index should be built: by year, month, day or hour. @search
defaults to year, but once you understand your data and query patterns, you
might want to changes that like @search(by: [day])
.
Boolean fields
argument | constructed filter |
---|
none | true and false |
Boolean fields can only be tested for true
or false
. If
isPublished: Boolean @search
is in the schema, then the search allows
filter: { isPublished: true }
and
filter: { isPublished: false }
Strings allow a wider variety of search options than other types. For strings,
you have the following options as arguments to @search
.
argument | constructed searches |
---|
hash | eq and in |
exact | lt , le , eq , in , between , ge , and gt (lexicographically) |
regexp | regexp (regular expressions) |
term | allofterms and anyofterms |
fulltext | alloftext and anyoftext |
ngram | ngram |
- Schema rule:
hash
and exact
canβt be used together.
String exact and hash search
Exact and hash search has the standard lexicographic meaning.
query {
queryAuthor(filter: { name: { eq: "Diggy" } }) { ... }
}
And for exact search
query {
queryAuthor(filter: { name: { gt: "Diggy" } }) { ... }
}
to find users with names lexicographically after βDiggy.β
String regular expression search
Search by regular expression requires bracketing the expression with /
and
/
. For example, query for βDiggyβ and anyone else with βiggyβ in their name:
query {
queryAuthor(filter: { name: { regexp: "/.*iggy.*/" } }) { ... }
}
String term and fulltext search
If the schema has
type Post {
title: String @search(by: [term])
text: String @search(by: [fulltext])
...
}
then
query {
queryPost(filter: { title: { `allofterms: "GraphQL tutorial"` } } ) { ... }
}
anyofterms: "GraphQL tutorial"
would match posts with either βGraphQLβ or
example, to find posts that talk about fantastic GraphQL tutorials:
query {
queryPost(filter: { title: { `alloftext: "fantastic GraphQL tutorials"` } } ) { ... }
}
String ngram search
The ngram
index tokenizes a string into contiguous sequences of n words, with
support for stop word removal and stemming. N-gram search matches if the indexed
string contains the given sequence of terms.
If the schema has
type Post {
title: String @search(by: [ngram])
...
}
then
query {
queryPost(filter: { title: { ngram: "quick brown fox" } } ) { ... }
}
will match all posts that contain the contiguous sequence βquick brown foxβ in
the title.
Strings with multiple searches
It is possible to add multiple string indexes to a field. For example to search
for authors by eq
and regular expressions, add both options to the type
definition, as follows.
type Author {
...
name: String! @search(by: [hash, regexp])
}
argument | constructed searches |
---|
none | eq and in |
hash | eq and in |
exact | lt , le , eq , in , between , ge , and gt (lexicographically) |
regexp | regexp (regular expressions) |
enum fields are serialized in Dgraph as strings. @search
with no arguments is
the same as @search(by: [hash])
and provides eq
and in
searches. Also
available for enums are exact
and regexp
. For hash and exact search on
enums, the literal enum value, without quotes "..."
, is used, for regexp,
strings are required. For example:
enum Tag {
GraphQL
Database
Question
...
}
type Post {
...
tags: [Tag!]! @search
}
would allow
query {
queryPost(filter: { tags: { eq: GraphQL } } ) { ... }
}
Which would find any post with the GraphQL
tag.
While @search(by: [exact, regexp]
would also admit lt
etc. and
query {
queryPost(filter: { tags: { regexp: "/.*aph.*/" } } ) { ... }
}
which is helpful for example if the enums are something like product codes where
regular expressions can match a number of values.
Geolocation
There are 3 Geolocation types: Point
, Polygon
and MultiPolygon
. All of
them are searchable.
The following table lists the generated filters for each type when you include
@search
on the corresponding field:
type | constructed searches |
---|
Point | near , within |
Polygon | near , within , contains , intersects |
MultiPolygon | near , within , contains , intersects |
Example
Take for example a Hotel
type that has a location
and an area
:
type Hotel {
id: ID!
name: String!
location: Point @search
area: Polygon @search
}
The near
filter matches all entities where the location given by a field is
within a distance meters
from a coordinate.
queryHotel(filter: {
location: {
near: {
coordinate: {
latitude: 37.771935,
longitude: -122.469829
},
distance: 1000
}
}
}) {
name
}
The within
filter matches all entities where the location given by a field is
within a defined polygon
.
queryHotel(filter: {
location: {
within: {
polygon: {
coordinates: [{
points: [{
latitude: 11.11,
longitude: 22.22
}, {
latitude: 15.15,
longitude: 16.16
}, {
latitude: 20.20,
longitude: 21.21
}, {
latitude: 11.11,
longitude: 22.22
}]
}],
}
}
}
}) {
name
}
Contains
The contains
filter matches all entities where the Polygon
or MultiPolygon
field contains another given point
or polygon
.
Only one point
or polygon
can be taken inside the ContainsFilter
at a
time.
A contains
example using point
:
queryHotel(filter: {
area: {
contains: {
point: {
latitude: 0.5,
longitude: 2.5
}
}
}
}) {
name
}
A contains
example using polygon
:
queryHotel(filter: {
area: {
contains: {
polygon: {
coordinates: [{
points:[{
latitude: 37.771935,
longitude: -122.469829
}]
}],
}
}
}
}) {
name
}
Intersects
The intersects
filter matches all entities where the Polygon
or
MultiPolygon
field intersects another given polygon
or multiPolygon
.
Only one polygon
or multiPolygon
can be given inside the
IntersectsFilter
at a time.
queryHotel(filter: {
area: {
intersects: {
multiPolygon: {
polygons: [{
coordinates: [{
points: [{
latitude: 11.11,
longitude: 22.22
}, {
latitude: 15.15,
longitude: 16.16
}, {
latitude: 20.20,
longitude: 21.21
}, {
latitude: 11.11,
longitude: 22.22
}]
}, {
points: [{
latitude: 11.18,
longitude: 22.28
}, {
latitude: 15.18,
longitude: 16.18
}, {
latitude: 20.28,
longitude: 21.28
}, {
latitude: 11.18,
longitude: 22.28
}]
}]
}, {
coordinates: [{
points: [{
latitude: 91.11,
longitude: 92.22
}, {
latitude: 15.15,
longitude: 16.16
}, {
latitude: 20.20,
longitude: 21.21
}, {
latitude: 91.11,
longitude: 92.22
}]
}, {
points: [{
latitude: 11.18,
longitude: 22.28
}, {
latitude: 15.18,
longitude: 16.18
}, {
latitude: 20.28,
longitude: 21.28
}, {
latitude: 11.18,
longitude: 22.28
}]
}]
}]
}
}
}
}) {
name
}
Unions can be queried only as a field of a type. Union queries canβt be ordered,
but you can filter and paginate them.
Union queries donβt support the order
argument. The results will be ordered
by the UID of each node in ascending order.
For example, the following schema will enable to query the members
union field
in the Home
type with filters and pagination.
union HomeMember = Dog | Parrot | Human
type Home {
id: ID!
address: String
members(filter: HomeMemberFilter, first: Int, offset: Int): [HomeMember]
}
# Not specifying a field in the filter input will be considered as a null value for that field.
input HomeMemberFilter {
# `homeMemberTypes` is used to specify which types to report back.
homeMemberTypes: [HomeMemberType]
# specifying a null value for this field means query all dogs
dogFilter: DogFilter
# specifying a null value for this field means query all parrots
parrotFilter: ParrotFilter
# note that there is no HumanFilter because the Human type wasn't filterable
}
enum HomeMemberType {
dog
parrot
human
}
input DogFilter {
id: [ID!]
category: Category_hash
breed: StringTermFilter
and: DogFilter
or: DogFilter
not: DogFilter
}
input ParrotFilter {
id: [ID!]
category: Category_hash
and: ParrotFilter
or: ParrotFilter
not: ParrotFilter
}
Not specifying any filter at all or specifying any of the null
values for a
filter will query all members.
The same example, but this time with filter and pagination arguments:
query {
queryHome {
address
members(
filter: {
homeMemberTypes: [dog, parrot] # means we don't want to query humans
dogFilter: {
# means in Dogs, we only want to query "German Shepherd" breed
breed: { allofterms: "German Shepherd" }
}
# not specifying any filter for parrots means we want to query all parrots
}
first: 5
offset: 10
) {
... on Animal {
category
}
... on Dog {
breed
}
... on Parrot {
repeatsWords
}
... on HomeMember {
name
}
}
}
}
Vector embedding
The @search
directive is used in conjunction with @embedding
directive to
define the HNSW index on vector embeddings. These vector embeddings are obtained
from external Machine Learning models.
type User {
userID: ID!
name: String!
name_v: [Float!]
@embedding
@search(by: ["hnsw(metric: euclidean, exponent: 4)"])
}
In this schema, the field name_v
is an embedding on which the HNSW algorithm
is used to create a vector search index.
The metric used to compute the distance between vectors (in this example) is
Euclidean distance. Other possible metrics are cosine
and dotproduct
.
The directive, @embedding
, designates one or more fields as vector embeddings.
The exponent
value is used to set reasonable defaults for HNSW internal tuning
parameters. It is an integer representing an approximate number for the vectors
expected in the index, in terms of power of 10. Default is β4β (10^4 vectors).