Algolia is a hosted search engine, offering full-text, numerical, and faceted search, capable of delivering real-time results from the first keystroke. Algolia's powerful API lets you quickly and seamlessly implement search within your websites and mobile applications. Our search API powers billions of queries for thousands of companies every month, delivering relevant results in under 100ms anywhere in the world.
Resources
Well before continuing, i believe most of you are fimailiar with django
, and won't be explaining much of it.
Demo:
Setup
- create a project or clone from github
- create Virtualenv.
virtualenv venv
- create requirements.txt
Django==4.0.5
django-taggit==3.0.0
django-treebeard==4.5.1
djangorestframework==3.13.1
algoliasearch-django==2.0.0
django-environ==0.8.1
- create a new app
algolia_search
in the project
python manage.py startapp algolia_search
- create
.env
file
DJANGO_SUPERUSER_PASSWORD=root
DJANGO_SUPERUSER_USERNAME=root
DJANGO_SUPERUSER_EMAIL=root@root.com
APPLICATION_ID=
ADMIN_API_KEY=
SEARCH_ONLY_API_KEY=
Config Settings
configure the settings.py
file
import os
import environ
from pathlib import Path
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
env = environ.Env()
environ.Env.read_env(os.path.join(BASE_DIR, ".env"))
INSTALLED_APPS = [
# *** 3rd party apps ***
"rest_framework",
"rest_framework.authtoken",
"treebeard",
"taggit",
"algoliasearch_django",
# ** apps **
"algolia_search
]
ALGOLIA = {
"APPLICATION_ID": os.environ.get("APPLICATION_ID"),
"API_KEY": os.environ.get("ADMIN_API_KEY"),
"SEARCH_API_KEY": os.environ.get("SEARCH_ONLY_API_KEY"),
}
Creating Models
# algolia_search/models.py
from this import s
from unicodedata import category
from django.db import models
from django.db.models import Manager, QuerySet
from taggit.managers import TaggableManager
from treebeard.mp_tree import MP_Node
from django.contrib.auth import get_user_model
User = get_user_model()
class TimeStamp(models.Model):
created_at = models.DateTimeField(auto_now_add=True)
update_at = models.DateTimeField(auto_now=True)
class Meta:
abstract = True
class Category(MP_Node):
class Meta:
db_table = "categories"
verbose_name_plural = "Categories"
name = models.CharField(max_length=30)
node_order_by = ["name"]
def __str__(self):
return f"Category: {self.name}"
class ArticleQuerySet(QuerySet):
def update(self, **kwargs):
super(ArticleQuerySet, self).update(**kwargs)
class CustomManager(Manager):
def get_queryset(self):
return ArticleQuerySet(self.model, using=self._db)
class ArticleLike(TimeStamp):
class Meta:
db_table = "article_like"
unique_together = ("user", "article")
user = models.ForeignKey(User, on_delete=models.CASCADE)
article = models.ForeignKey(
"Article", on_delete=models.CASCADE, related_name="likes_article"
)
class Article(TimeStamp):
class Meta:
db_table = "articles"
category = models.ForeignKey(Category, on_delete=models.SET_NULL, null=True)
title = models.CharField(max_length=255)
description = models.TextField(null=True, blank=True)
is_published = models.BooleanField(default=False)
tags = TaggableManager()
likes = models.ManyToManyField(
User, related_name="user_likes_article", through=ArticleLike, blank=True
)
objects = CustomManager()
def __str__(self):
return self.title
def is_published_indexing(self):
return self.is_published == True
@property
def likes_count(self):
return int(self.likes.count())
@property
def tags_indexing(self):
return [tag.name for tag in self.tags.all()]
@property
def category_indexing(self):
return list(self.category.get_descendants())
Modify admin.py
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import User
from django.db import models
from django.utils.safestring import mark_safe
from treebeard.admin import TreeAdmin
from treebeard.forms import movenodeform_factory
from algolia_search.models import Article, Category, ArticleLike
class UserAdmin(UserAdmin):
model = User
list_display = (
"username",
"email",
"is_staff",
"is_active",
)
list_filters = (
"username",
"email",
"is_staff",
"is_active",
)
fieldsets = (
(None, {"fields": ("username", "email", "password")}),
(
"Permissions",
{
"fields": (
"is_staff",
(
"is_active",
"is_superuser",
),
)
},
),
("Important dates", {"fields": ("last_login", "date_joined")}),
("Advanced options", {"classes": ("collapse",), "fields": ("groups",)}),
)
add_fieldsets = (
(
None,
{
"classes": ("wide",),
"fields": (
"username",
"email",
"password1",
"password2",
"is_staff",
"is_active",
"is_superuser",
"groups",
),
},
),
)
admin.site.unregister(User)
admin.site.register(User, UserAdmin)
class CategoryAdmin(TreeAdmin):
form = movenodeform_factory(Category)
admin.site.register(Category, CategoryAdmin)
class ArticleLikeInline(admin.TabularInline):
model = ArticleLike
extra = 0
class ArticleAdmin(admin.ModelAdmin):
list_display = [
"id",
"title",
"get_tags",
"likes_count",
"is_published",
]
search_fields = ["id", "title"]
def get_tags(self, article):
tags = [str(tag) for tag in article.tags.all()]
return ", ".join(tags)
inlines = [
ArticleLikeInline,
]
admin.site.register(Article, ArticleAdmin)
Create index.py
file.
# algolia_search/index.py
import algoliasearch_django as algoliasearch
from algoliasearch_django import AlgoliaIndex
from .models import Article
class ArticleIndex(AlgoliaIndex):
"""Index for Article model"""
# ** fields to index if is_published is True
name = "article"
should_index = "is_published_indexing"
fields = (
"title",
"description",
"is_published",
"tags_indexing",
"category_indexing",
"likes_count",
)
settings = {
"searchableAttributes": [
"title",
"description",
"tags_indexing",
"category_indexing",
],
"attributesForFaceting": [
"title",
"tags_indexing",
"description",
"category_indexing",
],
"queryType": "prefixAll",
# ** custom ranking rules with like_count
"customRanking": [
"desc(likes_count)",
],
"advancedSyntax": True,
"highlightPreTag": "<mark>",
"highlightPostTag": "</mark>",
"hitsPerPage": 15,
}
index_name = "articles"
algoliasearch.register(Article, ArticleIndex)
- Above we created
ArticleIndex
class for indexing.
should_index = "is_published_indexing"
- here
should_index
attribute helps to indexArticle
object whichis_published
is true. So, if it is false no objects are indexed.
fields = (
"title",
"description",
"is_published",
"category_indexing",
"tags_indexing",
"likes_count",
)
- Simply, it is just defining out fields from
article
models.
settings = {
"searchableAttributes": [
"title",
"description",
"tags_indexing",
"category_indexing",
],
"attributesForFaceting": [
"title",
"tags_indexing",
"description",
"category_indexing",
],
"queryType": "prefixAll",
# ** custom ranking rules with like_count
"customRanking": [
"desc(likes_count)",
],
"advancedSyntax": True,
"highlightPreTag": "<mark>",
"highlightPostTag": "</mark>",
"hitsPerPage": 15,
}
in setting options:
- searchableAttributes: The complete list of attributes used for searching.
-
attributesForFaceting: The complete list of attributes that will be used for faceting.
- to turn an attribute into a facet
- to make any string attribute filterable.
-
queryType: Controls if and how query words are interpreted as prefixes.
- prefixAll: All query words are interpreted as prefixes. This option is not recommended, as it tends to yield counterintuitive results and has a negative impact on performance.
- prefixLast: Only the last word is interpreted as a prefix (default behavior).
- prefixNone: No query word is interpreted as a prefix. This option is not recommended, especially in an instant search setup, as the user will have to type the entire word(s) before getting any relevant results.
-
customRanking: Specifies the custom ranking criterion.
- Modifiers:#
- asc: Sort by increasing value of the attribute.
- desc: Sort by decreasing value of the attribute.
Note: we have our custom rank according to like count of
articles
-
advancedSyntax: Enables the advanced query syntax.
- This advanced syntax brings two additional features:
- Phrase query: a specific sequence of terms that must be matched next to one another. A phrase query needs to be surrounded by double quotes ("). For example, the query "search engine" only returns a record if it contains “search engine” exactly in at least one attribute.
Note: Typo tolerance is disabled inside the phrase (i.e. within the quotes).
-
Prohibit operator: excludes records that contain a specific term. To exclude a term, you need to prefix it with a minus (-). The engine only interprets the minus (-) as a prohibit operator when you place it at the start of a word. A minus (-) within double quotes (") is not treated as a prohibit operator.
- highlightPreTag: The HTML string to insert before the highlighted parts in all highlight and snippet results.
- highlightPostTag: The HTML string to insert after the highlighted parts in all highlight and snippet results.
- hitsPerPage: is a widget that displays a menu of options to change the number of results per page.
Finally, register Article
, ArticleIndex
.
Creating Custom Commands.
- create dir
algolia_search/management/commands
& copy from following links. - After creating then run the following commands
$ python manage.py migrate
$ python manage.py makemigrations
$ python manage.py seed_superuser
$ python manage.py seed_users
$ python manage.py seed_articles
$ python manage.py seed_likes
ALgolia Dashboard:
so we are going to create index and query suggestion:
- index: indexing a list of article objects.
-
query suggestion: retrieves articles matching the query and displays a preview
- Login to Algolia with your desired accounts.
- create new application
- Select Algolia Package
-select a region, suitable for you
- click on
Review Application Details
- click on
check boxes
andcreate application
- create index
articles
- Return to Dashboard and click on
API keys
- Copy
keys
fromApplication ID
,Search-only API Key
, andAdmin API Key and paste it to
.env` file
- Run commands python to index your data from backends:
$ python manage.py algolia_reindex
- Go to home
Dashboard
and click on articles.
- List of datas are displayed as shown below
Create query suggestions
- click on
query suggestions
tab.
- click button to create
query suggestions
Accept and continue, wait for a while until it creates your
suggestion index
click to Edit Categories button and add the following categories attributes as shown in image.
- click to save button and wait for a while until it re-index.
Frontend Integration
- Algolia suggest to use InstantSearch.js library to build your search interface and perform search queries directly from the end-user browser without going through your server.
Orginal code: Autocomplete with React InstantSearch Hooks example
well, i had made some changes from original src code.
lyamaa
/
algolia-search-frontend
ALgolia search in React
lyamaa / algolia-search-frontend
ALgolia search in React
Final Words
Well, i found algolia to be simple and easy to configure than elastic search. ES is much more of writing code than algolia and bit more of complex.
Read comparision of ES and algolia : Algolia VS Elasticsearch
till then Bye bye 👋👋👋...
Top comments (0)