--- title: Quickstart description: Get started with ParadeDB in five minutes canonical: https://docs.paradedb.com/documentation/getting-started/quickstart --- This guide will walk you through a few queries to give you a feel for ParadeDB. ## Create Example Table ParadeDB comes with a helpful procedure that creates a table populated with mock data to help you get started. Run the following command to create this table. ```sql CALL paradedb.create_bm25_test_table( schema_name => 'public', table_name => 'mock_items' ); ``` Then inspect the first 3 rows: ```sql SELECT description, rating, category FROM mock_items LIMIT 3; ``` ```ini Expected Response description | rating | category --------------------------+--------+------------- Ergonomic metal keyboard | 4 | Electronics Plastic Keyboard | 4 | Electronics Sleek running shoes | 5 | Footwear (3 rows) ``` Next, let's create a BM25 index called `search_idx` on this table. A BM25 index is a covering index, which means that multiple columns can be included in the same index. ```sql CREATE INDEX search_idx ON mock_items USING bm25 (id, description, category, rating, in_stock, created_at, metadata, weight_range) WITH (key_field='id'); ``` As a general rule of thumb, any columns that you want to filter, `GROUP BY`, `ORDER BY`, or aggregate as part of a full text query should be added to the index for faster performance. Note the mandatory `key_field` option. See [choosing a key field](/documentation/indexing/create-index#choosing-a-key-field) for more details. ## Match Query We're now ready to execute a basic text search query. We'll look for matches where `description` matches `running shoes` where `rating` is greater than `2`. ```sql SQL SELECT description, rating, category FROM mock_items WHERE description ||| 'running shoes' AND rating > 2 ORDER BY rating LIMIT 5; ``` ```python Django from paradedb import Match, ParadeDB MockItem.objects.filter( description=ParadeDB(Match('running shoes', operator='OR')), rating__gt=2 ).values('description', 'rating', 'category').order_by('rating')[:5] ``` ```ruby Rails MockItem.search(:description) .matching_any("running shoes") .where(rating: 3..) .select(:description, :rating, :category) .order(:rating) .limit(5) ``` ```ini Expected Response description | rating | category ---------------------+--------+---------- White jogging shoes | 3 | Footwear Generic shoes | 4 | Footwear Sleek running shoes | 5 | Footwear (3 rows) ``` `|||` is ParadeDB's custom [match disjunction](/documentation/full-text/match#disjunction) operator, which means "find me all documents containing `running OR shoes`. If we want all documents containing `running AND shoes`, we can use ParadeDB's `&&&` [match conjunction](/documentation/full-text/match#conjunction) operator. ```sql SQL SELECT description, rating, category FROM mock_items WHERE description &&& 'running shoes' AND rating > 2 ORDER BY rating LIMIT 5; ``` ```python Django from paradedb import Match, ParadeDB MockItem.objects.filter( description=ParadeDB(Match('running shoes', operator='AND')), rating__gt=2 ).values('description', 'rating', 'category').order_by('rating')[:5] ``` ```ruby Rails MockItem.search(:description) .matching_all("running shoes") .where(rating: 3..) .select(:description, :rating, :category) .order(:rating) .limit(5) ``` ```ini Expected Response description | rating | category ---------------------+--------+---------- Sleek running shoes | 5 | Footwear (1 row) ``` ## BM25 Scoring Next, let's add [BM25 scoring](/documentation/sorting/score) to the results, which sorts matches by relevance. To do this, we'll use `pdb.score`. ```sql SQL SELECT description, pdb.score(id) FROM mock_items WHERE description ||| 'running shoes' AND rating > 2 ORDER BY score DESC LIMIT 5; ``` ```python Django from paradedb import Match, ParadeDB, Score MockItem.objects.filter( description=ParadeDB(Match('running shoes', operator='OR')), rating__gt=2 ).annotate( score=Score() ).values('description', 'score').order_by('-score')[:5] ``` ```ruby Rails MockItem.search(:description) .matching_any("running shoes") .where(rating: 3..) .with_score .select(:description) .order(search_score: :desc) .limit(5) ``` ```ini Expected Response description | score ---------------------+----------- Sleek running shoes | 6.817111 Generic shoes | 3.8772602 White jogging shoes | 3.4849067 (3 rows) ``` ## Highlighting Finally, let's also [highlight](/documentation/full-text/highlight) the relevant portions of the documents that were matched. To do this, we'll use `pdb.snippet`. ```sql SQL SELECT description, pdb.snippet(description), pdb.score(id) FROM mock_items WHERE description ||| 'running shoes' AND rating > 2 ORDER BY score DESC LIMIT 5; ``` ```python Django from paradedb import Match, ParadeDB, Score, Snippet MockItem.objects.filter( description=ParadeDB(Match('running shoes', operator='OR')), rating__gt=2 ).annotate( snippet=Snippet('description'), score=Score() ).values('description', 'snippet', 'score').order_by('-score')[:5] ``` ```ruby Rails MockItem.search(:description) .matching_any("running shoes") .where(rating: 3..) .with_snippet(:description) .with_score .select(:description) .order(search_score: :desc) .limit(5) ``` ```ini Expected Response description | snippet | score ---------------------+-----------------------------------+----------- Sleek running shoes | Sleek running shoes | 6.817111 Generic shoes | Generic shoes | 3.8772602 White jogging shoes | White jogging shoes | 3.4849067 (3 rows) ``` ## Top K ParadeDB is highly optimized for quickly returning the [Top K](/documentation/sorting/topk) results out of the index. In SQL, this means queries that contain an `ORDER BY...LIMIT`: ```sql SQL SELECT description, rating, category FROM mock_items WHERE description ||| 'running shoes' ORDER BY rating LIMIT 5; ``` ```python Django from paradedb import Match, ParadeDB MockItem.objects.filter( description=ParadeDB(Match('running shoes', operator='OR')) ).values('description', 'rating', 'category').order_by('rating')[:5] ``` ```ruby Rails MockItem.search(:description) .matching_any("running shoes") .select(:description, :rating, :category) .order(:rating) .limit(5) ``` ```ini Expected Response description | rating | category ---------------------+--------+---------- White jogging shoes | 3 | Footwear Generic shoes | 4 | Footwear Sleek running shoes | 5 | Footwear (3 rows) ``` ## Facets [Faceted queries](/documentation/aggregates/facets) allow a single query to return both the Top K results and an aggregate value, which is more CPU-efficient than issuing two separate queries. For example, the following query returns the top 3 results as well as the total number of results matched. ```sql SQL SELECT description, rating, category, pdb.agg('{"value_count": {"field": "id"}}') OVER () FROM mock_items WHERE description ||| 'running shoes' ORDER BY rating LIMIT 5; ``` ```python Django from paradedb import Match, ParadeDB rows, facets = ( MockItem.objects .filter(description=ParadeDB(Match('running shoes', operator='OR'))) .order_by('rating') .values('description', 'rating', 'category')[:5] .facets(agg='{"value_count": {"field": "id"}}') ) ``` ```ruby Rails relation = MockItem.search(:description) .matching_any("running shoes") .with_agg(agg: ParadeDB::Aggregations.value_count(:id)) .order(:rating) .select(:description, :rating, :category) .limit(5) rows = relation.to_a facets = relation.aggregates ``` ```ini Expected Response description | rating | category | agg ---------------------+--------+----------+---------------- White jogging shoes | 3 | Footwear | {"value": 3.0} Generic shoes | 4 | Footwear | {"value": 3.0} Sleek running shoes | 5 | Footwear | {"value": 3.0} (3 rows) ``` That's it! Next, let's [load your data](/documentation/getting-started/load) to start running real queries.