Skip to content

Commit 16f58ff

Browse files
authored
Merge pull request #139 from weaviate/update-to-handle-125-changes
Update to handle core `v1.25` changes
2 parents 25ac3fb + 5d16094 commit 16f58ff

File tree

12 files changed

+537
-72
lines changed

12 files changed

+537
-72
lines changed

.github/workflows/main.yaml

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ on:
88

99

1010
env:
11-
WEAVIATE_VERSION: 1.24.1
11+
WEAVIATE_VERSION: 1.25.1
1212

1313
jobs:
1414
checks:
@@ -27,15 +27,23 @@ jobs:
2727
tests:
2828
needs: checks
2929
runs-on: ubuntu-latest
30+
strategy:
31+
fail-fast: false
32+
matrix:
33+
versions: [
34+
{ node: "18.x", weaviate: $WEAVIATE_VERSION},
35+
{ node: "20.x", weaviate: $WEAVIATE_VERSION},
36+
{ node: "22.x", weaviate: $WEAVIATE_VERSION}
37+
]
3038
steps:
3139
- uses: actions/checkout@v3
3240
- uses: actions/setup-node@v3
3341
with:
34-
node-version: '18.x'
42+
node-version: ${{ matrix.versions.node }}
3543
- name: "Install dependencies"
3644
run: |
3745
npm install
38-
ci/run_dependencies.sh ${{ env.WEAVIATE_VERSION }}
46+
ci/run_dependencies.sh ${{ matrix.versions.weaviate }}
3947
- name: "Run tests with authentication tests"
4048
if: ${{ !github.event.pull_request.head.repo.fork }}
4149
env:
@@ -52,7 +60,7 @@ jobs:
5260
npm test
5361
npm run build
5462
- name: "Stop Weaviate"
55-
run: ci/stop_dependencies.sh ${{ env.WEAVIATE_VERSION }}
63+
run: ci/stop_dependencies.sh ${{ matrix.versions.weaviate }}
5664

5765
publish:
5866
needs: tests

ci/docker-compose-cluster.yml

Lines changed: 51 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,22 @@ services:
66
restart: on-failure:0
77
ports:
88
- "8087:8080"
9+
- "50058:50051"
910
environment:
10-
CONTEXTIONARY_URL: contextionary:9999
1111
QUERY_DEFAULTS_LIMIT: 20
1212
AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED: 'true'
1313
PERSISTENCE_DATA_PATH: "./weaviate-node-1"
14-
DEFAULT_VECTORIZER_MODULE: text2vec-contextionary
15-
ENABLE_MODULES: text2vec-contextionary
14+
CLUSTER_HOSTNAME: "node1"
1615
CLUSTER_GOSSIP_BIND_PORT: "7110"
1716
CLUSTER_DATA_BIND_PORT: "7111"
17+
RAFT_PORT: '8300'
18+
RAFT_INTERNAL_RPC_PORT: "8301"
19+
RAFT_JOIN: "node1:8300,node2:8300,node3:8300"
20+
RAFT_BOOTSTRAP_EXPECT: "3"
1821
DISABLE_TELEMETRY: 'true'
22+
CONTEXTIONARY_URL: contextionary:9999
23+
DEFAULT_VECTORIZER_MODULE: text2vec-contextionary
24+
ENABLE_MODULES: text2vec-contextionary
1925

2026
weaviate-node-2:
2127
init: true
@@ -29,19 +35,55 @@ services:
2935
image: semitechnologies/weaviate:${WEAVIATE_VERSION}
3036
ports:
3137
- 8088:8080
32-
- 6061:6060
38+
- "50059:50051"
3339
restart: on-failure:0
3440
environment:
35-
CONTEXTIONARY_URL: contextionary:9999
3641
LOG_LEVEL: 'debug'
3742
QUERY_DEFAULTS_LIMIT: 20
3843
AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED: 'true'
3944
PERSISTENCE_DATA_PATH: './weaviate-node-2'
45+
CLUSTER_HOSTNAME: 'node2'
46+
CLUSTER_GOSSIP_BIND_PORT: '7110'
47+
CLUSTER_DATA_BIND_PORT: '7111'
48+
CLUSTER_JOIN: 'weaviate-node-1:7110'
49+
RAFT_PORT: '8300'
50+
RAFT_INTERNAL_RPC_PORT: "8301"
51+
RAFT_JOIN: "node1:8300,node2:8300,node3:8300"
52+
RAFT_BOOTSTRAP_EXPECT: "3"
53+
DISABLE_TELEMETRY: 'true'
54+
CONTEXTIONARY_URL: contextionary:9999
4055
DEFAULT_VECTORIZER_MODULE: text2vec-contextionary
4156
ENABLE_MODULES: text2vec-contextionary
42-
CLUSTER_HOSTNAME: 'node2'
43-
CLUSTER_GOSSIP_BIND_PORT: '7112'
44-
CLUSTER_DATA_BIND_PORT: '7113'
57+
58+
weaviate-node-3:
59+
init: true
60+
command:
61+
- --host
62+
- 0.0.0.0
63+
- --port
64+
- '8080'
65+
- --scheme
66+
- http
67+
image: semitechnologies/weaviate:${WEAVIATE_VERSION}
68+
ports:
69+
- 8089:8080
70+
- "50060:50051"
71+
restart: on-failure:0
72+
environment:
73+
LOG_LEVEL: 'debug'
74+
QUERY_DEFAULTS_LIMIT: 20
75+
AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED: 'true'
76+
PERSISTENCE_DATA_PATH: './weaviate-node-2'
77+
CLUSTER_HOSTNAME: 'node3'
78+
CLUSTER_GOSSIP_BIND_PORT: '7110'
79+
CLUSTER_DATA_BIND_PORT: '7111'
4580
CLUSTER_JOIN: 'weaviate-node-1:7110'
81+
RAFT_PORT: '8300'
82+
RAFT_INTERNAL_RPC_PORT: "8301"
83+
RAFT_JOIN: "node1:8300,node2:8300,node3:8300"
84+
RAFT_BOOTSTRAP_EXPECT: "3"
4685
DISABLE_TELEMETRY: 'true'
47-
...
86+
CONTEXTIONARY_URL: contextionary:9999
87+
DEFAULT_VECTORIZER_MODULE: text2vec-contextionary
88+
ENABLE_MODULES: text2vec-contextionary
89+
...

src/connection/httpClient.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,8 +149,8 @@ const makeCheckStatus = (expectResponseBody: boolean) => (res: Response) => {
149149
};
150150

151151
const handleHeadResponse = (expectResponseBody: boolean) => (res: Response) => {
152-
if (res.status == 204 || res.status == 404) {
153-
return res.status == 204;
152+
if (res.status == 200 || res.status == 204 || res.status == 404) {
153+
return res.status == 200 || res.status == 204;
154154
}
155155
return makeCheckStatus(expectResponseBody)(res);
156156
};

src/graphql/getter.test.ts

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1289,6 +1289,21 @@ describe('bm25 valid searchers', () => {
12891289

12901290
expect(mockClient.query).toHaveBeenCalledWith(expectedQuery);
12911291
});
1292+
1293+
test('query and groupby', () => {
1294+
const expectedQuery = `{Get{Person(bm25:{query:"accountant"},groupBy:{path:["employer"],groups:2,objectsPerGroup:3}){name}}}`;
1295+
1296+
new Getter(mockClient)
1297+
.withClassName('Person')
1298+
.withFields('name')
1299+
.withBm25({
1300+
query: 'accountant',
1301+
})
1302+
.withGroupBy({ path: ['employer'], groups: 2, objectsPerGroup: 3 })
1303+
.do();
1304+
1305+
expect(mockClient.query).toHaveBeenCalledWith(expectedQuery);
1306+
});
12921307
});
12931308

12941309
describe('hybrid valid searchers', () => {
@@ -1383,6 +1398,50 @@ describe('hybrid valid searchers', () => {
13831398

13841399
expect(mockClient.query).toHaveBeenCalledWith(expectedQuery);
13851400
});
1401+
1402+
test('query and groupby', () => {
1403+
const expectedQuery = `{Get{Person(hybrid:{query:"accountant"},groupBy:{path:["employer"],groups:2,objectsPerGroup:3}){name}}}`;
1404+
1405+
new Getter(mockClient)
1406+
.withClassName('Person')
1407+
.withFields('name')
1408+
.withHybrid({
1409+
query: 'accountant',
1410+
})
1411+
.withGroupBy({ path: ['employer'], groups: 2, objectsPerGroup: 3 })
1412+
.do();
1413+
1414+
expect(mockClient.query).toHaveBeenCalledWith(expectedQuery);
1415+
});
1416+
1417+
test('query and subsearches', () => {
1418+
const subQuery = `searches:[{nearVector:{vector:[1,2,3],certainty:0.8,targetVectors:["employer"]}},{nearText:{concepts:["accountant"],distance:0.3,moveTo:{concepts:["foo"],objects:[{id:"uuid"}],force:0.8}}}]`;
1419+
const expectedQuery = `{Get{Person(hybrid:{query:"accountant",${subQuery}}){name}}}`;
1420+
1421+
new Getter(mockClient)
1422+
.withClassName('Person')
1423+
.withFields('name')
1424+
.withHybrid({
1425+
query: 'accountant',
1426+
searches: [
1427+
{ nearVector: { certainty: 0.8, targetVectors: ['employer'], vector: [1, 2, 3] } },
1428+
{
1429+
nearText: {
1430+
concepts: ['accountant'],
1431+
distance: 0.3,
1432+
moveTo: {
1433+
concepts: ['foo'],
1434+
objects: [{ id: 'uuid' }],
1435+
force: 0.8,
1436+
},
1437+
},
1438+
},
1439+
],
1440+
})
1441+
.do();
1442+
1443+
expect(mockClient.query).toHaveBeenCalledWith(expectedQuery);
1444+
});
13861445
});
13871446

13881447
describe('generative search', () => {

src/graphql/hybrid.ts

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,92 @@
1+
import { Move, parseMove } from './nearText';
2+
13
export interface HybridArgs {
24
alpha?: number;
35
query: string;
46
vector?: number[];
57
properties?: string[];
68
targetVectors?: string[];
79
fusionType?: FusionType;
10+
searches?: HybridSubSearch[];
11+
}
12+
13+
export interface NearTextSubSearch {
14+
concepts: string[];
15+
certainty?: number;
16+
distance?: number;
17+
moveAwayFrom?: Move;
18+
moveTo?: Move;
19+
}
20+
21+
export interface NearVectorSubSearch {
22+
vector: number[];
23+
certainty?: number;
24+
distance?: number;
25+
targetVectors?: string[];
26+
}
27+
28+
export interface HybridSubSearch {
29+
nearText?: NearTextSubSearch;
30+
nearVector?: NearVectorSubSearch;
831
}
932

1033
export enum FusionType {
1134
rankedFusion = 'rankedFusion',
1235
relativeScoreFusion = 'relativeScoreFusion',
1336
}
1437

38+
class GraphQLHybridSubSearch {
39+
private nearText?: NearTextSubSearch;
40+
private nearVector?: NearVectorSubSearch;
41+
42+
constructor(args: HybridSubSearch) {
43+
this.nearText = args.nearText;
44+
this.nearVector = args.nearVector;
45+
}
46+
47+
toString(): string {
48+
let outer: string[] = [];
49+
if (this.nearText !== undefined) {
50+
let inner = [`concepts:${JSON.stringify(this.nearText.concepts)}`];
51+
if (this.nearText.certainty) {
52+
inner = [...inner, `certainty:${this.nearText.certainty}`];
53+
}
54+
if (this.nearText.distance) {
55+
inner = [...inner, `distance:${this.nearText.distance}`];
56+
}
57+
if (this.nearText.moveTo) {
58+
inner = [...inner, parseMove('moveTo', this.nearText.moveTo)];
59+
}
60+
if (this.nearText.moveAwayFrom) {
61+
inner = [...inner, parseMove('moveAwayFrom', this.nearText.moveAwayFrom)];
62+
}
63+
outer = [...outer, `nearText:{${inner.join(',')}}`];
64+
}
65+
if (this.nearVector !== undefined) {
66+
let inner = [`vector:${JSON.stringify(this.nearVector.vector)}`];
67+
if (this.nearVector.certainty) {
68+
inner = [...inner, `certainty:${this.nearVector.certainty}`];
69+
}
70+
if (this.nearVector.distance) {
71+
inner = [...inner, `distance:${this.nearVector.distance}`];
72+
}
73+
if (this.nearVector.targetVectors && this.nearVector.targetVectors.length > 0) {
74+
inner = [...inner, `targetVectors:${JSON.stringify(this.nearVector.targetVectors)}`];
75+
}
76+
outer = [...outer, `nearVector:{${inner.join(',')}}`];
77+
}
78+
return `{${outer.join(',')}}`;
79+
}
80+
}
81+
1582
export default class GraphQLHybrid {
1683
private alpha?: number;
1784
private query: string;
1885
private vector?: number[];
1986
private properties?: string[];
2087
private targetVectors?: string[];
2188
private fusionType?: FusionType;
89+
private searches?: GraphQLHybridSubSearch[];
2290

2391
constructor(args: HybridArgs) {
2492
this.alpha = args.alpha;
@@ -27,6 +95,7 @@ export default class GraphQLHybrid {
2795
this.properties = args.properties;
2896
this.targetVectors = args.targetVectors;
2997
this.fusionType = args.fusionType;
98+
this.searches = args.searches?.map((search) => new GraphQLHybridSubSearch(search));
3099
}
31100

32101
toString() {
@@ -52,6 +121,10 @@ export default class GraphQLHybrid {
52121
args = [...args, `fusionType:${this.fusionType}`];
53122
}
54123

124+
if (this.searches !== undefined) {
125+
args = [...args, `searches:[${this.searches.map((search) => search.toString()).join(',')}]`];
126+
}
127+
55128
return `{${args.join(',')}}`;
56129
}
57130
}

0 commit comments

Comments
 (0)