Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix AS keyword bug #49

Merged
merged 4 commits into from
Jun 7, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions bql/planner/planner.go
Original file line number Diff line number Diff line change
Expand Up @@ -485,8 +485,14 @@ func (p *queryPlan) processGraphPattern(ctx context.Context, lo *storage.LookupO
// groups it by if needed.
func (p *queryPlan) projectAndGroupBy() error {
grp := p.stm.GroupByBindings()
if len(grp) == 0 {
// The table only needs to be projected.
if len(grp) == 0 { // The table only needs to be projected.
p.tbl.AddBindings(p.stm.OutputBindings())
// For each row, copy each input binding value to its appropriate alias.
for _, prj := range p.stm.Projections() {
for _, row := range p.tbl.Rows() {
row[prj.Alias] = row[prj.Binding]
}
}
return p.tbl.ProjectBindings(p.stm.OutputBindings())
}
// The table needs to be group reduced.
Expand Down
86 changes: 86 additions & 0 deletions bql/planner/planner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,32 @@ func populateTestStore(t *testing.T) storage.Store {
return s
}

func populateBenchmarkStore(b *testing.B) storage.Store {
s, ctx := memory.NewStore(), context.Background()
g, err := s.NewGraph(ctx, "?test")
if err != nil {
b.Fatalf("memory.NewGraph failed to create \"?test\" with error %v", err)
}
buf := bytes.NewBufferString(testTriples)
if _, err := io.ReadIntoGraph(ctx, g, buf, literal.DefaultBuilder()); err != nil {
b.Fatalf("io.ReadIntoGraph failed to read test graph with error %v", err)
}
trpls := make(chan *triple.Triple)
go func() {
if err := g.Triples(ctx, trpls); err != nil {
b.Fatal(err)
}
}()
cnt := 0
for _ = range trpls {
cnt++
}
if got, want := cnt, len(strings.Split(testTriples, "\n"))-1; got != want {
b.Fatalf("Failed to import all test triples; got %v, want %v", got, want)
}
return s
}

func TestPlannerQuery(t *testing.T) {
ctx := context.Background()
testTable := []struct {
Expand All @@ -272,11 +298,21 @@ func TestPlannerQuery(t *testing.T) {
nbs: 3,
nrws: len(strings.Split(testTriples, "\n")) - 1,
},
{
q: `select ?s as ?s1, ?p as ?p1, ?o as ?o1 from ?test where {?s ?p ?o};`,
nbs: 3,
nrws: len(strings.Split(testTriples, "\n")) - 1,
},
{
q: `select ?p, ?o from ?test where {/u<joe> ?p ?o};`,
nbs: 2,
nrws: 2,
},
{
q: `select ?p as ?p1, ?o as ?o1 from ?test where {/u<joe> ?p ?o};`,
nbs: 2,
nrws: 2,
},
{
q: `select ?s, ?p from ?test where {?s ?p /t<car>};`,
nbs: 2,
Expand Down Expand Up @@ -312,6 +348,11 @@ func TestPlannerQuery(t *testing.T) {
nbs: 1,
nrws: 4,
},
{
q: `select ?s as ?s1 from ?test where {?s "is_a"@[] /t<car>};`,
nbs: 1,
nrws: 4,
},
{
q: `select ?o from ?test where {/u<joe> "parent_of"@[] ?o. ?o "parent_of"@[] /u<john>};`,
nbs: 1,
Expand Down Expand Up @@ -461,6 +502,7 @@ func TestPlannerQuery(t *testing.T) {
tbl, err := plnr.Excecute(ctx)
if err != nil {
t.Errorf("planner.Excecute failed for query %q with error %v", entry.q, err)
continue
}
if got, want := len(tbl.Bindings()), entry.nbs; got != want {
t.Errorf("tbl.Bindings returned the wrong number of bindings for %q; got %d, want %d", entry.q, got, want)
Expand Down Expand Up @@ -519,3 +561,47 @@ func TestTreeTravesalToRoot(t *testing.T) {
t.Errorf("planner.Excecute failed to return the expected number of rows for query %q; got %d want %d\nGot:\n%v\n", traversalQuery, got, want, tbl)
}
}

// benchmarkQuery is a helper function that runs a specified query on the testing data set for benchmarking purposes.
func benchmarkQuery(query string, b *testing.B) {
ctx := context.Background()

s := populateBenchmarkStore(b)
p, err := grammar.NewParser(grammar.SemanticBQL())
if err != nil {
b.Fatalf("grammar.NewParser: should have produced a valid BQL parser with error %v", err)
}
b.ResetTimer()
for n := 0; n < b.N; n++ {
st := &semantic.Statement{}
if err := p.Parse(grammar.NewLLk(query, 1), st); err != nil {
b.Errorf("Parser.consume: failed to parse query %q with error %v", query, err)
}
plnr, err := New(ctx, s, st, 0)
if err != nil {
b.Errorf("planner.New failed to create a valid query plan with error %v", err)
}
_, err = plnr.Excecute(ctx)
if err != nil {
b.Errorf("planner.Excecute failed for query %q with error %v", query, err)
}
}
}

// These benchmark tests are used to observe the difference in speed between queries using the "as" keyword as opposed
// to queries that do not.
func BenchmarkReg1(b *testing.B) {
benchmarkQuery(`select ?p, ?o as ?o1 from ?test where {/u<joe> ?p ?o};`, b)
}

func BenchmarkAs1(b *testing.B) {
benchmarkQuery(`select ?p as ?p1, ?o as ?o1 from ?test where {/u<joe> ?p ?o};`, b)
}

func BenchmarkReg2(b *testing.B) {
benchmarkQuery(`select ?s, ?p, ?o from ?test where {?s ?p ?o};`, b)
}

func BenchmarkAs2(b *testing.B) {
benchmarkQuery(`select ?s as ?s1, ?p as ?p1, ?o as ?o1 from ?test where {?s ?p ?o};`, b)
}