Lesson 3: How to Think Like a Computer Using Boolean Logic

Special thanks to community contributor @thatgothlibrarian for co-writing this lesson. With his Boolean Logic 101 article, he gracefully provided clear examples to help us wrap our heads around Boolean operators. Do you want to help out writing educational content for the community? Send me a DM!


Does looking at queries cause you anxiety? Does it feel like you need to become a coder to use Logseq fully?

Don’t despair! It all looks scarier than it actually is.

To talk with a database like Logseq, you mostly need to understand how it thinks. In other words: you need to understand the basic logic that Logseq uses to search through your notes.

The type of logic that Logseq follows is called Boolean logic. While you may have never heard of this term, you most likely have applied it before.

Have you ever filtered results on an e-commerce website? For example, to only show results within a specific price range or with a minimum rating? Then you’ve used Boolean logic before.

In this lesson, we dive into the building blocks of Boolean logic:

  • True and False
  • AND, OR, NOT operators

True or False: the two possible results of Boolean logic

In the world of Boolean logic, things are very black and white. Something is either true, or it’s false; those are the only answers you can get from a Boolean question.

Two possible results, isn’t that very limiting? Remember that computers are dumb, and we must be precise with them. Boolean logic helps us to be precise.

Over the next few days, we’ll learn how Logseq uses Boolean logic. For now, you must remember that Logseq queries only show results that return true as an answer.

Let’s continue with the Boolean operators (called filters in Logseq). We’ll use these to filter out anything we don’t want to see in our search results.

The three basic Boolean operators

There are three basic Boolean operators: AND, OR, and NOT. But despite them being basic, their logic can be somewhat counter-intuitive.

Let’s walk through each step-by-step. To make things less abstract, we’ve assumed you’re a fan of Shakespeare and have lots of notes about his plays (who hasn’t!?). As Shakespeare was kinda obsessed with ghosts (they appear in five of his plays), we’ll use this theme throughout.

An important note: In this lesson, we use something called [pseudocode] for the query examples. We wanted to show you the logic behind Logseq queries without confusing you with the proper way to write them. While actual Logseq queries are close to our pseudocode, please remember that they are written differently. Tomorrow we’ll see the correct way of writing them.

AND :heavy_minus_sign:

First up, we have AND.

You might think, “Oh hey, AND. That sounds like it increases my results when searching!” But AND actually decreases our search/query results. Let us explain.

Imagine you’re searching through your collection of notes. You want to see everything you have about ‘ghosts’, so you search the keyword [[Ghosts]] (remember we use [[links]] as search terms in queries).

Let’s say you get 100 results from that. That’s a lot! You realize you actually only wanted to see results about ghosts in Shakespeare plays. You want to decrease your results, so you search for [[Ghosts]] AND [[Shakespeare]]. Now you only get 20 results.

AND means that all the results in our example must contain both the keywords [[Ghosts]] and [[Shakespeare]]. If we have a Venn diagram of items that contain Ghosts in one circle and items that contain Shakespeare in the other, our search for [[ghosts]] AND [[Shakespeare]] would give us results that are where those two circles overlap (the orange part in the middle):

OR :heavy_plus_sign:

On the other hand, what if we wanted results that contain Ghosts or Shakespeare? That’s what OR is for!

OR increases the number of search results.

In a Venn diagram, OR brings us the entirety of both circles and where they overlap. This OR is not exclusionary, meaning results can contain both or either.

You’ll get the 100 results from just searching Ghosts (including the overlaps with Shakespeare), plus any results about Shakespeare and not Ghosts. In our AND search, you wouldn’t have been able to see results about Romeo and Juliet, for example.

NOT :x:

Now we want to see results about Ghosts but not about Shakespeare. So, we search: [[Ghosts]] NOT [[Shakespeare]].

Let’s reason about how NOT functions, step-by-step:

  • If our original search for Ghosts was 100 results;
  • and if our search for [[Ghosts]] AND [[Shakespeare]] was only 20 notes;
  • then, the number of notes about Ghosts but not about Shakespeare is 80.

In a Venn diagram, this query would be only the part of the Ghost circle that didn’t overlap with the Shakespeare circle (the orange part on the left):

Combining Operators

As our notes collection grows, we will need more than just AND, OR, and NOT. We need to combine operators.

Returning to our example, we realize we actually do want to see results about Shakespeare, but we don’t want to see anything about Hamlet or Julius Caesar.

To build our search query, we’ll need to use parentheses. Like in math! This will tell the query how it should combine the operators.

Let’s have a first attempt at the combined query with our current knowledge:

  1. We want to see all notes about Ghosts: [[Ghosts]]
  2. We only want the results that are also about Shakespeare: [[Ghosts]] AND [[Shakespeare]]
  3. But we don’t want to see anything about Hamlet: [[Ghosts]] AND [[Shakespeare]] NOT [[Hamlet]]
  4. And we don’t want to see anything about Julius Caesar, either. It would make sense for our query to be: [[Ghosts]] AND [[Shakespeare]] NOT [[Hamlet]] OR [[Julius Caesar]]. Right?

Nope!

Think about the math problem 1 + 2 x 3.

Is the answer 9? 1 + 2, and then 3 x 3?

No, it’s 7. 2 x 3, and then 6 +1.

An easier way to write this equation is 1 + (2 x 3). The parentheses let us know which part of the equation to do first. In Boolean, parentheses do the same thing.

Let’s revisit what we want to know. We want results about Ghosts and Shakespeare, but we don’t want to see anything about Hamlet or Julius Caesar, which are both plays by Shakespeare.

Let’s start with those two plays: [[Hamlet]] OR [[Julius Caesar]].

Julius Caesar, however, is an actual historical figure, and there might be cool ghost stuff about him! So, we need to ensure that the Julius Caesar stuff is only about the Shakespeare play.

For this, our search would be [[Shakespeare]] NOT ([[Hamlet]] OR [[Julius Caesar]]).

And there’s our first set of parentheses! This is making sure our search is getting us results about Shakespeare, but not Hamlet or Julius Caesar.

Finally, we need to bring ghosts back in since that’s what we really care about: [[Ghosts]] AND ([[Shakespeare]] NOT ([[Hamlet]] OR [[Julius Caesar]])).

You’ll notice we put the previous query in its own set of parentheses, and that tells the query that Shakespeare and NOT (Hamlet OR Julius Caesar) are related. This means we can still get stuff about Julius Caesar, the person, but not Julius Caesar, the Shakespeare play. So, whatever results we get here, we can be sure they’re only related to ghosts.

These basics allow us to build practically any workflow we want in Logseq. Tomorrow, we’ll apply this logic to Logseq’s query syntax.

Additional resources

Need to spend some more time to wrap your head around Boolean logic? Check out these additional resources:

Exercise

Answer the following questions in writing. Don’t just write down the answer; also try to write down the individual steps that Logseq takes to interpret the query.

Post your answers as a comment, and take some time to read the answers of others.

The answer key is below.

  1. What operator should you use when you want to see results that contain either of two search terms?
  2. What operator should you use when you only want to see results that contain both of two search terms?
  3. What operator should you use when you only want to see results that contain one search term but do not contain another search term?
  4. True or False: given the following query, all blocks containing the link [[Hamlet]] will show in the results.
[[Hamlet]] OR [[Shakespeare]]
  1. True or False: given the following query, all blocks containing the link [[Ghosts]] will show in the results.
[[Ghosts]] NOT [[Shakespeare]]
  1. True or False: given the following query, all blocks containing the link [[Sharespeare]] will show in the results.
[[Shakespeare]] AND ([[Hamlet]] NOT [[Ghosts]])
Show answers
  1. OR
  2. AND
  3. NOT
  4. True. All blocks and branches that contain [[Hamlet]] will appear. However, not all results will contain [[Hamlet]] as the other half of the query looks at blocks/branches that contain [[Sharespeare]], even if they don’t contain [[Hamlet]].
  5. False. Only the blocks that contain [[Ghosts]] but not [[Shakespeare]] will appear. As soon as Logseq encounters [[Shakespeare]], the block containing the link and all of its child blocks get filtered out—even if it contains [[Ghosts]].
  6. False. Only the blocks and branches that contain both [[Shakespeare]] and [[Hamlet]] (but not [[Hamlet]] in combination with [[Ghosts]]) will appear in the query results.
1 Like
  1. What operator should you use when you want to see results that contain either of two search terms?

Term-1 OR Term-2

  1. What operator should you use when you only want to see results that contain both of two search terms?

Term-1 AND Term-2

  1. What operator should you use when you only want to see results that contain one search term but do not contain another search term?

Term-1 NOT Term-2

  1. True or False: given the following query, all blocks containing the link [[Hamlet]] will show in the results.
[[Hamlet]] OR [[Shakespeare]]

TRUE

  1. True or False: given the following query, all blocks containing the link [[Ghosts]] will show in the results.
[[Ghosts]] NOT [[Shakespeare]]

FALSE

  1. True or False: given the following query, all blocks containing the link [[Shakespeare]] will show in the results.
[[Shakespeare]] AND ([[Hamlet]] NOT [[Ghosts]])

FALSE

  1. What operator should you use when you want to see results that contain either of two search terms?
    [[ice cream]] or [[ice cream sandwiches]]
  2. What operator should you use when you only want to see results that contain both of two search terms?
    [[ice cream]] and [[ice cream sandwiches]]
  3. What operator should you use when you only want to see results that contain one search term but do not contain another search term?
    [[ice cream sandwiches]] not [[ice cream]]
  4. True or False: given the following query, all blocks containing the link [[Hamlet]] will show in the results.
    [[Hamlet]] OR [[Shakespeare]]
    True
  5. True or False: given the following query, all blocks containing the link [[Ghosts]] will show in the results.
    [[Ghosts]] NOT [[Shakespeare]]
    False
  6. True or False: given the following query, all blocks containing the link [[Shakespeare]] will show in the results.
    [[Shakespeare]] AND ([[Hamlet]] NOT [[Ghosts]])
    False
  1. To see either search term, specify only that search term without an operator.
  2. If both search terms must be present, then the operator is AND.
  3. If one search term must be present and the other must not, you achieve that with the operator NOT.
  4. With Hamlet OR Shakespeare, no blocks containing Hamlet are skipped, so True.
  5. Because Shakespeare also has Ghosts, you don’t get all Ghosts, so False.
  6. An AND always gives a restriction so False.
1 Like
  • [[Aug 24th, 2022]] Questions for this lesson are moving towards actual exercises, rather than just questions to answer:
    1. What operator should you use when you want to see results that contain either of two search terms?
      OR will show results that contain either or both of two search terms.
    2. What operator should you use when you only want to see results that contain both of two search terms?
      AND will show results only if both search terms are present.
    3. What operator should you use when you only want to see results that contain one search term but do not contain another search term?
      NOT will show all results for the first search term, but only if the second term is not also present.
    4. True or False: given the following query, all blocks containing the link [[Hamlet]] will show in the results:
      [[Hamlet]] OR [[Shakespeare]]
      TRUE: because OR will return all results that contain either one of the search terms.
    5. True or False: given the following query, all blocks containing the link [[Ghosts]] will show in the results:
      [[Ghosts]] NOT [[Shakespeare]]
      FALSE: because all blocks that contain [[Ghosts]] will show, except for those that also contain [[Shakespeare]].
    6. True or False: given the following query, all blocks containing the link [[Sharespeare]] will show in the results:
      [[Shakespeare]] AND ([[Hamlet]] NOT [[Ghosts]])
      FALSE: because ([[Hamlet]] NOT [[Ghosts]]) will only return results where [[Hamlet]] is present but [[Ghosts]] is not. From there the set of results will be filtered further, including only blocks where [[Shakespeare]] is also present. In effect: for a block containing [[Shakespeare]] to be included in results, it must also contain [[Hamlet]] and must not contain[[Ghosts]].

What I got wrong: I forgot to be specific about the hierarchy; for all answers, a block will show in results if it’s parent is present, unless it contains a search term excluded by NOT Also, if a parent and child each have one of the terms, they will show up in the results as well.

  1. What operator should you use when you want to see results that contain either of two search terms?
    OR. Logseq will search for pages that have Link 1 or Link 2, and include all of them.
  2. What operator should you use when you only want to see results that contain both of two search terms?
    AND, Logseq will include only pages that have both Link 1 and Link 2
  3. What operator should you use when you only want to see results that contain one search term but do not contain another search term?
    NOT. Logseq will include all pages with Link 1, excluding those with Link 2 as well.
  4. True or False: given the following query, all blocks containing the link [[Hamlet]] will show in the results.
[[Hamlet]] OR [[Shakespeare]]

True. As [[Hamlet]] is included in merely an OR operator, every page with the [[Hamlet]] link will be included in the results.
5. True or False: given the following query, all blocks containing the link [[Ghosts]] will show in the results.

[[Ghosts]] NOT [[Shakespeare]]

False. Logseq will retrieve all the pages, but will exclude [[Ghosts]] pages that include the [[Shakespeare]] tag.
6. True or False: given the following query, all blocks containing the link [[Sharespeare]] will show in the results.

[[Shakespeare]] AND ([[Hamlet]] NOT [[Ghosts]])

False Logseq will only include the [[Shakespeare]] pages that are linked [[Hamlet]], but lack the link [[Ghost]].

  • 1.What operator should you use when you want to see results that contain either of two search terms?

    • OR : [[A]] OR [[B]]
        1. select all blocks contain [[A]]
        1. then to selected blocks, add every block contains [[B]] that does not include [[A]]
  • 2.What operator should you use when you only want to see results that contain both of two search terms?

    • AND : [[A]] AND [[B]]
        1. select all blocks contain [[A]]
        1. then from selected blocks, remove the block that does not contain [[B]]
  • 3.What operator should you use when you only want to see results that contain one search term but do not contain another search term?

    • NOT : A not B ← that means [[A]] and (not [[B]] )
        1. “NOT” is strong operator so should be evaluated first.
        1. select all blocks that does not contain B
        1. then from selected blocks, select all blocks that contain [[A]]
          • I am not sure if this comment is right.
            I think as Attached figure No.3. Is it right?
            boolean_02
  • 4.True or False: given the following query, all blocks containing the link [[Hamlet]] will show in the results.

    [[Hamlet]] OR [[Shakespeare]]
    
    • TRUE
      • result of the OR operation contains all the link [[Hamlet]], (as well as all the link [[Shakespeare]])
  • 5.True or False: given the following query, all blocks containing the link [[Ghosts]] will show in the results.

    [[Ghosts]] NOT [[Shakespeare]]
    
    • FALSE
      • because the result does not contain [[Ghosts]] with [[Shakespear]]
  • 6.True or False: given the following query, all blocks containing the link [[Shakespeare]] will show in the results.

    [[Shakespeare]] AND ([[Hamlet]] NOT [[Ghosts]])
    
    • FALSE
2 Likes
  • What operator should you use when you want to see results that contain either of two search terms?
    • OR
  • What operator should you use when you only want to see results that contain both of two search terms?
    • AND
  • What operator should you use when you only want to see results that contain one search term but do not contain another search term?
    • NOT
  • True or False: given the following query, all blocks containing the link [[Hamlet]] will show in the results.

    ```
    	  [[Hamlet]] OR [[Shakespeare]]
    ```
    
    • True
  • True or False: given the following query, all blocks containing the link [[Ghosts]] will show in the results.

    ```
    	  [[Ghosts]] NOT [[Shakespeare]]
    ```
    
    • False, only Ghosts blocks that do not include shakespeare
  • True or False: given the following query, all blocks containing the link [[Sharespeare]] will show in the results.
    • [[Shakespeare]] AND ([[Hamlet]] NOT [[Ghosts]])
    • False, only shakespeare that also contains hamlet blocks that do not contain ghosts

What is a real world use case of this? So far I used only AND with multiple tags.


Nice comparison between boolean operators and addition/multiplication in arithmetic, indeed in Boolean Algebra we use + for OR, × for AND (× is usually tacit), ’ for NOT and we evaluate ’ before × and × before +, just like in arithmetic:

AB + CD'

means

(A and B) or (C and (not D))

so you could write

[[Alice]][[Bob]]+[[Charlie]][[David]]'

but it could be hard to interpret for who is not comfortable with Boolean Algebra.

3 Likes

What operator should you use when you want to see results that contain either of two search terms?
- You should use the OR operator as this will list results that match either of the conditions
What operator should you use when you only want to see results that contain both of two search terms?
- You should use the AND operator as this will only show results where both conditions are met
What operator should you use when you only want to see results that contain one search term but do not contain another search term?
- You should use the NOT operator as this will produce results where your condition is not matched
True or False: given the following query, all blocks containing the link [[Hamlet]] will show in the results.[[Hamlet]] OR [[Shakespeare]]
- True, the results will show all that contain [[Hamlet]] as well as those that match [[Shakespeare]]
True or False: given the following query, all blocks containing the link [[Ghosts]] will show in the results.[[Ghosts]] NOT [[Shakespeare]]
- False, the NOT operator will create results that show all results that match [[ghosts]] except for those that match [[Shakespeare]]
True or False: given the following query, all blocks containing the link [[Sharespeare]] will show in the results.
[[Shakespeare]] AND ([[Hamlet]] NOT [[Ghosts]])
- True, the AND condition will include all result where [[Shakespeare]] as well as those that match the conditions inside the parenthesis. The NOT condition in the parenthesis will give results all results that contain [[Hamlet]] except those that contain [[Ghosts]]

1 Like

@du20 I really like the graphic you created for this!

2 Likes

@alex0 Your Boolean Algebra example is helpful. Thanks for sharing it!

2 Likes
  1. What operator should you use when you want to see results that contain either of two search terms?
    OR
  2. What operator should you use when you only want to see results that contain both of two search terms?
    AND
  3. What operator should you use when you only want to see results that contain one search term but do not contain another search term?
    NOT
  4. True or False: given the following query, all blocks containing the link [[Hamlet]] will show in the results.
    [[Hamlet]] OR [[Shakespeare]]
    True - OR searches for both terms
  5. True or False: given the following query, all blocks containing the link [[Ghosts]] will show in the results.
    [[Ghosts]] NOT [[Shakespeare]]
    False - the search will not return results for blocks that also include the term [[Shakespeare]]
  6. True or False: given the following query, all blocks containing the link [[Sharespeare]] will show in the results.
    [[Shakespeare]] AND ([[Hamlet]] NOT [[Ghosts]])
    False - the search will only return results from blocks that also include [[Hamlet]] without [[Ghosts]]
  1. What operator should you use when you want to see results that contain either of two search terms?

OR

  1. What operator should you use when you only want to see results that contain both of two search terms?

AND

  1. What operator should you use when you only want to see results that contain one search term but do not contain another search term?

NOT

  1. True or False: given the following query, all blocks containing the link [[Hamlet]] will show in the results.
[[Hamlet]] OR [[Shakespeare]]

True

  1. True or False: given the following query, all blocks containing the link [[Ghosts]] will show in the results.
[[Ghosts]] NOT [[Shakespeare]]

False (blocks that contain both Ghosts and Shakespeare don’t)

  1. True or False: given the following query, all blocks containing the link [[Sharespeare]] will show in the results.
[[Shakespeare]] AND ([[Hamlet]] NOT [[Ghosts]])

False

1 Like

Thank you! I’m happy you like it.

1 Like

I think it’s best to separate the filter from the operator which is one of its parameters

After reading these two articles

Filter (higher-order function) - Wikipedia

and

https://docs.logseq.com/#/page/queries

I think Filters, Query Filters are synonymous: a type of query.

Operators, Query operators are synonymous: one of the parameters that go into the filters, the other parameter is the data.

The proper form in standard notation should be
Filter(operator, list1, list2, ...)
in logseq notation it’s probably
{{query (operator list1, list2, ...) }}

For example in this case
Filter(AND [[Ghosts]] [[Shakespeare]])
in logseq notation
{{query (AND [[Ghosts]], [[Shakespeare]]) }}

[[Ghosts]] and [[Shakespeare]] are two lists of blocks that contain the corresponding references

Each filter could use multiple different operators, and the same operator could be used in many filters. There really isn’t a one one correspondence between operators and filters.