Skip to content

Commit 983f282

Browse files
committed
edit: better example query and generated aql; tests: 30/30
1 parent 71990ff commit 983f282

File tree

2 files changed

+95
-115
lines changed

2 files changed

+95
-115
lines changed

README.md

Lines changed: 51 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -12,43 +12,53 @@ all available Arango Search View capabilities, including, `PHRASE` and
1212
multi-lingual and language-specific, complex phrase, (proximity... TBD) and tokenized
1313
search terms.
1414

15-
For example, passing a search phrase like: `+mandatory -exclude ?"optional
16-
phrase"` to `buildAQL`'s query object as the `term` key, will produce a query
17-
like the following:
18-
19-
```aql
20-
FOR doc IN search_view
21-
SEARCH
22-
MIN_MATCH(
23-
ANALYZER(
24-
TOKENS(@value0, @value1)
25-
ALL IN doc.@value2, @value1),
26-
@value3) OR (MIN_MATCH(
27-
ANALYZER(
28-
TOKENS(@value0, @value1)
29-
ALL IN doc.@value2, @value1),
30-
@value3) AND (PHRASE(doc.@value2, @value4, @value1)))
31-
32-
AND
33-
34-
MIN_MATCH(
35-
ANALYZER(
36-
TOKENS(@value5, @value1)
37-
NONE IN doc.@value2, @value1),
38-
@value3)
39-
40-
OPTIONS @value6
41-
SORT TFIDF(doc) DESC
42-
43-
LIMIT @value7, @value8
44-
RETURN doc
15+
For example, passing a search phrase like: `some +words -not +"phrase search"
16+
-"not these" ?"could have"` to `buildAQL`'s query object as the `term` key,
17+
will produce a query like the following:
18+
19+
```asx
20+
FOR doc IN view
21+
22+
SEARCH
23+
(PHRASE(doc.text, "phrase search", analyzer)) AND MIN_MATCH(
24+
ANALYZER(
25+
TOKENS("words", analyzer)
26+
ALL IN doc.text, analyzer),
27+
1) OR ((PHRASE(doc.text, "phrase search", analyzer)) AND MIN_MATCH(
28+
ANALYZER(
29+
TOKENS("words", analyzer)
30+
ALL IN doc.text, analyzer),
31+
1) AND (PHRASE(doc.text, "could have", analyzer)) OR MIN_MATCH(
32+
ANALYZER(
33+
TOKENS(other, analyzer)
34+
ANY IN doc.text, analyzer),
35+
1))
36+
37+
AND
38+
NOT (PHRASE(doc.text, "not these", analyzer))
39+
AND MIN_MATCH(
40+
ANALYZER(
41+
TOKENS("nor", analyzer)
42+
NONE IN doc.text, analyzer),
43+
1)
44+
45+
OPTIONS {"collections": ["col"]}
46+
SORT TFIDF(doc) DESC
47+
48+
LIMIT "phrase search"0, "phrase search"1
49+
RETURN doc`
4550
```
51+
4652
This query will retrieve all documents that __include__ the term "mandatory"
4753
AND __do not include__ the term "exclude", AND whose ranking will be boosted by the
4854
presence of the phrase "optional phrase". If no mandatory or exclude terms are
4955
provided, optional terms are considered required, so as not to retrieve all
5056
documents.
5157

58+
If multiple collections are passed, the above queried is essentially
59+
replicated across all collections, see examples in 'tests/cols.ts'. In the
60+
future this will also accommodate multiple key searches.
61+
5262
## setup
5363

5464
1) running generated AQL queries will require a working arangodb instance. In
@@ -159,24 +169,33 @@ Example:
159169
```
160170

161171
### boolean search logic
172+
162173
Quoting [mit's Database Search Tips](https://libguides.mit.edu/c.php?g=175963&p=1158594):
174+
163175
> Boolean operators form the basis of mathematical sets and database logic.
164176
They connect your search words together to either narrow or broaden your
165177
set of results. The three basic boolean operators are: AND, OR, and NOT.
166178

167179
#### `+` AND
180+
168181
* Mandatory terms and phrases. All results MUST INCLUDE these terms and
169182
phrases.
183+
170184
#### `?` OR
185+
171186
* Optional terms and phrases. If there are ANDS or NOTS, these serve as match
172187
score "boosters". If there are no ANDS or NOTS, ORS become required in
173188
results.
189+
174190
#### `-` NOT
191+
175192
* Search results MUST NOT INCLUDE these terms and phrases. If a result that
176193
would otherwise have matched, contains one or more terms or phrases, it will
177-
not be included in the result set.
194+
not be included in the result set. If there are no required or optional
195+
terms, all results that do NOT match these terms will be returned.
178196

179197
### default query syntax
198+
180199
for more information on boolean search logic see
181200
[above](#boolean-search-logic)
182201

@@ -208,3 +227,4 @@ score higher than those that do not.
208227
plase see [bugs](https://github.com/HP4k1h5/AQLqueryBuilder.js/issues/new?assignees=HP4k1h5&labels=bug&template=bug_report.md&title=basic)
209228
## contributing
210229
plase see [./.github/CONTRIBUTING.md]
230+

tests/cols.ts

Lines changed: 44 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -69,107 +69,67 @@ describe('multiple collections', () => {
6969
})
7070

7171
it(`should return an aql object
72-
when TOKENs are passed to multiple collections`, () => {
72+
when a mixed query string
73+
with multiple members and multiple collections is passed`, () => {
7374
let query = {
7475
view: 'view',
75-
collections: [
76-
{ name: 'coll1', analyzer: 'analyzer1' },
77-
{ name: 'coll2', analyzer: 'analyzer2' },
78-
],
79-
terms: 'hope',
76+
collections: [ { name: 'coll', analyzer: 'analyzer' } ],
77+
terms: 'other +words -nor +"phrase search" -"not these" ?"could have"',
8078
}
8179
const builtAQL = buildAQL(query)
82-
8380
expect(builtAQL).to.be.an('object')
81+
8482
expect(builtAQL.query).to.equal(`
8583
FOR doc IN view
8684
8785
SEARCH
88-
89-
MIN_MATCH(
86+
(PHRASE(doc.@value0, @value1, @value2)) AND MIN_MATCH(
9087
ANALYZER(
91-
TOKENS(@value0, @value3)
92-
ANY IN doc.@value2, @value3),
88+
TOKENS(@value3, @value2)
89+
ALL IN doc.@value0, @value2),
90+
@value4) OR ((PHRASE(doc.@value0, @value1, @value2)) AND MIN_MATCH(
9391
ANALYZER(
94-
TOKENS(@value0, @value3)
95-
ANY IN doc.@value2, @value3),
96-
@value4)
92+
TOKENS(@value3, @value2)
93+
ALL IN doc.@value0, @value2),
94+
@value4) AND (PHRASE(doc.@value0, @value5, @value2)) OR MIN_MATCH(
95+
ANALYZER(
96+
TOKENS(@value6, @value2)
97+
ANY IN doc.@value0, @value2),
98+
@value4))
9799
100+
AND
101+
NOT (PHRASE(doc.@value0, @value7, @value2))
102+
AND MIN_MATCH(
103+
ANALYZER(
104+
TOKENS(@value8, @value2)
105+
NONE IN doc.@value0, @value2),
106+
@value4)
98107
99-
OPTIONS @value5
108+
OPTIONS @value9
100109
SORT TFIDF(doc) DESC
101110
102-
LIMIT @value6, @value7
103-
RETURN doc`)
104-
})
105-
106-
it.skip(`should return an aql object
107-
when a phrase string is passed for query terms`, () => {
108-
let query = {
109-
view: 'view',
110-
collections: [ { name: 'coll', analyzer: 'analyzer' } ],
111-
terms: '"phrase search"',
112-
}
113-
const builtAQL = buildAQL(query)
114-
expect(builtAQL).to.be.an('object')
115-
116-
expect(builtAQL.query).to.equal(`\n FOR doc IN view\n \n SEARCH \n \n MIN_MATCH(\n ANALYZER(\n TOKENS(@value0, @value1)\n ANY IN doc.@value2, @value1), \n ANALYZER(\n TOKENS(@value0, @value3)\n ANY IN doc.@value2, @value3), \n @value4)\n \n \n OPTIONS @value5\n SORT TFIDF(doc) DESC\n \n LIMIT @value6, @value7\n RETURN doc`
111+
LIMIT @value10, @value11
112+
RETURN doc`
117113
)
118-
})
119114

120-
it.skip(`should handle basic boolean cases`, () => {
121-
let query = {
122-
view: 'view',
123-
collections: [ { name: 'coll', analyzer: 'analyzer' } ],
124-
terms: '-"hope"',
125-
}
126-
127-
const builtAQL = buildAQL(query)
128-
expect(builtAQL).to.be.an('object')
129-
expect(builtAQL.query).to.equal(`
130-
FOR doc IN view
131-
132-
SEARCH
133-
134-
135-
136-
NOT (PHRASE(doc.@value0, @value1, @value2))
137-
138-
139-
OPTIONS @value3
140-
SORT TFIDF(doc) DESC
141-
142-
LIMIT @value4, @value5
143-
RETURN doc`)
115+
expect(builtAQL.bindVars).to.deep.equal({
116+
"value0": "text",
117+
"value1": "phrase search",
118+
"value10": 0,
119+
"value11": 20,
120+
"value2": "analyzer",
121+
"value3": "words",
122+
"value4": 1,
123+
"value5": "could have",
124+
"value6": "other",
125+
"value7": "not these",
126+
"value8": "nor",
127+
"value9": {
128+
"collections": [
129+
"coll"
130+
]
131+
}
132+
})
144133
})
145134

146-
it.skip(`should handle basic boolean cases`, () => {
147-
let query = {
148-
view: 'view',
149-
collections: [ { name: 'coll', analyzer: 'analyzer' } ],
150-
terms: '-hope',
151-
}
152-
153-
const builtAQL = buildAQL(query)
154-
expect(builtAQL).to.be.an('object')
155-
expect(builtAQL.query).to.equal(`
156-
FOR doc IN view
157-
158-
SEARCH
159-
160-
161-
162-
163-
MIN_MATCH(
164-
ANALYZER(
165-
TOKENS(@value0, @value1)
166-
NONE IN doc.@value2, @value1),
167-
@value3)
168-
169-
OPTIONS @value4
170-
SORT TFIDF(doc) DESC
171-
172-
LIMIT @value5, @value6
173-
RETURN doc`)
174-
})
175135
})

0 commit comments

Comments
 (0)