From ecccaf023e2530afbf7d3e9062c5c1b15af9bb73 Mon Sep 17 00:00:00 2001 From: delvedor Date: Thu, 3 Sep 2020 18:30:56 +0200 Subject: [PATCH] Updated examples --- dsl/examples/compile-query.ts | 137 ++++++++++++++++++--------- dsl/examples/compile-unsafe-query.ts | 120 +++++++++++++++++++++++ dsl/examples/day-most-commits.ts | 35 ++++++- dsl/examples/fix-commit.ts | 29 +++++- dsl/examples/last-commits.ts | 28 +++++- dsl/examples/top-committers.ts | 36 ++++++- dsl/examples/top-month.ts | 50 +++++++++- 7 files changed, 375 insertions(+), 60 deletions(-) create mode 100644 dsl/examples/compile-unsafe-query.ts diff --git a/dsl/examples/compile-query.ts b/dsl/examples/compile-query.ts index f901a95b3..d8d8444b8 100644 --- a/dsl/examples/compile-query.ts +++ b/dsl/examples/compile-query.ts @@ -18,56 +18,103 @@ */ import { Client } from '../../' -import { Q } from '../' +import { Q, F } from '../' -// You can compile a query if you need to get -// the best performances out of your code. -// The query crafting and compilation should be done -// outside of your hot code path. -// First of all yu should create your query almost -// in the same way as you were doing before, the only -// difference, is that all the paramegers you are passing -// now should be updated with the `Q.param` API. -// The only parameter or `Q.param`, is the name of the parameter -// that you were passing before. -const query = Q( - Q.match('description', Q.param('description')), - Q.filter( - Q.term('author.name', Q.param('author')) - ), - Q.size(10) -) +/** + * Pure functions API + */ +{ + // You can compile a query if you need to get + // the best performances out of your code. + // The query crafting and compilation should be done + // outside of your hot code path. + // First of all you should create your query almost + // in the same way as you were doing before, the only + // difference, is that all the paramegers you are passing + // now should be updated with the `Q.param` API. + // The only parameter or `Q.param`, is the name of the parameter + // that you were passing before. + const query = Q( + Q.match('description', Q.param('description')), + Q.filter( + Q.term('author.name', Q.param('author')) + ), + Q.size(10) + ) -// Afterwards, you can create an interface that represents -// the input object of the compiled query. The input object -// contains all the parameters you were passing before, the -// keys are the same you have passed to the various `Q.param` -// invocations before. It defaults to `unknown`. -interface Input { - description: string - author: string -} -// Once you have created the query and the input interface, -// you must pass the query to `Q.compile` and store the result -// in a variable. `Q.compile` returns a function that accepts -// a single object parameter, which is the same you have declared -// in the interface before. -const compiledQuery = Q.compile(query) + // Afterwards, you can create an interface that represents + // the input object of the compiled query. The input object + // contains all the parameters you were passing before, the + // keys are the same you have passed to the various `Q.param` + // invocations before. It defaults to `unknown`. + interface Input { + description: string + author: string + } + // In this example we will use `Q.compile`, the returned function + // works in the same way as `Q.compileUnsafe` but the function returned by the + // safe API is an order of magnitude slower. + // `Q.compile` can be used with unstrusted input (but it's not recommended). + // Once you have created the query and the input interface, + // you must pass the query to `Q.compile` and store the result + // in a variable. `Q.compile` returns a function that accepts + // a single object parameter, which is the same you have declared + // in the interface before. + const compiledQuery = Q.compile(query) -async function run () { - const client = new Client({ node: 'http://localhost:9200' }) + async function run () { + const client = new Client({ node: 'http://localhost:9200' }) - const { body } = await client.search({ - index: 'git', - // Finally, you call the function inside your hot code path, - // the returned value will be the query. - body: compiledQuery({ - description: 'fix', - author: 'delvedor' + const { body } = await client.search({ + index: 'git', + // Finally, you call the function inside your hot code path, + // the returned value will be the query. + body: compiledQuery({ + description: 'fix', + author: 'delvedor' + }) }) - }) - console.log(body.hits.hits) + console.log(body.hits.hits) + } + + run().catch(console.log) } -run().catch(console.log) +/** + * Fluent API + */ +{ + // The theory behind query compilation is the same here, + // the query crafting and compilation should be done + // outside of your hot code path. + const query = new F() + .match('description', Q.param('description')) + .filter(f => f + .term('author.name', Q.param('author')) + ) + .size(10) + + interface Input { + description: string + author: string + } + + const compiledQuery = query.compile() + + async function run () { + const client = new Client({ node: 'http://localhost:9200' }) + + const { body } = await client.search({ + index: 'git', + body: compiledQuery({ + description: 'fix', + author: 'delvedor' + }) + }) + + console.log(body.hits.hits) + } + + run().catch(console.log) +} diff --git a/dsl/examples/compile-unsafe-query.ts b/dsl/examples/compile-unsafe-query.ts new file mode 100644 index 000000000..851715e1a --- /dev/null +++ b/dsl/examples/compile-unsafe-query.ts @@ -0,0 +1,120 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { Client } from '../../' +import { Q, F } from '../' + +/** + * Pure functions API + */ +{ + // You can compile a query if you need to get + // the best performances out of your code. + // The query crafting and compilation should be done + // outside of your hot code path. + // First of all you should create your query almost + // in the same way as you were doing before, the only + // difference, is that all the paramegers you are passing + // now should be updated with the `Q.param` API. + // The only parameter or `Q.param`, is the name of the parameter + // that you were passing before. + const query = Q( + Q.match('description', Q.param('description')), + Q.filter( + Q.term('author.name', Q.param('author')) + ), + Q.size(10) + ) + + // Afterwards, you can create an interface that represents + // the input object of the compiled query. The input object + // contains all the parameters you were passing before, the + // keys are the same you have passed to the various `Q.param` + // invocations before. It defaults to `unknown`. + interface Input { + description: string + author: string + } + // In this example we will use `Q.compileUnsafe`, the returned function + // works in the same way as `Q.compile` but the function returned by the + // unsafe API is an order of magnitude faster. + // You should NEVER use `Q.compileUnsafe` with untrusted input. + // Once you have created the query and the input interface, + // you must pass the query to `Q.compileUnsafe` and store the result + // in a variable. `Q.compile` returns a function that accepts + // a single object parameter, which is the same you have declared + // in the interface before. + const compiledQuery = Q.compileUnsafe(query) + + async function run () { + const client = new Client({ node: 'http://localhost:9200' }) + + const { body } = await client.search({ + index: 'git', + // Finally, you call the function inside your hot code path, + // the returned value will be the query. + body: compiledQuery({ + description: 'fix', + author: 'delvedor' + }) + }) + + console.log(body.hits.hits) + } + + run().catch(console.log) +} + +/** + * Fluent API + */ +{ + // The theory behind query compilation is the same here, + // the query crafting and compilation should be done + // outside of your hot code path. + const query = new F() + .match('description', Q.param('description')) + .filter(f => f + .term('author.name', Q.param('author')) + ) + .size(10) + + interface Input { + description: string + author: string + } + + const compiledQuery = query.compileUnsafe() + + async function run () { + const client = new Client({ node: 'http://localhost:9200' }) + + const { body } = await client.search({ + index: 'git', + body: compiledQuery({ + description: 'fix', + author: 'delvedor' + }) + }) + + console.log(body.hits.hits) + } + + run().catch(console.log) +} diff --git a/dsl/examples/day-most-commits.ts b/dsl/examples/day-most-commits.ts index 9141897c9..04a27b090 100644 --- a/dsl/examples/day-most-commits.ts +++ b/dsl/examples/day-most-commits.ts @@ -18,9 +18,12 @@ */ import { Client } from '../../' -import { Q, A } from '../' +import { Q, A, F } from '../' -async function run () { +/** + * Pure function API + */ +async function run1 () { const client = new Client({ node: 'http://localhost:9200' }) // get the day where the most commits were made @@ -41,4 +44,30 @@ async function run () { console.log(body.aggregations) } -run().catch(console.log) +/** + * Fluent API + */ +async function run2 () { + const client = new Client({ node: 'http://localhost:9200' }) + + // get the day where the most commits were made + const { body } = await client.search({ + index: 'git', + body: new F() + .size(0) + // 'day_most_commits' is the name of the aggregation + .aggs( + A.day_most_commits.dateHistogram({ + field: 'committed_date', + interval: 'day', + min_doc_count: 1, + order: { _count: 'desc' } + }) + ) + }) + + console.log(body.aggregations) +} + +run1().catch(console.log) +run2().catch(console.log) diff --git a/dsl/examples/fix-commit.ts b/dsl/examples/fix-commit.ts index 5a3146be8..f6d8f81e5 100644 --- a/dsl/examples/fix-commit.ts +++ b/dsl/examples/fix-commit.ts @@ -18,9 +18,12 @@ */ import { Client } from '../../' -import { Q } from '../' +import { Q, F } from '../' -async function run () { +/** + * Pure function API + */ +async function run1 () { const client = new Client({ node: 'http://localhost:9200' }) // search commits that contains 'fix' but do not changes test files @@ -37,4 +40,24 @@ async function run () { console.log(body.hits.hits) } -run().catch(console.log) +/** + * Fluent API + */ +async function run2 () { + const client = new Client({ node: 'http://localhost:9200' }) + + // search commits that contains 'fix' but do not changes test files + const { body } = await client.search({ + index: 'git', + body: new F() + // You can avoid to call `.must`, as any query will be + // sent inside a `must` block unless specified otherwise + .must(f => f.match('description', 'fix')) + .mustNot(f => f.term('files', 'test')) + }) + + console.log(body.hits.hits) +} + +run1().catch(console.log) +run2().catch(console.log) diff --git a/dsl/examples/last-commits.ts b/dsl/examples/last-commits.ts index 5ba5b8856..52a72b058 100644 --- a/dsl/examples/last-commits.ts +++ b/dsl/examples/last-commits.ts @@ -18,9 +18,12 @@ */ import { Client } from '../../' -import { Q } from '../' +import { Q, F } from '../' -async function run () { +/** + * Pure function API + */ +async function run1 () { const client = new Client({ node: 'http://localhost:9200' }) // last 10 commits for 'elasticsearch-js' repo @@ -36,4 +39,23 @@ async function run () { console.log(body.hits.hits) } -run().catch(console.log) +/** + * Fluent API + */ +async function run2 () { + const client = new Client({ node: 'http://localhost:9200' }) + + // last 10 commits for 'elasticsearch-js' repo + const { body } = await client.search({ + index: 'git', + body: new F() + .term('repository', 'elasticsearch-js') + .sort('committed_date', { order: 'desc' }) + .size(10) + }) + + console.log(body.hits.hits) +} + +run1().catch(console.log) +run2().catch(console.log) diff --git a/dsl/examples/top-committers.ts b/dsl/examples/top-committers.ts index 7575b9ede..7c2f7ad2b 100644 --- a/dsl/examples/top-committers.ts +++ b/dsl/examples/top-committers.ts @@ -18,9 +18,12 @@ */ import { Client } from '../../' -import { Q, A } from '../' +import { Q, A, F } from '../' -async function run () { +/** + * Pure function API + */ +async function run1 () { const client = new Client({ node: 'http://localhost:9200' }) // top committers aggregation @@ -44,4 +47,31 @@ async function run () { console.log(body.aggregations) } -run().catch(console.log) +/** + * Fluent API + */ +async function run2 () { + const client = new Client({ node: 'http://localhost:9200' }) + + // top committers aggregation + // 'committers' is the name of the aggregation + const committersAgg = A.committers.terms( + { field: 'committer.name.keyword' }, + // you can nest multiple aggregations by + // passing them to the aggregation constructor + // 'line_stats' is the name of the aggregation + A.line_stats.stats({ field: 'stat.insertions' }) + ) + const { body } = await client.search({ + index: 'git', + body: new F() + .matchAll() + .size(0) + .aggs(committersAgg) + }) + + console.log(body.aggregations) +} + +run1().catch(console.log) +run2().catch(console.log) diff --git a/dsl/examples/top-month.ts b/dsl/examples/top-month.ts index 2ee122c29..677541535 100644 --- a/dsl/examples/top-month.ts +++ b/dsl/examples/top-month.ts @@ -18,9 +18,12 @@ */ import { Client } from '../../' -import { Q, A } from '../' +import { Q, A, F } from '../' -async function run () { +/** + * Pure function API + */ +async function run1 () { const client = new Client({ node: 'http://localhost:9200' }) const committers = A.committers.terms( @@ -58,4 +61,45 @@ async function run () { console.log(topMonths) } -run().catch(console.log) +/** + * Fluent API + */ +async function run2 () { + const client = new Client({ node: 'http://localhost:9200' }) + + const committers = A.committers.terms( + { field: 'committer.name.keyword' }, + A.insertions.sum({ field: 'stat.insertions' }) + ) + const topCommittersPerMonth = A.top_committer_per_month.maxBucket( + { bucket_path: 'committers>insertions' } + ) + const commitsPerMonth = A.commits_per_month.dateHistogram( + { + field: 'committed_date', + interval: 'day', + min_doc_count: 1, + order: { _count: 'desc' } + }, + // nested aggregations + committers, + topCommittersPerMonth + ) + const topCommittersPerMonthGlobal = A.top_committer_per_month.maxBucket( + { bucket_path: 'commits_per_month>top_committer_per_month' } + ) + + const { body: topMonths } = await client.search({ + index: 'git', + body: new F() + // we want to know the top month for 'delvedor' + .filter(f => f.term('author', 'delvedor')) + .size(0) + .aggs(commitsPerMonth, topCommittersPerMonthGlobal) + }) + + console.log(topMonths) +} + +run1().catch(console.log) +run2().catch(console.log)