当前位置:   article > 正文

node vue 实时推送_使用Node,Vue和ElasticSearch构建实时搜索引擎

elasticsearch和vue

node vue 实时推送

介绍 ( Introduction )

Have you ever tried to search a site and got disappointed at the page having to reload? Or better still, you have to wait for an awfully long time while looking at a preloading spinning? I can bet that sucks.

您是否曾经尝试过搜索站点,并对必须重新加载的页面感到失望? 还是更好的是,您必须等待很长一段时间才能看到预紧纺纱? 我敢打赌,这很糟糕。

Do you know you as a developer can make near real-time search engines on your sites?

您是否知道您作为开发人员可以在您的网站上制作近乎实时的搜索引擎?

Elasticsearch is a distributed, RESTful search and analytics engine capable of solving a growing number of use cases. Elasticsearch is built on top of Apache Lucene, which is a high-performance text search engine library.

Elasticsearch是一个分布式的RESTful搜索和分析引擎,能够解决越来越多的用例。 Elasticsearch是基于Apache Lucene构建的,Apache Lucene是一个高性能的文本搜索引擎库。

In today's lesson, you will learn how to build a real-time search engine using Node.js, Elasticsearch, and Vue.js. As a result, a basic comprehension of Vue.js and Node.js (Express) is needed to follow this tutorial.

在今天的课程中,您将学习如何使用Node.js,Elasticsearch和Vue.js构建实时搜索引擎。 因此,需要基本的Vue.js和Node.js(Express)理解才能遵循本教程。

入门 ( Getting Started )

Let's get started with setting up the environment for this lesson. Since you will use Node.js, the easiest way to get started is to create a new folder and run npm init. Create a new folder called elastic-node, change directory into the new folder and then run npm init:

让我们开始设置本课的环境。 由于将使用Node.js,因此最简单的入门方法是创建一个新文件夹并运行npm init 。 创建一个名为elastic-node的新文件夹,将目录更改为新文件夹,然后运行npm init

  1. //create a new directory called elastic-nodemkdir elastic-node
  2. //change directory to the new folder created
  3. cd elastic-node
  4. //run npm init to create a package.json file
  5. npm init

The above commands take you through the process of creating a package.json file, which is required to run any Node.js library. Next, you need to install libraries which will be needed for the real-time search engine. The libraries needed are:

上面的命令将带您完成创建package.json文件的过程,这是运行任何Node.js库所必需的。 接下来,您需要安装实时搜索引擎所需的库。 所需的库是:

  • Express: This library will run our server.

    Express:此库将运行我们的服务器。
  • Body-parser: This library works with Express to parse body requests.

    正文解析器:此库与Express一起解析正文请求。
  • Elasticsearch: This is the official Node.js library for Elasticsearch, which is the engine on which the real-time search will be built.

    Elasticsearch:这是Elasticsearch的官方Node.js库,该库是构建实时搜索的引擎。

To install these libraries, run:

要安装这些库,请运行:

npm install express body-parser elasticsearch

Now the first part of your environment is set up. However, Elasticsearch itself is missing from your setup. You will need to install Elasticsearch itself. There are different ways to install Elasticsearch. If you are using a Debian Linux operating system, you could just download the .deb file and install using dpkg.

现在,您的环境的第一部分已设置完毕。 但是,您的设置中缺少Elasticsearch本身。 您将需要安装Elasticsearch本身。 有多种安装Elasticsearch的方法。 如果您使用的是Debian Linux操作系统,则可以下载.deb文件并使用dpkg安装。

  1. //download the deb packagecurl -L -O https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-5.6.4.deb
  2. //install the deb package using dpkg
  3. sudo dpkg -i elasticsearch-5.6.4.deb

For other distributions/operating systems, you can find a guide on how to install Elasticsearch here.

对于其他发行版/操作系统,您可以在此处找到有关如何安装Elasticsearch的指南。

Elasticsearch is not started automatically after installation. Elasticsearch can be started and stopped using the service command:

安装后,Elasticsearch不会自动启动。 可以使用service命令启动和停止Elasticsearch:

  1. // start the Elasticsearchservice
  2. sudo -i service elasticsearch start
  3. // stop the Elasticsearch service
  4. sudo -i service elasticsearch stop

To configure Elasticsearch to start automatically when the system boots up, run:

要将Elasticsearch配置为在系统启动时自动启动,请运行:

  1. //reload the systemctl daemonsudo /bin/systemctl daemon-reload
  2. // enable elastic search so it can be called as a service
  3. sudo /bin/systemctl enable elasticsearch.service

After running the command above, you can start and stop Elasticsearch by running:

运行上述命令后,您可以运行以下命令来启动和停止Elasticsearch:

  1. // start the Elasticsearchservice
  2. sudo systemctl start elasticsearch.service
  3. // stop the Elasticsearch service
  4. sudo systemctl stop elasticsearch.service

To check the status of Elasticsearch:

要检查Elasticsearch的状态:

// check status of Elasticsearchsudo service elasticsearch status

Note: A great tool while working with Elasticsearch is the Google Chrome Elastic toolbox. It helps you to take a quick look at your indexes and documents.

注意:与Elasticsearch搭配使用时,很棒的工具是Google Chrome Elastic工具箱 它可以帮助您快速查看索引和文档。

在Elasticsearch中索引数据 ( Indexing Data In Elasticsearch )

Create a data.js file in your root folder and add:

在您的根文件夹中创建一个data.js文件,并添加:

  1. //data.js
  2. //require the Elasticsearch librray
  3. const elasticsearch = require('elasticsearch');
  4. // instantiate an Elasticsearch client
  5. const client = new elasticsearch.Client({
  6. hosts: [ 'http://localhost:9200']
  7. });
  8. // ping the client to be sure Elasticsearch is up
  9. client.ping({
  10. requestTimeout: 30000,
  11. }, function(error) {
  12. // at this point, eastic search is down, please check your Elasticsearch service
  13. if (error) {
  14. console.error('Elasticsearch cluster is down!');
  15. } else {
  16. console.log('Everything is ok');
  17. }
  18. });

Let me explain what you have done in the code-block above: first, you required the Elasticsearch library and set up a new Elasticsearch client passing in an array of one host. If you notice, the host is http://localhost:9200. This is because, by default, Elasticsearch listens on port 9200. Next, you ping the Elasticsearch client to be sure the server is up. If you run node data.js you should get a message that says Everything is ok.

让我解释一下您在上面的代码块中所做的事情:首先,您需要Elasticsearch库并设置了一个传入一个主机数组的新Elasticsearch客户端。 如果您注意到,则主机为http://localhost:9200 。 这是因为,默认情况下,Elasticsearch监听端口9200 。 接下来,您对Elasticsearch客户端执行ping操作,以确保服务器已启动。 如果运行node data.js ,则应收到一条消息,指出“ Everything is ok

了解索引 ( Understanding Indexes )

Unlike normal databases, an Elasticsearch index is a place to store related documents. For example, you will create an index called scotch.io-tutorial to store data of type cities_list. This is how it's done in Elasticsearch:

与普通数据库不同,Elasticsearch索引是存储相关文档的地方。 例如,您将创建一个名为scotch.io-tutorial的索引来存储“ cities_list ”类型的数据。 这是在Elasticsearch中完成的方式:

  1. //data.js
  2. // create a new index called scotch.io-tutorial. If the index has already been created, this function fails safely
  3. client.indices.create({
  4. index: 'scotch.io-tutorial'
  5. }, function(error, response, status) {
  6. if (error) {
  7. console.log(error);
  8. } else {
  9. console.log("created a new index", response);
  10. }
  11. });

Add this piece of code after the ping function you had written before. Now, run node data.js again, you should get two messages:

在您之前编写的ping函数之后添加这段代码。 现在,再次运行node data.js ,您将收到两条消息:

  • Everything is okay

    一切正常
  • Created a new index (with the response from Elasticsearch)

    创建一个新索引(来自Elasticsearch的响应)

将文档添加到索引 ( Adding Documents To Indexes )

The Elasticsearch API makes it easy for documents to be added to already created indexes. It is as simple as:

Elasticsearch API使您可以轻松地将文档添加到已创建的索引中。 它很简单:

  1. // add a data to the index that has already been created
  2. client.index({
  3. index: 'scotch.io-tutorial',
  4. id: '1',
  5. type: 'cities_list',
  6. body: {
  7. "Key1": "Content for key one",
  8. "Key2": "Content for key two",
  9. "key3": "Content for key three",
  10. }
  11. }, function(err, resp, status) {
  12. console.log(resp);
  13. });

The code block above is explanatory. The body refers to the document you want to add to the scotch.io-tutorial index, while the type is more of a category. However, note that if the id key is omitted, Elasticsearch will auto-generate one.

上面的代码块是说明性的。 body是指您要添加到scotch.io-tutorial索引中的文档,而类型更多是类别。 但是,请注意,如果省略id密钥,Elasticsearch将自动生成一个。

However, in this lesson, your document will be a list of all the cities in the world. If you are to add each city one by one, It will take days, if not weeks to completely index all. Luckily, Elasticsearch has a bulk function used to process bulk data.

但是,在本课程中,您的文档将是世界上所有城市的列表。 如果要逐个添加每个城市,则要花费数天甚至数周的时间才能完全索引所有城市。 幸运的是,Elasticsearch具有用于处理批量数据的bulk功能。

First, grab the JSON file containing all cities in the world here and save into your root folder as cities.json

首先,在此处获取包含世界上所有城市的JSON文件,并将其另存为城市cities.json到根文件夹中

It's time to use the bulk API to import the large chunk of data we have:

现在是时候使用bulk API导入我们拥有的大量数据了:

  1. //data.js
  2. // require the array of cities that was downloaded
  3. const cities = require('./cities.json');
  4. // declare an empty array called bulk
  5. var bulk = [];
  6. //loop through each city and create and push two objects into the array in each loop
  7. //first object sends the index and type you will be saving the data as
  8. //second object is the data you want to index
  9. cities.forEach(city =>{
  10. bulk.push({index:{
  11. _index:"scotch.io-tutorial",
  12. _type:"cities_list",
  13. }
  14. })
  15. bulk.push(city)
  16. })
  17. //perform bulk indexing of the data passed
  18. client.bulk({body:bulk}, function( err, response ){
  19. if( err ){
  20. console.log("Failed Bulk operation".red, err)
  21. } else {
  22. console.log("Successfully imported %s".green, cities.length);
  23. }
  24. });

Here, you have looped through all the cities in your JSON file, and at each loop, you append an object with the index and type of the document you will be indexing. Notice that there are two pushes to the array during the loop? This is because the bulk API expects an object containing the index definition first, then the document you want to index. For more information on that, you can check here

在这里,您已经遍历了JSON文件中的所有城市,并且在每个循环中,都为对象附加了将要建立索引的文档的indextype 。 请注意,在循环过程中有两次对数组的推送吗? 这是因为bulk API要求对象首先包含索引定义,然后才包含要索引的文档。 有关更多信息,您可以在此处查看

Next, you called the client.bulk function passing in the new bulk array as the body. This indexes all your data into Elasticsearch with the index of scotch.io-tutorial and type cities_list.

接下来,您调用了client.bulk函数,并将新的批量数组作为主体传递。 这会使用scotch.io-tutorial的索引scotch.io-tutorial您的所有数据索引到Elasticsearch中,并键入cities_list

表达混合 ( Express To The Mix )

Your Elasticsearch instance is up and running, and you can connect with it using Node.js. It's time to use Express to serve a landing page and use the setup you have running so far.

您的Elasticsearch实例已启动并正在运行,您可以使用Node.js与之连接。 现在是时候使用Express服务着陆页并使用您到目前为止运行的设置了。

Create a file called index.js and add:

创建一个名为index.js的文件并添加:

  1. //index.js
  2. //require the Elasticsearch librray
  3. const elasticsearch = require('elasticsearch');
  4. // instantiate an elasticsearch client
  5. const client = new elasticsearch.Client({
  6. hosts: [ 'http://localhost:9200']
  7. });
  8. //require Express
  9. const express = require( 'express' );
  10. // instanciate an instance of express and hold the value in a constant called app
  11. const app = express();
  12. //require the body-parser library. will be used for parsing body requests
  13. const bodyParser = require('body-parser')
  14. //require the path library
  15. const path = require( 'path' );
  16. // ping the client to be sure Elasticsearch is up
  17. client.ping({
  18. requestTimeout: 30000,
  19. }, function(error) {
  20. // at this point, eastic search is down, please check your Elasticsearch service
  21. if (error) {
  22. console.error('elasticsearch cluster is down!');
  23. } else {
  24. console.log('Everything is ok');
  25. }
  26. });
  27. // use the bodyparser as a middleware
  28. app.use(bodyParser.json())
  29. // set port for the app to listen on
  30. app.set( 'port', process.env.PORT || 3001 );
  31. // set path to serve static files
  32. app.use( express.static( path.join( __dirname, 'public' )));
  33. // enable CORS
  34. app.use(function(req, res, next) {
  35. res.header("Access-Control-Allow-Origin", "*");
  36. res.header('Access-Control-Allow-Methods', 'PUT, GET, POST, DELETE, OPTIONS');
  37. res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
  38. next();
  39. });
  40. // defined the base route and return with an HTML file called tempate.html
  41. app.get('/', function(req, res){
  42. res.sendFile('template.html', {
  43. root: path.join( __dirname, 'views' )
  44. });
  45. })
  46. // define the /search route that should return elastic search results
  47. app.get('/search', function (req, res){
  48. // declare the query object to search elastic search and return only 200 results from the first result found.
  49. // also match any data where the name is like the query string sent in
  50. let body = {
  51. size: 200,
  52. from: 0,
  53. query: {
  54. match: {
  55. name: req.query['q']
  56. }
  57. }
  58. }
  59. // perform the actual search passing in the index, the search query and the type
  60. client.search({index:'scotch.io-tutorial', body:body, type:'cities_list'})
  61. .then(results => {
  62. res.send(results.hits.hits);
  63. })
  64. .catch(err=>{
  65. console.log(err)
  66. res.send([]);
  67. });
  68. })
  69. // listen on the specified port
  70. app .listen( app.get( 'port' ), function(){
  71. console.log( 'Express server listening on port ' + app.get( 'port' ));
  72. } );

Looking at the code above, notice you have:

查看上面的代码,请注意您具有:

  • Required the Express, body-parser and path libraries.

    需要Express,body解析器和路径库。

  • Set a new instance of Express to the constant called app.

    将Express的新实例设置为名为app的常量。

  • Set the app to use the bodyParser middleware.

    将应用程序设置为使用bodyParser中间件。

  • Set the static part of the app to a folder called public (I'm yet to create this folder).

    将应用程序的静态部分设置为名为public的文件夹(我尚未创建此文件夹)。

  • Defined a middleware which adds CORS header to the app.

    定义了将CORS标头添加到应用程序的中间件。

  • Defined a GET route for the root URL of the app represented by / and in this route, I returned a file called template.html which is in the views folder (I'm also yet to create this folder and the file template.html)

    /表示的应用程序的root URL定义了GET路由,在此路由中,我返回了一个名为template.html的文件,该文件位于views文件夹中(我也将创建此文件夹和template.html文件)

  • Defined a GET route for the /search URL of the app which uses a query object to search for the match of the data passed to it via the query string. The main search query is included within the query object. You can add different search queries to this object. For this query, you add a key with the query and return an object telling it that the name of the document you are looking for should match req.query['q'].

    Besides the query object, the search body can contain other optional properties, including size and from. The size property determines the number of documents to be included in the response. If this value is not present, by default ten documents are returned. The from property determines the starting index of the returned documents. This is useful for pagination.

    为应用程序的/search URL定义了GET路由,该路由使用查询对象来搜索通过查询字符串传递给它的数据的匹配项。 主搜索查询包含在查询对象内。 您可以向该对象添加不同的搜索查询。 对于此查询,您可以在查询中添加一个键,然后返回一个对象,告诉该对象您要查找的文档名称应与req.query['q']匹配。

    除了查询对象之外,搜索主体还可以包含其他可选属性,包括size和from。 size属性确定响应中要包含的文档数。 如果不存在此值,默认情况下将返回十个文档。 from属性确定返回文档的起始索引。 这对于分页很有用。

了解Search API响应 ( Understanding The Search API Response )

If you were to log out the response from the search API, it includes a lot of information.

如果您要注销来自搜索API的响应,它将包含很多信息。

  1. { took: 88,
  2. timed_out: false,
  3. _shards: { total: 5, successful: 5, failed: 0 },
  4. hits:
  5. { total: 59,
  6. max_score: 5.9437823,
  7. hits:
  8. [ {"_index":"scotch.io-tutorial",
  9. "_type":"cities_list",
  10. "_id":"AV-xjywQx9urn0C4pSPv",
  11. "_score":5.9437823,"
  12. _source":{"country":"ES","name":"A Coruña","lat":"43.37135","lng":"-8.396"}},
  13. [Object],
  14. ...
  15. [Object] ] } }

The response includes a took property for the number of milliseconds it took to find the results, timed_out, which is only true if no results were found in the maximum allowed time, _shards for information about the status of the different nodes (if deployed as a cluster of nodes), and hits, which includes the search results.

响应包括一个took属性的毫秒数花找到的结果, timed_out ,如果没有结果的最大允许时间发现,这是唯一真正的, _shards有关不同节点(的状态信息,如果部署为节点簇)和hits ,其中包括搜索结果。

Within the hits property, we have an object the following properties:

hits属性中,我们有一个对象,具有以下属性:

total shows the total number of matched items.

total显示匹配项的总数。

max_score is the maximum score of the found items.

max_score是找到的项目的最高分。

hits is an array that includes the found items.

hits是一个包含找到的项目的数组。

The explanation above is the reason in the search route, you returned response.hits.hits, which houses the documents found.

上面的解释是搜索路线中的原因,您返回了response.hits.hits ,其中包含找到的文档。

创建HTML模板 ( Creating The HTML Template )

First, create two new folders in your root folder named views and public which you referenced in the section above. Next, create a file called template.html in the views folder and paste:

首先,在上一节中引用的根文件夹中创建两个新文件夹,命名为viewspublic 。 接下来,在views文件夹中创建一个名为template.html的文件并粘贴:

  1. <!-- template.html -->
  2. <link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
  3. <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
  4. <script src="https://cdn.jsdelivr.net/npm/vue"></script>
  5. <div class="container" id="app">
  6. <div class="row">
  7. <div class="col-md-6 col-md-offset-3">
  8. <h1>Search Cities around the world</h1>
  9. </div>
  10. </div>
  11. <div class="row">
  12. <div class="col-md-4 col-md-offset-3">
  13. <form action="" class="search-form">
  14. <div class="form-group has-feedback">
  15. <label for="search" class="sr-only">Search</label>
  16. <input type="text" class="form-control" name="search" id="search" placeholder="search" v-model="query" >
  17. <span class="glyphicon glyphicon-search form-control-feedback"></span>
  18. </div>
  19. </form>
  20. </div>
  21. </div>
  22. <div class="row">
  23. <div class="col-md-3" v-for="result in results">
  24. <div class="panel panel-default">
  25. <div class="panel-heading">
  26. <!-- display the city name and country -->
  27. {{ result._source.name }}, {{ result._source.country }}
  28. </div>
  29. <div class="panel-body">
  30. <!-- display the latitude and longitude of the city -->
  31. <p>lat:{{ result._source.lat }}, long: {{ result._source.lng }}.</p>
  32. </div>
  33. </div>
  34. </div>
  35. </div>
  36. </div>
  37. <!--- some styling for the page -->
  38. <style>
  39. .search-form .form-group {
  40. float: right !important;
  41. transition: all 0.35s, border-radius 0s;
  42. width: 32px;
  43. height: 32px;
  44. background-color: #fff;
  45. box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075) inset;
  46. border-radius: 25px;
  47. border: 1px solid #ccc;
  48. }
  49. .search-form .form-group input.form-control {
  50. padding-right: 20px;
  51. border: 0 none;
  52. background: transparent;
  53. box-shadow: none;
  54. display: block;
  55. }
  56. .search-form .form-group input.form-control::-webkit-input-placeholder {
  57. display: none;
  58. }
  59. .search-form .form-group input.form-control:-moz-placeholder {
  60. /* Firefox 18- */
  61. display: none;
  62. }
  63. .search-form .form-group input.form-control::-moz-placeholder {
  64. /* Firefox 19+ */
  65. display: none;
  66. }
  67. .search-form .form-group input.form-control:-ms-input-placeholder {
  68. display: none;
  69. }
  70. .search-form .form-group:hover,
  71. .search-form .form-group.hover {
  72. width: 100%;
  73. border-radius: 4px 25px 25px 4px;
  74. }
  75. .search-form .form-group span.form-control-feedback {
  76. position: absolute;
  77. top: -1px;
  78. right: -2px;
  79. z-index: 2;
  80. display: block;
  81. width: 34px;
  82. height: 34px;
  83. line-height: 34px;
  84. text-align: center;
  85. color: #3596e0;
  86. left: initial;
  87. font-size: 14px;
  88. }
  89. </style>

In the code snippet above, there are two main sections which are:

在上面的代码段中,有两个主要部分:

  • HTML code: In this section, you started by requiring three different libraries which are 1.) Bootstrap CSS, for styling the page. 2.) Axios js, for making HTTP requests to our server and 3.) Vue.js, a minimalistic framework which you will use for our view.

    HTML代码:在本节中,您首先需要三个不同的库,它们是1.)Bootstrap CSS,用于设置页面样式。 2.)Axios js,用于向我们的服务器发出HTTP请求; 3.)Vue.js,这是一个简约的框架,将用于我们的视图。

  • CSS code: Here, you have applied styling to make the search input hide and reveal itself once you hover over the search icon.

    Next, there is an input for the search box which you assigned its v-model to query (this will be used by Vue.js). After this, you looped through all our results (this loop and the result variable will be made available by Vue.js). Note that while looping here, you had to access the_source property of your data. This should look familiar based on the response that elastic search returns.

    CSS代码:在这里,您已应用样式使鼠标悬停在搜索图标上时隐藏并显示搜索输入。

    接下来,为搜索框提供一个输入,您为其分配了其v-model以进行query (Vue.js将使用此输入)。 之后,您遍历了我们所有的结果(该循环和result变量将由Vue.js提供)。 请注意,在此处循环时,必须访问数据的_source属性。 根据弹性搜索返回的响应,这应该看起来很熟悉。

Run node index.js command, browse to http://localhost:3001/, you will see:

运行node index.js命令,浏览至http://localhost:3001/ ,您将看到:

Next, add a script tag in your template.html file, add:

接下来,在您的template.html文件中添加一个脚本标记,添加:

  1. //template.html
  2. // create a new Vue instance
  3. var app = new Vue({
  4. el: '#app',
  5. // declare the data for the component (An array that houses the results and a query that holds the current search string)
  6. data: {
  7. results: [],
  8. query: ''
  9. },
  10. // declare methods in this Vue component. here only one method which performs the search is defined
  11. methods: {
  12. // make an axios request to the server with the current search query
  13. search: function() {
  14. axios.get("http://127.0.0.1:3001/search?q=" + this.query)
  15. .then(response => {
  16. this.results = response.data;
  17. })
  18. }
  19. },
  20. // declare Vue watchers
  21. watch: {
  22. // watch for change in the query string and recall the search method
  23. query: function() {
  24. this.search();
  25. }
  26. }
  27. })

Vue.js code: In this section, you declared a new instance of Vue, mounting it on the element with the id of app. You declared data properties which include 1.) query which you had attached to the search input, and 2.) results which is an array of all results found.

Vue.js代码:在本节中,您声明了Vue的新实例,并将其安装在idapp的元素上。 你声明的数据性质,包括1) query您已连接到搜索输入,和2), results是所有结果的阵列中。

In the methods quota, you have just one function called search, which triggers a GET request to the search route passing along the current input in the search box. This in turns returns a response that is then looped in the HTML code block.

在方法配额中,只有一个名为搜索的函数,该函数会沿搜索框中的当前输入传递对search路径的GET请求。 依次返回一个响应,然后在HTML代码块中循环该响应。

Finally, you use what is called watchers in Vue.js, which performs an action anytime data being watched for changes. Here, you are watching for a change in the query data, and once it changes, the search method is fired.

最后,在Vue.js中使用所谓的watchers程序,该watchers在监视数据更改时随时执行操作。 在这里,您正在观察query数据中的更改,并且一旦更改,就会触发search方法。

If you re-run the node index.js command now and browse to http://localhost:3001/, it should work as seen:

如果现在重新运行node index.js命令并浏览到http://localhost:3001/ ,它应该可以正常运行:

从客户端搜索 ( Searching From The Client Side )

What if I do not want to send requests to my server every time a search occurs? Can I search the Elasticsearch engine directly from the client side? YES.

如果我不想每次搜索都向我的服务器发送请求怎么办? 我可以直接从客户端搜索Elasticsearch引擎吗? 是。

While the above approach works, some developers might not be comfortable with always hitting their servers for every search term, while some feel it's more secure to search from the server side.

尽管上述方法行得通,但有些开发人员可能并不总是为每个搜索词都命中服务器,而有些人则认为从服务器端进行搜索更安全。

However, it is possible to search from the client side. Elasticsearch offers a browser build which can make searches. Let me take you through a quick sample.

但是,可以从客户端进行搜索。 Elasticsearch提供了可以进行搜索的浏览器版本。 让我为您简要介绍一下。

First, add a new route to your Express file and restart your server:

首先,将新路径添加到Express文件并重新启动服务器:

  1. //index.js
  2. // decare a new route. This route serves a static HTML template called template2.html
  3. app.get('/v2', function(req, res){
  4. res.sendFile('template2.html', {
  5. root: path.join( __dirname, 'views' )
  6. });
  7. })

In this code block above, you have created a new route for the URL at /v2 and all you did in this route is to return a static HTML file called template2.html which will be created soon.

在上面的代码块中,您为/v2处的URL创建了一个新路由,并且您在此路由中所做的全部工作是返回一个名为template2.html的静态HTML文件,该文件将很快创建。

Next, you need to download the client library for Elasticsearch here. After downloading, extract and copy elasticsearch.min.js to the public folder in your application root.

接下来,您需要在此处下载Elasticsearch的客户端库。 下载后,解压缩elasticsearch.min.js并将其复制到应用程序根目录下的公共文件夹中。

Note: It is important to know if you try to connect with the Elasticsearch engine from the client side, you might experience CORS issue. To solve this issue, locate your Elasticsearch config file (For Debian/Ubuntu, it can be found at /etc/elasticsearch/elasticsearch.yml. For other operating systems, find out where it is located here and add the following to the bottom of the file:

注意:重要的是要知道是否尝试从客户端与Elasticsearch引擎连接,否则可能会遇到CORS问题。 要解决此问题,请找到您的Elasticsearch配置文件(对于Debian / Ubuntu,可以在/etc/elasticsearch/elasticsearch.yml找到。对于其他操作系统,请在此处找到它的位置,并将以下内容添加到文件:

  1. #/etc/elasticsearch/elasticsearch.yml
  2. http.cors.enabled : true
  3. http.cors.allow-origin : "*"

After that is done, restart your Elasticsearch instance

完成之后,重新启动您的Elasticsearch实例

  1. // restart the Elasticsearchservice
  2. sudo service elasticsearch restart

Next, create a file called template2.html in your views folder and add:

接下来,在您的views文件夹中创建一个名为template2.html的文件,并添加:

  1. <!-- template2.html -->
  2. <link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
  3. <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
  4. <script src="https://cdn.jsdelivr.net/npm/vue"></script>
  5. <div class="container" id="app">
  6. <div class="row">
  7. <div class="col-md-6 col-md-offset-3">
  8. <h1>Search Cities around the world</h1>
  9. </div>
  10. </div>
  11. <div class="row">
  12. <div class="col-md-4 col-md-offset-3">
  13. <form action="" class="search-form">
  14. <div class="form-group has-feedback">
  15. <label for="search" class="sr-only">Search</label>
  16. <input type="text" class="form-control" name="search" id="search" placeholder="search" v-model="query" >
  17. <span class="glyphicon glyphicon-search form-control-feedback"></span>
  18. </div>
  19. </form>
  20. </div>
  21. </div>
  22. <div class="row">
  23. <div class="col-md-3" v-for="result in results">
  24. <div class="panel panel-default">
  25. <div class="panel-heading">
  26. <!-- display the city name and country -->
  27. {{ result._source.name }}, {{ result._source.country }}
  28. </div>
  29. <div class="panel-body">
  30. <!-- display the latitude and longitude of the city -->
  31. <p>lat:{{ result._source.lat }}, long: {{ result._source.lng }}.</p>
  32. </div>
  33. </div>
  34. </div>
  35. </div>
  36. </div>
  37. <script src="/elasticsearch.min.js"></script>
  38. <style>
  39. .search-form .form-group {
  40. float: right !important;
  41. transition: all 0.35s, border-radius 0s;
  42. width: 32px;
  43. height: 32px;
  44. background-color: #fff;
  45. box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075) inset;
  46. border-radius: 25px;
  47. border: 1px solid #ccc;
  48. }
  49. .search-form .form-group input.form-control {
  50. padding-right: 20px;
  51. border: 0 none;
  52. background: transparent;
  53. box-shadow: none;
  54. display: block;
  55. }
  56. .search-form .form-group input.form-control::-webkit-input-placeholder {
  57. display: none;
  58. }
  59. .search-form .form-group input.form-control:-moz-placeholder {
  60. /* Firefox 18- */
  61. display: none;
  62. }
  63. .search-form .form-group input.form-control::-moz-placeholder {
  64. /* Firefox 19+ */
  65. display: none;
  66. }
  67. .search-form .form-group input.form-control:-ms-input-placeholder {
  68. display: none;
  69. }
  70. .search-form .form-group:hover,
  71. .search-form .form-group.hover {
  72. width: 100%;
  73. border-radius: 4px 25px 25px 4px;
  74. }
  75. .search-form .form-group span.form-control-feedback {
  76. position: absolute;
  77. top: -1px;
  78. right: -2px;
  79. z-index: 2;
  80. display: block;
  81. width: 34px;
  82. height: 34px;
  83. line-height: 34px;
  84. text-align: center;
  85. color: #3596e0;
  86. left: initial;
  87. font-size: 14px;
  88. }
  89. </style>

Next, add a script tag in your template2.html file and add:

接下来,在您的template2.html文件中添加一个脚本标记,并添加:

  1. //template2.html
  2. // instantiate a new Elasticsearch client like you did on the client
  3. var client = new elasticsearch.Client({
  4. hosts: ['http://127.0.0.1:9200']
  5. });
  6. // create a new Vue instance
  7. var app = new Vue({
  8. el: '#app',
  9. // declare the data for the component (An array that houses the results and a query that holds the current search string)
  10. data: {
  11. results: [],
  12. query: ''
  13. },
  14. // declare methods in this Vue component. here only one method which performs the search is defined
  15. methods: {
  16. // function that calls the elastic search. here the query object is set just as that of the server.
  17. //Here the query string is passed directly from Vue
  18. search: function() {
  19. var body = {
  20. size: 200,
  21. from: 0,
  22. query: {
  23. match: {
  24. name: this.query
  25. }
  26. }
  27. }
  28. // search the Elasticsearch passing in the index, query object and type
  29. client.search({ index: 'scotch.io-tutorial', body: body, type: 'cities_list' })
  30. .then(results => {
  31. console.log(`found ${results.hits.total} items in ${results.took}ms`);
  32. // set the results to the result array we have
  33. this.results = results.hits.hits;
  34. })
  35. .catch(err => {
  36. console.log(err)
  37. });
  38. }
  39. },
  40. // declare Vue watchers
  41. watch: {
  42. // watch for change in the query string and recall the search method
  43. query: function() {
  44. this.search();
  45. }
  46. }
  47. })

The HTML and JavaScript snippet above is very identical to the one in the section above. The only differences are:

上面HTML和JavaScript代码段与以上部分非常相同。 唯一的区别是:

  • You did not require Axios, you required elasticsearch.js instead.

    您不需要Axios ,而是需要elasticsearch.js
  • At the top of the script tag, you initiated the Elasticsearch client as it was done on the server-side.

    在脚本标签的顶部,您像在服务器端一样启动了Elasticsearch客户端。
  • The search method does not perform an HTTP request, but rather searches the Elasticsearch engine as done in the search route on the server side.

    search方法不执行HTTP请求,而是按照服务器端搜索路线中的方式搜索Elasticsearch引擎。

If you browse to http://localhost:3001/v2, It should work as shown:

如果浏览到http://localhost:3001/v2 ,则它应如下所示工作:

结论 ( Conclusion )

In this lesson, you have gotten a grasp of how to index data in Elasticsearch and searching data in Elastic search. Also, you have learned how to implement a real-time search using the client library for Elasticsearch. What are your thoughts about Elasticsearch? Let's discuss them in the comment section.

在本课程中,您已掌握如何在Elasticsearch中为数据建立索引以及如何在Elastic search中搜索数据。 另外,您还学习了如何使用Elasticsearch客户端库实施实时搜索。 您对Elasticsearch有何看法? 让我们在评论部分中讨论它们。

翻译自: https://scotch.io/tutorials/build-a-real-time-search-engine-with-node-vue-and-elasticsearch

node vue 实时推送

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/543518
推荐阅读
相关标签
  

闽ICP备14008679号