In the previous posts, we had know how to get All Documents in Index and show them with pagination. This tutorial show you way to implement a simple Full Text Search in an Angular 4 Application.
Related Post:
– Angular 4 ElasticSearch – Quick Start – How to add Elasticsearch.js
– Angular 4 ElasticSearch example – How to create an Index
– Angular 4 ElasticSearch example – Add Document to Index
– Angular 4 ElasticSearch example – Get All Documents in Index
– Angular 4 ElasticSearch example – Documents Pagination with Scroll
Elasticsearch Tutorials:
– Elasticsearch Overview
– ElasticSearch Filter vs Query
– ElasticSearch Full Text Queries – Basic
Contents
I. How to
1. Add ElasticSearch to Angular 4 Project
Please visit Angular 4 ElasticSearch – Quick Start – How to add Elasticsearch.js for details.
With the post, you will know how to:
– Install ElasticSearch
– Add ElasticSearch to Angular 4 Project
– Use it in the project
2. Create Index & Check Connection
Please visit Angular 4 ElasticSearch example – How to create an Index for details.
3. Simple Full Text Search
Using Client.search()
function with match_phrase_prefix
, we create a simple full text search function:
fullTextSearch(_index, _type, _field, _queryText): any { return this.client.search({ index: _index, type: _type, filterPath: ['hits.hits._source', 'hits.total', '_scroll_id'], body: { 'query': { 'match_phrase_prefix': { [_field]: _queryText, } } }, // response for each document with only 'fullname' and 'address' fields '_source': ['fullname', 'address'] }); }
In the component to implement searching, we create html page that catch any key-up event in the text box:
Not found!
And search()
function:
search($event) { this.queryText = $event.target.value; this.es.fullTextSearch(INDEX,TYPE,'field', this.queryText).then( response => { this.customerSources = response.hits.hits; console.log(response); }, error => { console.error(error); }).then(() => { console.log('Search Completed!'); }); } }
To prevent hit the database after every keypress (it will make multiple queries to ElasticSearch), we implement a timeout by keeping track of the last keypress time, then update the subjects only if the last keypress was more than 100ms ago:
lastKeypress = 0; search($event) { if ($event.timeStamp - this.lastKeypress > 100) { this.queryText = $event.target.value; this.es.fullTextSearch(...); } this.lastKeypress = $event.timeStamp; }
So, with query:
-> POST http://localhost:9200/jsa_customer_idx/customer/_search?filter_path=hits.hits._source%2Chits.total%2C_scroll_id&_source=fullname%2Caddress { "query": { "match_phrase_prefix": { "address": "ull" } } }
The result will be like:
<- 200 { "hits": { "total": 2, "hits": [ { "_source": { "address": "Ap #443-336 Ullamcorper. Street\nVisalia VA 54886", "fullname": "Jamie Konan" } }, { "_source": { "address": "P.O. Box 902 3472 Ullamcorper Street\nLynchburg DC 29738", "fullname": "Jack Smith" } } ] } }
II. Practice
0. Overview
Goal:
Project Structure:
1. App Module
import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; import { ElasticsearchService } from './elasticsearch.service'; import { AddCustomerComponent } from './customer/add-customer/add-customer.component'; import { ShowCustomersComponent } from './customer/show-customers/show-customers.component'; import { CustomerDetailsComponent } from './customer/customer-details/customer-details.component'; import { SearchCustomersComponent } from './customer/search-customers/search-customers.component'; @NgModule({ declarations: [ AppComponent, AddCustomerComponent, ShowCustomersComponent, CustomerDetailsComponent, SearchCustomersComponent ], imports: [ BrowserModule, FormsModule, ReactiveFormsModule, AppRoutingModule ], providers: [ElasticsearchService], bootstrap: [AppComponent] }) export class AppModule { }
2. ElasticSearch Service
import { Injectable } from '@angular/core'; import { Client } from 'elasticsearch'; @Injectable() export class ElasticsearchService { private client: Client; constructor() { if (!this.client) { this.connect(); } } private connect() { this.client = new Client({ host: 'http://localhost:9200', log: 'trace' }); } createIndex(name): any { return this.client.indices.create(name); } isAvailable(): any { return this.client.ping({ requestTimeout: Infinity, body: 'hello JavaSampleApproach!' }); } addToIndex(value): any { return this.client.create(value); } getAllDocumentsWithScroll(_index, _type, _size): any { return this.client.search({ index: _index, type: _type, scroll: '1m', filterPath: ['hits.hits._source', 'hits.total', '_scroll_id'], body: { 'size': _size, 'query': { 'match_all': {} }, 'sort': [ { '_uid': { 'order': 'asc' } } ] } }); } getNextPage(scroll_id): any { return this.client.scroll({ scrollId: scroll_id, scroll: '1m', filterPath: ['hits.hits._source', 'hits.total', '_scroll_id'] }); } fullTextSearch(_index, _type, _field, _queryText): any { return this.client.search({ index: _index, type: _type, filterPath: ['hits.hits._source', 'hits.total', '_scroll_id'], body: { 'query': { 'match_phrase_prefix': { [_field]: _queryText, } } }, '_source': ['fullname', 'address'] }); } }
3. Components
3.1 Add Document Component
Please visit: 3_Add_Document_Component for details.
3.2 Details Component
You can find it at: 3.2_Details_Component (in the previous post).
In this tutorial, we just modify code to hide age
and published
:
{{customer.fullname}}0"> {{customer.age}}{{customer.address}}0"> {{customer.published}}
3.3 Show Documents Component
Please visit:
- Show_Documents_Component
- or Show_Documents_Component with Pagination
3.4 Search Documents Component
search-customers.component.ts
import { Component, OnInit } from '@angular/core'; import { CustomerSource } from '../customer.interface'; import { ElasticsearchService } from '../../elasticsearch.service'; @Component({ selector: 'search-customers', templateUrl: './search-customers.component.html', styleUrls: ['./search-customers.component.css'] }) export class SearchCustomersComponent implements OnInit { private static readonly INDEX = 'jsa_customer_idx'; private static readonly TYPE = 'customer'; customerSources: CustomerSource[]; private queryText = ''; private lastKeypress = 0; constructor(private es: ElasticsearchService) { this.queryText = ''; } ngOnInit() { } search($event) { if ($event.timeStamp - this.lastKeypress > 100) { this.queryText = $event.target.value; this.es.fullTextSearch( SearchCustomersComponent.INDEX, SearchCustomersComponent.TYPE, 'address', this.queryText).then( response => { this.customerSources = response.hits.hits; console.log(response); }, error => { console.error(error); }).then(() => { console.log('Search Completed!'); }); } this.lastKeypress = $event.timeStamp; } }
search-customers.component.html
Not found!
4. App Routing Module
import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { AddCustomerComponent } from './customer/add-customer/add-customer.component'; import { ShowCustomersComponent } from './customer/show-customers/show-customers.component'; import { SearchCustomersComponent } from './customer/search-customers/search-customers.component'; const routes: Routes = [ { path: '', redirectTo: 'add', pathMatch: 'full' }, { path: 'add', component: AddCustomerComponent }, { path: 'customers', component: ShowCustomersComponent }, { path: 'search', component: SearchCustomersComponent } ]; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule] }) export class AppRoutingModule { }
5. App Component
app.component.ts
import {Component} from '@angular/core'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { title = 'JavaSampleApproach'; description = 'Angular4-SpringBoot Demo'; }
app.component.html
{{title}}
{{description}}
6. Check Result
Run Angular 4 App, go to http://localhost:4200/
, add Customer Data, then choose Search by Address tab:
III. Sourcecode
Angular4ElasticSearch-fulltext-search
Last updated on August 17, 2018.