Skip to content

Commit

Permalink
Feat(GraphQL): Add support for @search directive for vector searches (#…
Browse files Browse the repository at this point in the history
…69)

Description: This PR adds support for specifying @search directive with
search options (vector index options)
The fix is not backward compatible. Earlier searchArgs in @search
directive were expected to be Enum of index types.
Arguments are expected to be strings now of the following form.
      `@search(by: [String!])`
where each string element in the array is of the form
      `<searchArg> := <searchType> [  ( <searchOptions> ) ]`
searchOptions are optional.
       ```
```
<searchOptions> :=  <searchOption> , <searchOption>, ...
       <searchOption> :=  <optionName><COLON><SPACE><optionValue>
```

```
For example:

`product_vector: [Float!] @hm_embedding @search(by: ["hnsw(metric: euclidian, exponent: 6)"])`

Fixes: HYP-313
  • Loading branch information
sunilmujumdar authored and harshil-goel committed Apr 17, 2024
1 parent 1c3c897 commit 46c7c0f
Show file tree
Hide file tree
Showing 97 changed files with 643 additions and 443 deletions.
18 changes: 9 additions & 9 deletions graphql/bench/schema.graphql
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
type Country {
cid: ID!
id: String! @id
name: String! @search(by: [term])
name: String! @search(by: ["term"])
cities: [City]
}

type City {
cid: ID!
id: String! @id
name: String! @search(by: [term])
name: String! @search(by: ["term"])
country: Country! @hasInverse(field: cities)
restaurants: [RestaurantAddress] @hasInverse(field: city)
}
Expand All @@ -30,12 +30,12 @@ type RestaurantAddress implements Location {
type Restaurant {
id: ID!
xid: String! @id
name: String! @search(by: [term])
name: String! @search(by: ["term"])
pic: String
addr: RestaurantAddress
rating: Float
costFor2: Float
currency: String @search(by: [hash])
currency: String @search(by: ["hash"])
cuisines: [Cuisine]
dishes: [Dish] @hasInverse(field: servedBy)
createdAt: DateTime
Expand All @@ -47,14 +47,14 @@ type Cuisine {
name: String! @id
restaurants: [Restaurant] @hasInverse(field: cuisines)
dishes: [Dish] @hasInverse(field: cuisine)
type: String! @search(by: [hash])
type: String! @search(by: ["hash"])
public: Boolean @search
}

type Dish {
id: ID!
name: String! @search(by: [term])
type: String! @search(by: [hash])
name: String! @search(by: ["term"])
type: String! @search(by: ["hash"])
pic: String
price: Float
description: String
Expand All @@ -65,8 +65,8 @@ type Dish {

type Owner {
username: String! @id
name: String! @search(by: [hash])
name: String! @search(by: ["hash"])
hasRestaurants: [Restaurant] @hasInverse(field: owner)
}

# Dgraph.Authorization {"VerificationKey":"secretkey","Header":"X-Test-Auth","Namespace":"https://xyz.io/jwt/claims","Algo":"HS256","Audience":["aud1","63do0q16n6ebjgkumu05kkeian","aud5"]}
# Dgraph.Authorization {"VerificationKey":"secretkey","Header":"X-Test-Auth","Namespace":"https://xyz.io/jwt/claims","Algo":"HS256","Audience":["aud1","63do0q16n6ebjgkumu05kkeian","aud5"]}
18 changes: 9 additions & 9 deletions graphql/bench/schema_auth.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ type Country @auth(
""" }) {
cid: ID!
id: String! @id
name: String! @search(by: [term])
name: String! @search(by: ["term"])
cities: [City]
}

Expand All @@ -46,7 +46,7 @@ type City @auth(
""" }) {
cid: ID!
id: String! @id
name: String! @search(by: [term])
name: String! @search(by: ["term"])
country: Country! @hasInverse(field: cities)
restaurants: [RestaurantAddress] @hasInverse(field: city)
}
Expand Down Expand Up @@ -128,12 +128,12 @@ type Restaurant @auth(
) {
id: ID!
xid: String! @id
name: String! @search(by: [term])
name: String! @search(by: ["term"])
pic: String
addr: RestaurantAddress
rating: Float
costFor2: Float
currency: String @search(by: [hash])
currency: String @search(by: ["hash"])
cuisines: [Cuisine]
dishes: [Dish] @hasInverse(field: servedBy)
createdAt: DateTime
Expand Down Expand Up @@ -197,7 +197,7 @@ type Cuisine @auth(
name: String! @id
restaurants: [Restaurant] @hasInverse(field: cuisines)
dishes: [Dish] @hasInverse(field: cuisine)
type: String! @search(by: [hash])
type: String! @search(by: ["hash"])
public: Boolean @search
}

Expand Down Expand Up @@ -225,8 +225,8 @@ type Dish @auth(
update: { rule: "{$Role: { eq: \"ADMIN\" }}"},
){
id: ID!
name: String! @search(by: [term])
type: String! @search(by: [hash])
name: String! @search(by: ["term"])
type: String! @search(by: ["hash"])
pic: String
price: Float
description: String
Expand All @@ -244,8 +244,8 @@ type Owner @auth(
}
}""" }) {
username: String! @id
name: String! @search(by: [hash])
name: String! @search(by: ["hash"])
hasRestaurants: [Restaurant] @hasInverse(field: owner)
}

# Dgraph.Authorization {"VerificationKey":"secretkey","Header":"X-Test-Auth","Namespace":"https://xyz.io/jwt/claims","Algo":"HS256","Audience":["aud1","63do0q16n6ebjgkumu05kkeian","aud5"]}
# Dgraph.Authorization {"VerificationKey":"secretkey","Header":"X-Test-Auth","Namespace":"https://xyz.io/jwt/claims","Algo":"HS256","Audience":["aud1","63do0q16n6ebjgkumu05kkeian","aud5"]}
40 changes: 20 additions & 20 deletions graphql/e2e/auth/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ type Tweets @auth (
update: { rule: "{$USER: { eq: \"foo\" } }"}
){
id: String! @id
text: String! @search(by: [fulltext])
text: String! @search(by: ["fulltext"])
user: User
timestamp: DateTime! @search
score: Int @search
Expand Down Expand Up @@ -71,8 +71,8 @@ type UserSecret @auth(
"""}
){
id: ID!
aSecret: String @search(by: [term])
ownedBy: String @search(by: [hash])
aSecret: String @search(by: ["term"])
ownedBy: String @search(by: ["hash"])
}

type Region @auth(
Expand All @@ -83,7 +83,7 @@ type Region @auth(
"""}
){
id: ID!
name: String @search(by: [hash])
name: String @search(by: ["hash"])
global: Boolean @search
users: [User]
}
Expand Down Expand Up @@ -207,7 +207,7 @@ type Movie @auth(
]}
) {
id: ID!
content: String @search(by: [hash])
content: String @search(by: ["hash"])
hidden: Boolean @search
regionsAvailable: [Region]
reviews: [Review]
Expand Down Expand Up @@ -354,7 +354,7 @@ type Project @secret(field: "pwd") @auth(
]}
) {
projID: ID!
name: String! @search(by: [hash])
name: String! @search(by: ["hash"])
roles: [Role]
columns: [Column] @hasInverse(field: inProject)
random: String
Expand Down Expand Up @@ -478,7 +478,7 @@ type Column @auth(
) {
colID: ID!
inProject: Project! # @auth(update: { rule: "DENY" })
name: String! @search(by: [hash])
name: String! @search(by: ["hash"])
tickets: [Ticket] @hasInverse(field: onColumn)
random: String
}
Expand Down Expand Up @@ -543,7 +543,7 @@ type Ticket @auth(
){
id: ID!
onColumn: Column!
title: String! @search(by: [term])
title: String! @search(by: ["term"])
assignedTo: [User!]
}

Expand All @@ -561,14 +561,14 @@ query($USER: String!) {
}
"""},{ rule: "{$ROLE: { eq: \"ADMIN\" }}"}]}) {
id: ID!
email: String! @dgraph(pred: "IOw80vnV") @search(by: [hash])
email: String! @dgraph(pred: "IOw80vnV") @search(by: ["hash"])
}

type Contact @auth(
query: { rule: "{$ContactRole: { eq: \"ADMINISTRATOR\"}}" }
) {
id: ID!
nickName: String @search(by: [exact, term, fulltext, regexp])
nickName: String @search(by: ["exact", "term", "fulltext", "regexp"])
adminTasks: [AdminTask] @hasInverse(field: forContact)
tasks: [Task] @hasInverse(field: forContact)
}
Expand All @@ -577,14 +577,14 @@ type AdminTask @auth(
query: { rule: "{$TaskRole: { eq: \"ADMINISTRATOR\"}}" }
) {
id: ID!
name: String @search(by: [exact, term, fulltext, regexp])
name: String @search(by: ["exact", "term", "fulltext", "regexp"])
occurrences: [TaskOccurrence] @hasInverse(field: adminTask)
forContact: Contact @hasInverse(field: adminTasks)
}

type Task {
id: ID!
name: String @search(by: [exact, term, fulltext, regexp])
name: String @search(by: ["exact", "term", "fulltext", "regexp"])
occurrences: [TaskOccurrence] @hasInverse(field: task)
forContact: Contact @hasInverse(field: tasks)
}
Expand All @@ -608,12 +608,12 @@ type TaskOccurrence @auth(
task: Task @hasInverse(field: occurrences)
adminTask: AdminTask @hasInverse(field: occurrences)
isPublic: Boolean @search
role: String @search(by: [exact, term, fulltext, regexp])
role: String @search(by: ["exact", "term", "fulltext", "regexp"])
}

type Author {
id: ID!
name: String! @search(by: [exact])
name: String! @search(by: ["exact"])
posts: [Post] @hasInverse(field: author)
}

Expand Down Expand Up @@ -653,7 +653,7 @@ interface Post @secret(field: "pwd") @auth(
}""" }
){
id: ID!
text: String! @search(by: [exact])
text: String! @search(by: ["exact"])
topic: String
datePublished: DateTime @search
author: Author!
Expand Down Expand Up @@ -725,7 +725,7 @@ type Answer implements Post {

interface A {
id: ID!
fieldA: String @search(by: [exact])
fieldA: String @search(by: ["exact"])
random: String
}

Expand Down Expand Up @@ -788,7 +788,7 @@ type Mission @key(fields: "id") @auth(
){
id: String! @id
crew: [Astronaut]
supervisorName: String @search(by: [exact])
supervisorName: String @search(by: ["exact"])
designation: String!
startDate: String
endDate: String
Expand All @@ -812,7 +812,7 @@ interface Vehicle @auth(
]
}
){
owner: String! @search(by: [exact])
owner: String! @search(by: ["exact"])
}

type Car implements Vehicle {
Expand All @@ -830,7 +830,7 @@ type Country @auth(
"""} ) {
id: String! @id
name: String!
ownedBy: String @search(by: [hash])
ownedBy: String @search(by: ["hash"])
states: [State] @hasInverse(field: country)
}

Expand All @@ -844,7 +844,7 @@ type State @auth(
"""} ) {
code: String! @id
name: String!
ownedBy: String @search(by: [hash])
ownedBy: String @search(by: ["hash"])
country: Country
}

Expand Down
2 changes: 1 addition & 1 deletion graphql/e2e/common/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -1285,7 +1285,7 @@ func stringExactFilters(t *testing.T) {

func scalarListFilters(t *testing.T) {

// tags is a list of strings with @search(by: exact). So all the filters
// tags is a list of strings with @search(by: "exact"). So all the filters
// lt, le, ... mean "is there something in the list that's lt 'Dgraph'", etc.

cases := map[string]struct {
Expand Down
6 changes: 3 additions & 3 deletions graphql/e2e/custom_logic/custom_logic_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1067,7 +1067,7 @@ func TestCustomFieldsShouldPassBody(t *testing.T) {

schema := `
type User {
id: String! @id @search(by: [hash, regexp])
id: String! @id @search(by: ["hash", "regexp"])
address:String
name: String
@custom(
Expand Down Expand Up @@ -2573,7 +2573,7 @@ func TestCustomDQL(t *testing.T) {
}
type Tweets implements Node {
id: ID!
text: String! @search(by: [fulltext, exact])
text: String! @search(by: ["fulltext", "exact"])
user: User
timestamp: DateTime! @search
}
Expand Down Expand Up @@ -2864,7 +2864,7 @@ func TestCustomFieldsWithRestError(t *testing.T) {
}
type User {
id: String! @id @search(by: [hash, regexp])
id: String! @id @search(by: ["hash", "regexp"])
name: String
@custom(
http: {
Expand Down
20 changes: 10 additions & 10 deletions graphql/e2e/directives/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

type Hotel {
id: ID!
name: String! @search(by: [exact])
name: String! @search(by: ["exact"])
location: Point @search
area: Polygon @search
branches: MultiPolygon @search
Expand Down Expand Up @@ -197,7 +197,7 @@ type Comment1 {
}
type post1{
id: ID
title: String! @id @search(by: [regexp])
title: String! @id @search(by: ["regexp"])
numLikes: Int64 @search
commentsByMonth: [Int]
likesByMonth: [Int64]
Expand All @@ -213,13 +213,13 @@ type Person1 {

type Person {
id: ID!
name: String! @search(by: [hash])
nameHi: String @dgraph(pred:"Person.name@hi") @search(by: [hash])
nameZh: String @dgraph(pred:"Person.name@zh") @search(by: [hash])
name: String! @search(by: ["hash"])
nameHi: String @dgraph(pred:"Person.name@hi") @search(by: ["hash"])
nameZh: String @dgraph(pred:"Person.name@zh") @search(by: ["hash"])
nameHiZh: String @dgraph(pred:"Person.name@hi:zh")
nameZhHi: String @dgraph(pred:"Person.name@zh:hi")
nameHi_Zh_Untag: String @dgraph(pred:"Person.name@hi:zh:.")
name_Untag_AnyLang: String @dgraph(pred:"Person.name@.") @search(by: [hash])
name_Untag_AnyLang: String @dgraph(pred:"Person.name@.") @search(by: ["hash"])
professionEn: String @dgraph(pred:"Person.profession@en")
}

Expand Down Expand Up @@ -363,19 +363,19 @@ type Owner {
type Project {
id: String! @id
owner: Owner!
name: String! @search(by: [hash])
name: String! @search(by: ["hash"])
datasets: [Dataset!] @hasInverse(field: project)
}

type Dataset {
id: String! @id
owner: Owner!
project: Project!
name: String! @search(by: [hash])
name: String! @search(by: ["hash"])
}

type author1{
name:String! @id @search(by: [regexp])
name:String! @id @search(by: ["regexp"])
posts:[post1] @hasInverse(field: author)
}
# multiple fields with @id directive
Expand Down Expand Up @@ -423,4 +423,4 @@ type CricketTeam implements Team {
type LibraryManager {
name: String! @id
manages: [LibraryMember]
}
}
Loading

0 comments on commit 46c7c0f

Please sign in to comment.