Build a Search Engine with PHP and Elasticsearch
The idea was to test the functionality of elasticsearch.
I developed a basic website to be able to add bookmarks and references to websites, with the functionality of adding descriptive information about the bookmark.
So then when I search for my bookmarks it presents me with a link to go directly to the website that I have bookmarked when clicking on the title.
While this is only a basic example, Elasticsearch is extremely fast and very powerful, especially when you index it, with a LOT of data.
Setup Dependencies:
$ yum update -y
$ yum install curl -y
$ yum install php54 -y
Prepare needed directories:
$ mkdir {js,css,app}
$ wget -O css/bootstrap.min.css https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css
$ wget -O js/bootstrap.min.js "https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"
$ wget -O js/jquery.min.js https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js
Composer Configuration:
Include the following in your composer.json
file, please note I am using ES-1.5 at this moment.
$ vi composer.json
then add the following:
{
"require": {
"elasticsearch/elasticsearch": "~1.0"
}
}
Get Composer for PHP:
$ curl -s http://getcomposer.org/installer | php
$ php composer.phar install --no-dev
Configure your Elasticsearch Endpoint:
$ vi app/init.php
then provide the following content:
<?php
require_once 'vendor/autoload.php';
$es = new Elasticsearch\Client([
'hosts' => ['elasticsearch-domain']
]);
?>
Our PHP Files:
Our PHP files which will be embedded in HTML documents:
index.php
<?php
require_once 'app/init.php';
if(isset($_GET['q'])) {
$q = $_GET['q'];
$query = $es->search([
'body' => [
'query' => [
'bool' => [
'should' => [
'match' => ['title' => $q],
'match' => ['text' => $q]
]
]
]
]
]);
if($query['hits']['total'] >=1 ) {
$results = $query['hits']['hits'];
}
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Search | Document Search</title>
<link href="https://fonts.googleapis.com/css?family=Pattaya|Slabo+27px" rel="stylesheet">
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css" rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-social/4.10.1/bootstrap-social.css" rel="stylesheet" >
<link rel="icon" type="image/png" href="images/favicon.png">
<link href="//fonts.googleapis.com/css?family=Pattaya|Slabo+27px|Raleway:400,300,600" rel="stylesheet" type="text/css">
<link href="css/bootstrap.min.css" rel="stylesheet">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="author" content="Ruan Bekker">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="js/bootstrap.min.js"></script>
<script src="js/jquery.min.js"></script>
<style>
h1 {
font-family: 'Pattaya', sans-serif;
font-size: 59px;
position: relative;
right: -10px;
}
h3 {
font-family: 'Pattaya', sans-serif;
font-size: 20px;
position: relative;
right: -90px;
}
h4 {
font-family: 'Slabo', sans-serif;
font-size: 30px;
}
</style>
</head>
<body>
<ul class="nav nav-tabs">
<li role="presentation" class="active"><a href="index.php">Home</a></li>
<li role="presentation"><a href="add.php">Add Bookmark</a></li>
<li role="presentation"><a href="about.php">About</a></li>
</ul>
<br>
<div class="row vertical-center-row">
<div class="col-lg-4 col-lg-offset-4">
<div class="input-group">
<h1>Document Search</h1><p>
<h3>powered by php and elasticsearch</h3>
</div>
</div>
</div>
<br>
<br>
<form action="results.php" method="get" autocomplete="on">
<div class="row">
<div class="col-lg-4 col-lg-offset-4">
<div class="input-group">
<input type="text" name="q" placeholder="Search..." class="form-control" />
<span class="input-group-btn">
<button type="submit" class="btn btn-primary">Search</button>
</span>
</div>
</div>
</div>
</form>
<br>
<br>
<br>
<center>
<footer class="bd-footer text-muted" role="contentinfo">
<div class="container">
<ul class="bd-footer-links"></ul>
<p>Developed by <a rel="" href="http://ruanbekker.com/#contact" target="_blank">Ruan Bekker</a></p>
</div>
</footer>
</center>
</body>
</html>
add.php
<?php
require_once 'app/init.php';
if (!empty($_POST)) {
if(isset($_POST['title'], $_POST['link'], $_POST['text'])) {
$title = $_POST['title'];
$link = $_POST['link'];
$text = explode(',', $_POST['text']);
$indexed = $es->index([
'index' => 'kb',
'type' => 'bookmarks',
'body' => [
'title' => $title,
'link' => $link,
'text' => $text
]
]);
if($indexed) {
print_r($indexed);
}
}
}
?>
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Add | ES</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="description" content="Search engine powered by Elasticsearch" >
<meta name="author" content="Ruan Bekker">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/png" href="images/favicon.png">
<link href="//fonts.googleapis.com/css?family=Raleway:400,300,600" rel="stylesheet" type="text/css">
<link href="css/bootstrap.min.css" rel="stylesheet">
<script src="js/bootstrap.min.js"></script>
<script src="js/jquery.min.js"></script>
<link href="https://fonts.googleapis.com/css?family=Pattaya|Slabo+27px" rel="stylesheet">
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css" rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-social/4.10.1/bootstrap-social.css" rel="stylesheet" >
<style>
h1 {
font-family: 'Pattaya', sans-serif;
font-size: 59px;
position: relative;
right: -10px;
}
h3 {
font-family: 'Pattaya', sans-serif;
font-size: 20px;
position: relative;
right: -90px;
}
h4 {
font-family: 'Slabo', sans-serif;
font-size: 30px;
}
</style>
</head>
<body>
<ul class="nav nav-tabs">
<li role="presentation"><a href="index.php">Home</a></li>
<li role="presentation" class="active"><a href="add.php">Add Bookmark</a></li>
<li role="presentation"><a href="about.php">About</a></li>
</ul>
<br>
<div class="row vertical-center-row">
<div class="col-lg-4 col-lg-offset-4">
<div class="input-group">
<h1>Document Search</h1><p>
<h3>powered by php and elasticsearch</h3>
</div>
</div>
</div>
<br>
<form action="add.php" method="post" autocomplete="off">
<div class="col-lg-4 col-lg-offset-4">
<div class="input-group">
<span class="input-group-addon" id="sizing-addon2">Title</span>
<input type="text" name="title" class="form-control" placeholder="My Bookmark Name" aria-describedby="sizing-addon2"><p>
<p>
</div>
</div>
<div class="container">
<div class="row">
</div>
</div>
<p>
<br>
<div class="col-lg-4 col-lg-offset-4">
<div class="input-group">
<span class="input-group-addon" id="sizing-addon2">Link</span>
<input type="text" name="link" class="form-control" placeholder="http://example.org" aria-describedby="sizing-addon2">
</div>
</div>
<div class="container">
<div class="row">
</div>
</div>
<p>
<br>
<div class="col-lg-4 col-lg-offset-4">
<div class="input-group">
<span class="input-group-addon" id="sizing-addon2">Text</span>
<textarea type="text" rows="1" name="text" class="form-control" placeholder="descriptive info about my bookmark" aria-describedby="sizing-addon2"></textarea>
</div>
</div>
</div>
<div class="container">
<div class="row">
</div>
</div>
<p>
<br>
<div class="row vertical-center-row">
<div class="col-lg-4 col-lg-offset-4">
<div class="center-block">
<center
<br><input type="submit" class="btn btn-success" value="Submit Bookmark Entry">
</center>
</form>
<br>
<center>
<a class="btn btn-danger" style="width:176px" href="index.php">Back to Search</a>
</center>
</div>
</div>
</div>
</body>
</html>
results.php
<?php
require_once 'app/init.php';
if(isset($_GET['q'])) {
$q = $_GET['q'];
$query = $es->search([
'body' => [
'query' => [
'bool' => [
'should' => [
'match' => ['title' => $q],
'match' => ['text' => $q]
]
]
]
]
]);
if($query['hits']['total'] >=1 ) {
$results = $query['hits']['hits'];
}
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Search | Document Search</title>
<meta name="description" content="search-results">
<meta name="author" content="Ruan Bekker">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="//fonts.googleapis.com/css?family=Pattaya|Slabo+27px|Raleway:400,300,600" rel="stylesheet" type="text/css">
<link href="css/bootstrap.min.css" rel="stylesheet">
<link rel="icon" type="image/png" href="images/favicon.png">
<script src="js/bootstrap.min.js"></script>
<script src="js/jquery.min.js"></script>
<style>
h1 {
font-family: 'Pattaya', sans-serif;
font-size: 59px;
position: relative;
right: -10px;
}
h3 {
font-family: 'Pattaya', sans-serif;
font-size: 20px;
position: relative;
right: -90px;
}
h4 {
font-family: 'Slabo', sans-serif;
font-size: 30px;
}
</style>
</head>
<body>
<ul class="nav nav-tabs">
<li role="presentation"><a href="index.php">Home</a></li>
<li role="presentation"><a href="add.php">Add Bookmark</a></li>
<li role="presentation"><a href="about.php">About</a></li>
</ul>
<br>
<div class="row vertical-center-row">
<div class="col-lg-4 col-lg-offset-4">
<div class="input-group">
<h1>Document Search</h1><p>
<h3>powered by php and elasticsearch</h3>
</div>
</div>
</div>
<br>
<br>
<form action="results.php" method="get" autocomplete="on">
<div class="row">
<div class="col-lg-4 col-lg-offset-4">
<div class="input-group">
<input type="text" name="q" placeholder="Search..." class="form-control" />
<span class="input-group-btn">
<button type="submit" class="btn btn-primary">Search</button>
<a class="btn btn-danger" href="index.php">Back</a>
</span>
</div>
</div>
</div>
</form>
<br>
<br>
<div class="container">
<div class="row" style="text-align: center">
<h2> Search Results: </h2>
</div>
</div>
<?php
if(isset($results)) {
foreach($results as $r) {
?>
<div class="row" style="text-align: center">
<div class="container">
<div class="panel panel-success">
<div class=panel-heading>
<h2 class=panel-title>
<a href="<?php echo $r['_source']['link']; ?>" target="_blank"><p><br>
<?php echo $r['_source']['title']; ?>
</a>
</div>
<br><br>
<b>Content:</b><p>
<?php echo implode(', ', $r['_source']['text']); ?><p></p><br>
<div class="">
<b>DocId:</b>
<center>
<?php echo $r['_id']; ?>
</center>
<br>
</div>
</div>
</div>
<?php
}
}
?>
</body>
</html>
about.php
<?php
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Search | Document Search</title>
<meta name="description" content="">
<meta name="author" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/png" href="images/favicon.png">
<link href="//fonts.googleapis.com/css?family=Pattaya|Slabo+27px|Raleway:400,300,600" rel="stylesheet" type="text/css">
<link href="css/bootstrap.min.css" rel="stylesheet">
<script src="js/bootstrap.min.js"></script>
<script src="js/jquery.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css" rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-social/4.10.1/bootstrap-social.css" rel="stylesheet" >
<style>
h1 {
font-family: 'Pattaya', sans-serif;
font-size: 59px;
position: relative;
right: 0px;
}
h2 {
font-family: 'Pattaya', sans-serif;
font-size: 40px;
position: relative;
right: 0px;
}
h3 {
font-family: 'Pattaya', sans-serif;
font-size: 20px;
position: relative;
right: -90px;
}
h4 {
font-family: 'Slabo', sans-serif;
font-size: 30px;
}
</style>
</head>
<body>
<ul class="nav nav-tabs">
<li role="presentation"><a href="index.php">Home</a></li>
<li role="presentation"><a href="add.php">Add Bookmark</a></li>
<li role="presentation" class="active"><a href="about.php">About</a></li>
</ul>
<br>
<center>
<div class="row vertical-center-row">
<div class="center-block">
<div class="jumbotron">
<h1>About</h1>
<p></p>
<br>
<address>
<strong><h4>About this project:</h4></strong><p></p>
This project was made purely to test the functionality of Elasticsearch<br>
</address>
<address>
<strong><h4>About me?</h4></strong><p></p>
Linux Fanatic | OpenSource Enthusiast | Linux Junkie<br>
</address>
<address>
<h4>Strenghts:</h4><p></p>
Linux System Administration<br>
Cloud Support, AWS<br>
Big Data<br>
</address>
<address>
<h4>Current Location:</h4><br>
Cape Town, South Africa<br>
<br><img src="images/capetown.jpg" width="360" height="250" class="img-fluid" alt="Built with Elasticsearch">
</address>
<br>
<h2>Get in Contact</h2><br>
<ul class="list-inline">
<li>
<a href="https://facebook.com/ruan.bekker" class="btn-social btn-outline"><i class="fa fa-fw fa-facebook"></i></a>
</li>
<li>
<a href="#" class="btn-social btn-outline"><i class="fa fa-fw fa-google-plus"></i></a>
</li>
<li>
<a href="https://twitter.com/ruanbekker" class="btn-social btn-outline"><i class="fa fa-fw fa-twitter"></i></a>
</li>
<li>
<a href="https://za.linkedin.com/in/ruanbekker" class="btn-social btn-outline"><i class="fa fa-fw fa-linkedin"></i></a>
</li>
<li><a href="https://github.com/ruanbekker" class="btn-social btn-outline" ><i class="fa fa-fw fa-github"></i></a>
<li><a href="//ruanbekker.com" class="btn-social btn-outline" target="_blank"><i class="fa fa-fw fa-google"></i></a>
<li><a href="mailto:ruan@ruanbekker.com" class="btn-social btn-outline" title="Email"><i class="fa fa-fw fa-envelope"></i></a>
</li>
</ul>
</div>
</div>
</div>
</div>
</center>
<br>
<br>
<center>
<footer class="bd-footer text-muted" role="contentinfo">
<div class="container">
<ul class="bd-footer-links"></ul>
<p>Developed by <a rel="" href="http://ruanbekker.com/#contact" target="_blank">Ruan Bekker</a></p>
</div>
</footer>
</center>
</body>
</html>
Directory Structure:
When completing this tutorial, your directory structure should look more or less like this:
├── about.php
├── add.php
├── app
│ ├── init.php
├── composer.json
├── composer.lock
├── composer.phar
├── css
│ ├── bootstrap.min.css
│ ├── normalize.css
├── images
│ ├── favicon.png
├── index.php
├── js
│ ├── bootstrap.min.js
│ └── jquery.min.js
├── results.php
└── vendor
Source Code is available here
Full demo is available here
Credit goes to codecademy