forked from elastic/examples
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request elastic#11 from ycombinator/master
Merging demo project from personal repo into elastic/demo as subfolder
- Loading branch information
Showing
13 changed files
with
520 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
vendor/ | ||
composer.lock |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
# Recipe Search - Simple | ||
|
||
This sample application demonstrates: | ||
* Searching for recipes by keywords, *and* | ||
* Creating new recipes and saving them in Elasticsearch | ||
|
||
 | ||
|
||
This sample application deliberately uses plain PHP code (that is, no PHP frameworks), a little bit of | ||
[Bootstrap CSS](http://getbootstrap.com/css/) and even less [jQuery](https://jquery.com/). These minimalist choices | ||
are deliberate. We want to keep non-Elasticsearch-related code to a minimum so it as easy as possible to focus on the | ||
Elasticsearch-related code in this application. | ||
|
||
## Running this on your own machine | ||
|
||
1. Download and install PHP. | ||
|
||
1. Download and unzip Elasticsearch. | ||
|
||
```sh | ||
$ wget 'https://download.elastic.co/elasticsearch/elasticsearch/elasticsearch-1.5.1.zip' | ||
$ unzip elasticsearch-1.5.1.zip | ||
``` | ||
|
||
1. Start a 1-node Elasticsearch cluster. | ||
|
||
```sh | ||
$ cd elasticsearch-1.5.1 | ||
$ ./bin/elasticsearch # The process started by this command corresponds to a single Elasticsearch node | ||
``` | ||
|
||
By default the node's REST API will be available at `http://localhost:9200`, unless port 9200 is already taken. In | ||
that case Elasticsearch will automatically choose another port. Read through the log messages emitted when you | ||
start the node, and look for a log message containing `http`. In this message, look for `bound_address` and note the | ||
port shown in the accompanying network address. | ||
|
||
1. Download the code in this repo and unzip it. | ||
|
||
```sh | ||
$ wget -O elastic-demo.zip 'https://github.com/elastic/demo/archive/master.zip' | ||
$ unzip elastic-demo.zip | ||
$ mv demo-master/recipe_search_simple . | ||
$ rm -rf demo-master elastic-demo.zip | ||
$ cd recipe_search_simple | ||
``` | ||
|
||
1. Install application dependencies. | ||
|
||
```sh | ||
$ composer install | ||
``` | ||
|
||
1. Seed Elasticsearch index with initial recipe data. | ||
|
||
```sh | ||
$ php data/seed.php | ||
``` | ||
|
||
1. Start the application using PHP's built-in web server. | ||
|
||
```sh | ||
$ cd public | ||
$ php -S localhost:8000 | ||
``` | ||
|
||
By default this application will communicate with the Elasticsearch API at `http://localhost:9200`. If, in step 3, you | ||
noted a different port than 9200 being used, you will need to pass this information to the application when starting | ||
it up via an environment variable: | ||
|
||
```sh | ||
$ APP_ES_PORT=<PORT> php -S localhost:8000 | ||
``` | ||
|
||
1. Open your web browser and visit [`http://localhost:8000`](http://localhost:8000). | ||
|
||
## Code Organization | ||
The code in this project is organized as follows, starting at the root directory level (only relevant files and folders listed): | ||
|
||
* `data/` — *contains seed data and loader script* | ||
* `seed.txt` — *contains seed data in [bulk index](http://www.elastic.co/guide/en/elasticsearch/guide/master/bulk.html) format* | ||
* `seed.php` — *script to load seed data* | ||
* `public/` — *contains files served by web server* | ||
* `css/` — *contains the Bootstrap CSS file* | ||
* `js/` — *contains the jQuery and this project's Javascript files* | ||
* `add.php` — *script to add a new recipe to Elasticsearch* | ||
* `index.php` — *script to search for recipes in Elasticsearch* | ||
* `view.php` — *script to view a recipe from Elasticsearch* | ||
* `composer.json` — *file describing application dependencies, including the [Elasticsearch PHP language client](http://www.elastic.co/guide/en/elasticsearch/client/php-api/current/index.html)* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
{ | ||
"require": { | ||
"elasticsearch/elasticsearch": "~1.0" | ||
}, | ||
"autoload": { | ||
"psr-4": { "RecipeSearchSimple\\": "src/RecipeSearchSimple/" } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
<?php | ||
|
||
require __DIR__ . '/../vendor/autoload.php'; | ||
|
||
use RecipeSearchSimple\Constants; | ||
|
||
// Connect to local Elasticsearch node | ||
$esPort = getenv('APP_ES_PORT') ?: 9200; | ||
$client = new Elasticsearch\Client([ | ||
'hosts' => [ 'localhost:' . $esPort ] | ||
]); | ||
|
||
// Delete index to clear out existing data | ||
$deleteParams = []; | ||
$deleteParams['index'] = Constants::ES_INDEX; | ||
|
||
if ($client->indices()->exists($deleteParams)) { | ||
$client->indices()->delete($deleteParams); | ||
} | ||
|
||
// Setup bulk index request for seed data | ||
$params = []; | ||
$params['index'] = Constants::ES_INDEX; | ||
$params['type'] = Constants::ES_TYPE; | ||
$params['body'] = file_get_contents(__DIR__ . '/seed.txt'); | ||
|
||
// Bulk load seed data | ||
$ret = $client->bulk($params); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
{ "index": { "_id": "lemon-chicken" } } | ||
{ "name": "Lemon chicken", "description": "Baked boneless chicken with lemon-garlic seasoning", "cooking_time_min": 40, "ingredients": [ "Chicken breast, 1 fillet", "Lemon-garlic seasoning, 2 tbsp", "Olive oil, 1 tbsp" ], "directions": [ "Pre-heat oven to 350 F.", "Take an oven-safe ceramic utensil and add the olive oil to it.", "Place the chicken in the olive oil and move it around until it is completely covered by the oil.", "Sprinkle about half the lemon-pepper seasoning on one side, usually the top, of the chicken.", "Place the utensil in the oven once it has heated up to 350 F.", "After 20 minutes, remove the utensil, flip the chicken, sprinkle the rest of the seasoning on the other side and put the utensil back in the oven.", "After another 20 minutes, remove the utensil, slice up the chicken to desired size and serve hot."], "servings": 2 } | ||
{ "index": { "_id": "salmon-in-dill-sauce" } } | ||
{ "name": "Salmon in dill sauce", "description": "Baked and broiled salmon fillet in dill-mayo sauce", "cooking_time_min": 25, "tags": "fish", "ingredients": [ "Salmon, 1 fillet" ], "directions": [ "Pre-heat oven to 400 F.", "Do other stuff." ] } | ||
{ "index": { "_id": "masala-chai" } } | ||
{ "name": "Masala chai", "description": "Hot street-style Indian beverage infused with ginger and cardamom", "cooking_time_min": 15 } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,172 @@ | ||
<?php | ||
|
||
require __DIR__ . '/../vendor/autoload.php'; | ||
|
||
use RecipeSearchSimple\Constants; | ||
use RecipeSearchSimple\Util; | ||
|
||
// Add recipe if one was submitted | ||
if (count($_POST) > 0) { | ||
|
||
// Connect to Elasticsearch (1-node cluster) | ||
$esPort = getenv('APP_ES_PORT') ?: 9200; | ||
$client = new Elasticsearch\Client([ | ||
'hosts' => [ 'localhost:' . $esPort ] | ||
]); | ||
|
||
// Convert recipe name to ID | ||
$id = Util::recipeNameToId($_POST['name']); | ||
|
||
// Check if recipe with this ID already exists | ||
$exists = $client->exists([ | ||
'id' => $id, | ||
'index' => Constants::ES_INDEX, | ||
'type' => Constants::ES_TYPE | ||
]); | ||
|
||
if ($exists) { | ||
$message = 'A recipe with this name already exists. You can view it ' | ||
. '<a href="/view.php?id=' . $id . '">here</a> or rename your recipe.'; | ||
} else { | ||
// Index the recipe in Elasticsearch | ||
$document = [ | ||
'id' => $id, | ||
'index' => Constants::ES_INDEX, | ||
'type' => Constants::ES_TYPE, | ||
'body' => $_REQUEST | ||
]; | ||
$client->index($document); | ||
|
||
// Redirect user to recipe view page | ||
$message = 'Recipe added!'; | ||
header('Location: /view.php?id=' . $id . '&message=' . $message); | ||
exit(); | ||
} | ||
|
||
} | ||
?> | ||
<html> | ||
<head> | ||
<title>Recipe Search</title> | ||
<link rel="stylesheet" href="/css/bootstrap.min.css" /> | ||
</head> | ||
<body> | ||
<div class="container bg-danger" id="message"> | ||
<?php | ||
if (!empty($message)) { | ||
?> | ||
<p><?php echo $message; ?></p> | ||
<?php | ||
} | ||
?> | ||
</div> | ||
<div class="container"> | ||
<h1>Add Recipe</h1> | ||
<form method="post" action="<?php echo $_SERVER['PHP_SELF']; ?>"> | ||
|
||
<!-- Basic information about the recipe --> | ||
<div class="container"> | ||
<h3>The Basics</h3> | ||
<div class="form-group"> | ||
<div class="row"> | ||
<div class="col-xs-7"> | ||
<label for="name">Name</label> | ||
<input name="name" value="<?php echo $_REQUEST['name']; ?>" required="true" class="form-control" /> | ||
</div> | ||
<div class="col-xs-2"> | ||
<label for="cooking_time_min">Cooking time</label> | ||
<input name="cooking_time_min" value="<?php echo $_REQUEST['cooking_time_min']; ?>" type="number" placeholder="minutes" class="form-control"/> | ||
</div> | ||
<div class="col-xs-1"> | ||
<label for="servings">Servings</label> | ||
<input name="servings" value="<?php echo $_REQUEST['servings']; ?>" type="number" class="form-control"/> | ||
</div> | ||
</div> | ||
</div> | ||
<div class="form-group"> | ||
<div class="row"> | ||
<div class="col-xs-10"> | ||
<label for="description">Description</label> | ||
<input name="description" value="<?php echo $_REQUEST['description']; ?>" required="true" class="form-control"/> | ||
</div> | ||
</div> | ||
</div> | ||
<div class="form-group"> | ||
<div class="row"> | ||
<div class="col-xs-10"> | ||
<label for="tags">Tags</label> | ||
<input name="tags" value="<?php echo $_REQUEST['tags']; ?>" placeholder="Comma-separated" class="form-control"/> | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
|
||
<!-- Ingredients --> | ||
<div class="container"> | ||
<h3>Ingredients</h3> | ||
<?php | ||
if (isset($_REQUEST['ingredients']) && (count($_REQUEST['ingredients']) > 0)) { | ||
foreach ($_REQUEST['ingredients'] as $index => $ingredient) { | ||
?> | ||
<div class="form-group"> | ||
<div class="row"> | ||
<div class="col-xs-6"> | ||
<input name="ingredients[<?php echo $index; ?>]" value="<?php echo $ingredient; ?>" required="true" class="form-control"/> | ||
</div> | ||
</div> | ||
</div> | ||
<?php | ||
} // END foreach ingredients | ||
} else { | ||
?> | ||
<div class="form-group"> | ||
<div class="row"> | ||
<div class="col-xs-6"> | ||
<input name="ingredients[]" required="true" class="form-control"/> | ||
</div> | ||
</div> | ||
</div> | ||
<?php | ||
} | ||
?> | ||
<a id="add-ingredient" name="add-ingredient" href="#add-ingredient">Add another ingredient</a> | ||
</div> | ||
|
||
<!-- Directions --> | ||
<div class="container"> | ||
<h3>Directions</h3> | ||
<?php | ||
if (isset($_REQUEST['directions']) && (count($_REQUEST['directions']) > 0)) { | ||
foreach ($_REQUEST['directions'] as $index => $step) { | ||
?> | ||
<div class="form-group"> | ||
<div class="row"> | ||
<div class="col-xs-6"> | ||
<input name="directions[<?php echo $index; ?>]" value="<?php echo $step; ?>" required="true" class="form-control"/> | ||
</div> | ||
</div> | ||
</div> | ||
<?php | ||
} // END foreach directions | ||
} else { | ||
?> | ||
<div class="form-group"> | ||
<div class="row"> | ||
<div class="col-xs-6"> | ||
<input name="directions[]" required="true" class="form-control"/> | ||
</div> | ||
</div> | ||
</div> | ||
<?php | ||
} | ||
?> | ||
<a id="add-step" href="#add-step">Add another step</a> | ||
</div> | ||
|
||
<input type="submit" value="Save" class="btn btn-default" /> | ||
</form> | ||
</div> | ||
<script language="javascript" src="/js/jquery.min.js"></script> | ||
<script language="javascript" src="/js/script.js"></script> | ||
</body> | ||
</html> |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
<?php | ||
|
||
require __DIR__ . '/../vendor/autoload.php'; | ||
|
||
use RecipeSearchSimple\Constants; | ||
|
||
// Get search results from Elasticsearch if the user searched for something | ||
$results = []; | ||
if (!empty($_REQUEST['q'])) { | ||
|
||
// Connect to Elasticsearch (1-node cluster) | ||
$esPort = getenv('APP_ES_PORT') ?: 9200; | ||
$client = new Elasticsearch\Client([ | ||
'hosts' => [ 'localhost:' . $esPort ] | ||
]); | ||
|
||
// Setup search query | ||
$searchParams['index'] = Constants::ES_INDEX; // which index to search | ||
$searchParams['type'] = Constants::ES_TYPE; // which type within the index to search | ||
$searchParams['body']['query']['multi_match']['fields'] = [ 'name', 'description', 'tags', 'ingredients', 'directions' ]; // which fields within the type to search | ||
$searchParams['body']['query']['multi_match']['query'] = $_REQUEST['q']; // what to search for | ||
|
||
// Send search query to Elasticsearch and get results | ||
$queryResponse = $client->search($searchParams); | ||
$results = $queryResponse['hits']['hits']; | ||
} | ||
?> | ||
<html> | ||
<head> | ||
<title>Recipe Search</title> | ||
<link rel="stylesheet" href="/css/bootstrap.min.css" /> | ||
</head> | ||
<body> | ||
<div class="container"> | ||
<h1>Recipe Search</h1> | ||
<form method="get" action="<?php echo $_SERVER['PHP_SELF']; ?>" class="form-inline"> | ||
<input name="q" value="<?php echo $_REQUEST['q']; ?>" type="text" placeholder="What are you hungry for?" class="form-control input-lg" size="40" /> | ||
<input type="submit" value="Search" class="btn btn-lg" /> | ||
</form> | ||
<?php | ||
if (count($results) > 0) { | ||
?> | ||
<table class="table table-striped"> | ||
<thead> | ||
<th>Name</th> | ||
<th>Description</th> | ||
<th>Cooking time (minutes)</th> | ||
</thead> | ||
<?php | ||
foreach ($results as $result) { | ||
$recipe = $result['_source']; | ||
?> | ||
<tr> | ||
<td><a href="/view.php?id=<?php echo $result['_id']; ?>"><?php echo $recipe['name']; ?></a></td> | ||
<td><?php echo $recipe['description']; ?></td> | ||
<td><?php echo $recipe['cooking_time_min']; ?></td> | ||
</tr> | ||
<?php | ||
} // END foreach loop over results | ||
?> | ||
</table> | ||
<?php | ||
} // END if there are search results | ||
|
||
elseif (!empty($_REQUEST['q'])) { | ||
?> | ||
<p>Sorry, no recipes with <em><?php echo $_REQUEST['q']; ?></em> found :( Would you like to <a href="/add.php">add</a> one?</p> | ||
<?php | ||
|
||
} // END elsif there are no search results | ||
|
||
?> | ||
</div> | ||
</body> | ||
</html> |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
$( "#add-ingredient" ).on("click", function(e) { | ||
var linkEl = e.target; | ||
var newEl = $(linkEl.previousElementSibling).clone(); | ||
newEl.insertBefore(linkEl); | ||
}); | ||
|
||
$( "#add-step" ).on("click", function(e) { | ||
var linkEl = e.target; | ||
var newEl = $(linkEl.previousElementSibling).clone(); | ||
newEl.insertBefore(linkEl); | ||
}); |
Oops, something went wrong.