使用Node.js和Elasticsearch构建搜索引擎
这篇文章是由同行审查马克·布朗 , Vildan Softic和莫里茨克罗格 。 感谢所有SitePoint的同行评审人员使SitePoint内容达到最佳状态!
Elasticsearch是一个开放源代码搜索引擎,由于其高性能和分布式体系结构而日益流行。 在本文中,我将讨论其主要功能,并引导您完成使用它创建Node.js搜索引擎的过程。
Elasticsearch简介
Elasticsearch建立在Apache Lucene之上, Apache Lucene是一个高性能的文本搜索引擎库。 尽管Elasticsearch可以执行数据的存储和检索,但其主要目的不是充当数据库,而是一个搜索引擎(服务器),其主要目标是对数据进行索引,搜索和提供实时统计信息。
Elasticsearch具有分布式架构,可通过添加更多节点并利用额外的硬件来进行水平扩展。 它支持数千个节点,用于处理PB的数据。 它的水平缩放还意味着,如果任何节点发生故障,则通过重新平衡数据即可实现高可用性。
导入数据后,即可立即进行搜索。 Elasticsearch是无架构的,将数据存储在JSON文档中,并且可以自动检测数据结构和类型。
Elasticsearch也是完全由API驱动的。 这意味着几乎所有操作都可以通过简单的RESTful API使用HTTP上的JSON数据来完成。 它具有适用于几乎所有编程语言(包括Node.js)的许多客户端库。 在本教程中,我们将使用官方客户端库 。
当涉及到硬件和软件需求时,Elasticsearch非常灵活。 尽管建议的生产设置是64GB内存和尽可能多的CPU内核,但是您仍然可以在资源受限的系统上运行它并获得不错的性能(假设您的数据集不大)。 为了遵循本文中的示例,具有2GB内存和单个CPU内核的系统就足够了。
您可以在所有主要操作系统(Linux,Mac OS和Windows)上运行Elasticsearch。 为此,您需要安装最新版本的Java Runtime Environment(请参阅“ 安装Elasticsearch”部分)。 要遵循本文中的示例,您还需要安装Node.js (v0.11.0之后的任何版本都可以)以及npm 。
Elasticsearch术语
Elasticsearch使用自己的术语,在某些情况下与典型的数据库系统不同。 以下是Elasticsearch中的常用术语及其含义的列表。
索引 :该术语在Elasticsearch上下文中有两个含义。 首先是添加数据的操作。 添加数据后,文本被分解为标记(例如单词),并且每个标记都被索引。 但是,索引还指的是所有索引数据存储在何处。 基本上,当您导入数据时,会将其索引到索引中。 每次您要对数据执行任何操作时,都需要指定其索引名称。
类型 :Elasticsearch在索引中提供了文档的更详细分类,这称为类型。 索引中的每个文档也应该有一个类型。 例如,我们可以定义一个library
索引,然后在其中索引多种数据类型,例如article
, book
, report
和presentation
。 由于索引的开销几乎是固定的,因此建议减少索引和类型,而不要增加索引和类型。
搜索 :该术语表示您可能会想的。 您可以搜索不同索引和类型的数据。 Elasticsearch提供了多种类型的搜索查询,例如术语,短语,范围,模糊甚至地理数据查询。
过滤器 :Elasticsearch允许您根据不同的条件过滤搜索结果,以进一步缩小搜索范围。 如果将新的搜索查询添加到一组文档中,则可能会根据相关性更改顺序,但是如果将同一查询添加为过滤器,则该顺序将保持不变。
聚合 :这些为您提供有关聚合数据的不同类型的统计信息,例如最小值,最大值,平均值,求和,直方图等。
建议 :Elasticsearch为输入文本提供不同类型的建议。 这些建议可以是基于术语或短语的,甚至可以是完成建议。
安装Elasticsearch
Elasticsearch在Apache 2许可下可用; 可以免费下载,使用和修改。 在安装它之前,您需要确保在计算机上安装了Java Runtime Environment(JRE)。 Elasticsearch是用Java编写的,并且依赖Java库来运行。 要检查系统上是否安装了Java,可以在命令行中键入以下内容。
java -version
建议使用最新的Java稳定版本(在撰写本文时为1.8)。 您可以在此处找到有关在系统上安装Java的指南。
接下来,要下载最新版本的Elasticsearch(在撰写本文时为2.4.0),请转到下载页面并下载ZIP文件。 Elasticsearch不需要安装,并且单个zip文件包含用于在所有支持的操作系统上运行程序的完整文件集。 解压下载的文件,就可以完成了! 还有其他几种方法可以使Elasticsearch运行,例如获取TAR文件或用于不同Linux发行版的软件包(请参见此处 )。
如果您正在运行Mac OS X并且安装了Homebrew ,则可以使用brew install elasticsearch
来安装Elasticsearch。 Homebrew自动将可执行文件添加到您的路径并安装所需的服务。 它还可以帮助您使用一个命令来更新应用程序: brew upgrade elasticsearch
。
要在Windows上运行Elasticsearch,请从解压缩的目录中,从命令行运行bin\elasticsearch.bat
。 对于其他所有操作系统, ./bin/elasticsearch
从终端运行./bin/elasticsearch
。 此时,它应该已在您的系统上运行。
正如我之前提到的,您几乎可以使用Elasticsearch进行的所有操作都可以通过RESTful API完成。 Elasticsearch默认使用端口9200。 为了确保它运行正确,请在浏览器中转到http://localhost:9200/
,它应显示有关正在运行的实例的一些基本信息。
有关安装和故障排除的更多信息,请访问文档 。
图形用户界面
Elasticsearch通过REST API提供几乎所有功能,并且不附带图形用户界面(GUI)。 在介绍如何通过API和Node.js执行所有必要的操作的同时,有几种GUI工具提供有关索引和数据的可视信息,甚至提供一些高级分析。
由同一家公司开发的Kibana提供了数据的实时摘要以及一些自定义的可视化和分析选项。 Kibana是免费的,并且具有详细的文档 。
社区还开发了其他工具,包括elasticsearch-head , Elasticsearch GUI甚至是一个名为ElasticSearch Toolbox的Chrome扩展。 这些工具可帮助您在浏览器中浏览索引和数据,甚至可以尝试其他搜索和聚合查询。 所有这些工具都提供了安装和使用的演练。
设置Node.js环境
Elasticsearch为Node.js提供了一个官方模块,称为elasticsearch
。 首先,您需要将模块添加到项目文件夹中,并保存依赖项以备将来使用。
npm install elasticsearch --save
然后,您可以按照以下步骤将模块导入脚本中:
const elasticsearch = require('elasticsearch');
最后,您需要设置处理与Elasticsearch的通信的客户端。 在这种情况下,我假设您正在IP地址为127.0.0.1
和端口9200
(默认设置)的本地计算机上运行Elasticsearch。
const esClient = new elasticsearch.Client({host: '127.0.0.1:9200',log: 'error'
});
log
选项可确保记录所有错误。 在本文的其余部分中,我将使用相同的esClient
对象与Elasticsearch进行通信。 此处提供了有关节点模块的完整文档。
注意 :本教程的所有源代码都在GitHub上提供 。 最简单的方法是将存储库克隆到您的PC并从那里运行示例:
git clone https://github.com:sitepoint-editors/node-elasticsearch-tutorial.git
cd node-elasticsearch-tutorial
npm install
导入数据
在整个教程中,我将使用具有随机生成内容的学术文章数据集。 数据以JSON格式提供,数据集中有1000篇文章。 为了显示数据的样子,下面显示了数据集中的一项。
{"_id": "57508457f482c3a68c0a8ab3","title": "Nostrud anim proident cillum non.","journal": "qui ea","volume": 54,"number": 11,"pages": "109-117","year": 2014,"authors": [{"firstname": "Allyson","lastname": "Ellison","institution": "Ronbert","email": "Allyson@Ronbert.tv"},...],"abstract": "Do occaecat reprehenderit dolore ...","link": "http://mollit.us/57508457f482c3a68c0a8ab3.pdf","keywords": ["sunt","fugiat",...],"body": "removed to save space"}
字段名称不言自明。 唯一需要注意的是,此处没有显示body
字段,因为它包含完整的随机生成的文章(100至200个段落)。 您可以在此处找到完整的数据集。
虽然Elasticsearch提供了索引 , 更新和删除单个数据点的方法,但是我们将使用Elasticserch的bulk方法导入数据,该方法用于以更有效的方式对大型数据集执行操作:
// index.jsconst bulkIndex = function bulkIndex(index, type, data) {let bulkBody = [];data.forEach(item => {bulkBody.push({index: {_index: index,_type: type,_id: item.id}});bulkBody.push(item);});esClient.bulk({body: bulkBody}).then(response => {console.log('here');let errorCount = 0;response.items.forEach(item => {if (item.index && item.index.error) {console.log(++errorCount, item.index.error);}});console.log(`Successfully indexed ${data.length - errorCount}out of ${data.length} items`);}).catch(console.err);
};const test = function test() {const articlesRaw = fs.readFileSync('data.json');bulkIndex('library', 'article', articles);
};
在这里,我们正在调用bulkIndex
函数,将其library
作为索引名称,将article
作为类型以及希望索引的JSON数据传递给它。 bulkIndex
函数依次调用esClient
对象上的bulk
方法。 此方法将具有body
属性的对象作为参数。 提供给body
属性的值是一个数组,其中每个操作都有两个条目。 在第一个条目中,操作的类型指定为JSON对象。 在此对象内, index
属性确定要执行的操作(在这种情况下为文档建立索引),以及索引名称,类型名称和文档ID。 下一个条目对应于文档本身。
请注意,将来您可能会以这种方式将其他类型的文档(例如书籍或报告)添加到同一索引中。 我们还可以为每个文档分配一个唯一的ID,但这是可选的-如果您不提供一个ID,Elasticsearch将为您为每个文档分配一个随机生成的唯一ID。
假设您已经克隆了存储库,现在可以通过从项目根目录执行以下命令将数据导入Elasticsearch:
$ node index.js
1000 items parsed from data file
Successfully indexed 1000 out of 1000 items
检查数据是否正确建立索引
Elasticsearch的一大特色是近实时搜索。 这意味着一旦对文档建立索引,它们将在一秒钟之内可供搜索(请参阅此处 )。 对数据建立索引后,您可以通过运行indices.js
( 链接到source )来检查索引信息:
// indices.jsconst indices = function indices() {return esClient.cat.indices({v: true}).then(console.log).catch(err => console.error(`Error connecting to the es client: ${err}`));
};
客户端的cat
对象中的方法提供有关当前正在运行的实例的不同信息。 indices
方法列出了所有索引,它们的健康状态,其文档数以及它们在磁盘上的大小。 v
选项将标题添加到cat
方法的响应中。
运行上面的代码片段时,您会注意到它会输出一个颜色代码来指示集群的运行状况。 红色表示群集出现问题,并且未运行。 黄色表示集群正在运行,但是有警告,绿色表示一切正常。 在本地计算机上运行时,最有可能(取决于您的设置)您将获得黄色状态。 这是因为默认设置包含该群集的五个节点,但是在本地计算机中,只有一个实例正在运行。 虽然您应该始终将生产环境中的绿色状态作为目标,但出于本教程的目的,您可以继续以黄色状态使用Elasticsearch。
$ node indices.js
elasticsearch indices information:
health status index pri rep docs.count docs.deleted store.size pri.store.size
yellow open library 5 1 1000 0 41.2mb 41.2mb
动态和自定义映射
如前所述,Elasticsearch是无架构的。 这意味着在导入数据之前,不必定义数据的结构(类似于在SQL数据库中定义表),而是Elasticsearch会自动为您检测数据。 但是尽管被称为无模式的,但数据结构还是有一些限制。
Elasticsearch将数据结构称为映射。 如果不存在映射,则在为数据建立索引时,Elasticsearch会查看JSON数据的每个字段,并根据其类型自动定义映射。 如果该字段已经存在映射条目,则确保要添加的新数据遵循相同的格式。 否则,将引发错误。
例如,如果已经为{"key1": 12}
编制了索引,Elasticsearch会自动将字段key1
映射为long
。 现在,如果您尝试为{"key1": "value1", "key2": "value2"}
编制索引,则会引发错误,并期望字段key1
类型为long
。 同时,对象{"key1": 13, "key2": "value2"}
将没有任何问题进行索引,以key2
类型的string
添加到映射。
映射超出了本文的范围,并且在大多数情况下,自动映射可以正常工作。 我建议您查看elasticsearch文档 ,该文档提供了有关映射的深入讨论。
构建搜索引擎
索引完数据后,我们准备实施搜索引擎。 Elasticsearch提供了一种称为Query DSL的直观完整搜索查询结构(基于JSON)来定义查询。 有很多类型的搜索查询,但是在本文中,我们将研究几种更常见的搜索查询。 可以在此处找到Query DSL的完整文档。
请记住,我在每个显示的示例后面都提供了指向代码的链接。 设置环境并为测试数据建立索引后,您可以克隆存储库并在计算机上运行任何示例。 为此,只需从命令行运行
node filename.js
。
返回一个或多个索引中的所有文档
为了执行搜索,我们将使用客户端提供的各种搜索方法。 最简单的查询是match_all
,它以一个或多个索引返回所有文档。 下面的示例说明了如何获取索引中的所有存储文档( 链接到source )。
//search_all.jsconst search = function search(index, body) {return esClient.search({index: index, body: body});
};const test = function test() {let body = {size: 20,from: 0,query: {match_all: {}}};search('library', body).then(results => {console.log(`found ${results.hits.total} items in ${results.took}ms`);console.log(`returned article titles:`);results.hits.hits.forEach((hit, index) => console.log(`\t${body.from + ++index} - ${hit._source.title}`))}).catch(console.error);
};
主搜索查询包含在query
对象内。 稍后我们将看到,我们可以向该对象添加不同类型的搜索查询。 对于每个查询,我们添加一个查询类型为key(在此示例中为match_all
)的键,该值是包含搜索选项的对象。 在此示例中没有选项,因为我们要返回索引中的所有文档。
除了query
对象之外,搜索主体还可以包含其他可选属性,包括size
和from
。 size
属性确定响应中要包含的文档数。 如果不存在此值,默认情况下将返回十个文档。 from
属性确定返回文档的起始索引。 这对于分页很有用。
了解搜索API响应
如果您要注销来自搜索API的响应(上例中的results
),则由于包含很多信息,它最初可能看起来不堪重负。
{ took: 6,timed_out: false,_shards: { total: 5, successful: 5, failed: 0 },hits:{ total: 1000,max_score: 1,hits:[ [Object],[Object],...[Object] ] } }
在最高级别,响应包括took
的毫秒数性质花找到的结果, timed_out
,这是唯一true
,如果没有结果的最大允许时间发现, _shards
有关不同节点的状态信息(如果部署为节点集群),则hits
,其中包括搜索结果。
在hits
属性中,我们有一个对象,具有以下属性:
total
—表示匹配项的总数max_score
—找到的项目的最高分hits
—包含找到的项目的数组。 在hits
数组中的每个文档中,我们都有索引,类型,文档ID,得分和文档本身(在_source
元素内)。
这非常复杂,但是好消息是,一旦实现了一种提取结果的方法,无论您使用何种搜索查询,都将始终以相同的格式获得结果。
还要注意,Elasticsearch的优点之一是它会自动为每个匹配的文档分配一个分数。 默认情况下,此分数用于量化文档的相关性,结果按递减的分数排序返回。 在我们使用match_all
检索所有文档的情况下,分数没有意义,所有分数均计算为1.0。
匹配包含字段中特定值的文档
现在,让我们看一些更有趣的例子。 要匹配包含字段中特定值的文档,我们可以使用match
查询。 下面显示了一个带有match
查询的简单搜索主体( 链接到source )。
// search_match.js{query: {match: {title: {query: 'search terms go here'}}}
}
正如我前面提到的,我们首先将一个条目添加到具有搜索类型的查询对象match
,在上面的示例中这是match
的。 在搜索类型对象内,我们标识要搜索的文档字段,此处为title
。 在其中,我们放入了与搜索相关的数据,包括query
属性。 我希望在测试完上面的示例后,您对搜索的速度感到惊讶。
上面的搜索查询返回其标题字段与query
属性中的任何单词匹配的文档。 我们可以按如下所示设置匹配词的最小数量。
// search_match.js...
match: {title: {query: 'search terms go here',minimum_should_match: 3}
}
...
此查询匹配标题中至少包含三个指定单词的文档。 如果查询中少于三个词,则要匹配的文档的标题中必须全部包含三个词。 添加到搜索查询中的另一个有用功能是模糊性。 如果用户在写查询时打错了输入,这将很有用,因为模糊匹配会找到拼写紧密的术语。 对于字符串,模糊度值基于每个术语的最大允许Levenshtein距离 。 下面是一个带有模糊性的示例。
match: {title: {query: 'search tems go here',minimum_should_match: 3,fuzziness: 2}
}
在多个字段中搜索
如果要在多个字段中搜索,则可以使用multi_match
搜索类型。 它与match
相似,不同之处在于,我们不是将字段作为搜索查询对象中的键,而是添加了一个fields
键,它是要搜索的字段数组。 在这里,我们在title
, authors.firstname
和authors.lastname
字段内搜索。 ( 链接到源 )
// search_multi_matchmulti_match: {query: 'search terms go here',fields: ['title', 'authors.firstname', 'authors.lastname']
}
multi_match
查询支持其他搜索属性,例如minimum_should_match
和fuzziness
。 Elasticsearch支持通配符(例如*
)来匹配多个字段,因此我们可以将上面的示例简化为['title', 'authors.*name']
。
匹配完整短语
Elasticsearch还可以完全匹配输入的短语,而无需在术语级别进行匹配。 此查询是常规match
查询的扩展,称为match_phrase
。 以下是match_phrase
的示例。 ( 链接到源 )
// match_phrase.jsmatch: {title: {query: 'search phrase goes here',type: 'phrase'}
}
合并多个查询
到目前为止,在示例中,我们仅对每个请求使用单个查询。 但是,Elasticsearch允许您组合多个查询。 最常见的复合查询是bool
。 bool
查询接受四种类型的键: must
, should
, must_not
和filter
。 正如其名称所暗示的,在结果的文件必须在匹配查询must
,内必须不匹配查询must_not
,并会得到更高的分数,如果他们内匹配查询should
。 提到的每个元素都可以以查询数组的形式接收多个搜索查询。
在下面,我们使用bool
查询以及名为query_string
的新查询类型。 这使您可以使用AND
和OR
关键字编写更高级的查询。 可在此处找到有关query_string
语法的完整文档。 另外,我们使用range
查询( 此处的文档),这允许我们将字段限制为给定范围。 (链接到源 )
// search_bool.js{bool: {must: [{query_string: {query: '(authors.firstname:term1 OR authors.lastname:term2) AND (title:term3)'}}],should: [{match: {body: {query: 'search phrase goes here',type: 'phrase'}}}],must_not: [{range: {year: {gte: 2011,lte: 2013}}}]}
}
在上面的例子中,查询返回的文件,其中作者的名字包含term1
或他们的姓氏包含term2
, 并且他们的头衔有term3
,他们没有公布在年2011年,2012年或2013年另外,已给定的文件在他们body
词组,会获得更高的分数,并显示在结果的顶部(因为match
查询位于should
子句中)。
过滤器,汇总和建议
除了其高级搜索功能外,Elasticsearch还提供其他功能。 在这里,我们看三个比较常见的功能。
筛选器
通常,您可能希望根据特定条件优化搜索结果。 Elasticsearch通过过滤器提供此功能。 在我们的文章数据中,假设您的搜索返回了几篇文章,而您只想选择在五年中发表的文章。 您可以简单地从搜索结果中筛选出不符合您的条件的所有内容,而无需更改搜索顺序。
过滤器与bool
查询的must
子句中的同一查询之间的区别在于,过滤器不会影响搜索得分,而must
查询会影响搜索得分。 当返回搜索结果并且用户根据某些特定条件进行过滤时,他们不希望更改原始结果顺序,而是只希望从结果中删除无关的文档。 过滤器遵循与搜索相同的格式,但是更常见的是,它们是在具有确定值的字段(而不是文本字符串)上定义的。 Elasticsearch建议通过bool
复合搜索查询的filter
子句添加过滤器。
继续上面的示例,假设我们希望将搜索结果限制为2011年至2015年之间发表的文章。为此,我们只需要向原始搜索查询的filter
部分添加一个range
查询即可。 这将从结果中删除所有不匹配的文档。 以下是过滤查询的示例。 (链接到源 )
// filter.js{bool: {must: [{match: {title: 'search terms go here'}}],filter: [{range: {year: {gte: 2011,lte: 2015}}}]}
}
集合体
聚合框架基于搜索查询提供各种聚合的数据和统计信息。 聚合的两种主要类型是度量和存储桶,其中度量聚合在一组文档上跟踪和计算度量,存储桶聚合构建存储桶,每个存储桶都与一个键和一个文档条件相关联。 度量标准聚合的示例是平均值,最小值,最大值,求和和值计数。 桶聚合的示例包括范围,日期范围,直方图和术语。 可以在这里找到有关聚合器的详细说明。
聚合放置在aggregations
对象中,该对象本身直接放置在search
对象主体中。 在aggregations
对象中,每个键都是用户分配给聚合器的名称。 聚合器类型和选项应作为该键的值放置。 下面,我们看两个不同的聚合器,一个度量标准和一个存储桶。 作为指标聚合器,我们尝试在数据集中找到最短的年份值(最旧的文章),对于存储桶聚合器,我们尝试查找每个关键字出现了多少次。 (链接到源 )
// aggregations.js{aggregations: {min_year: {min: {field: 'year'}},keywords: {terms: {field: 'keywords'}}}
}
在上面的示例中,我们将度量标准聚合器命名为min_year
(此名称可以是任何名称),在field year
上类型为min
。 铲斗聚合名为keywords
,这类型的terms
在外地keywords
。 聚合结果包含在响应中的aggregations
元素内,并且在更深的层次上,它们包含每个定义的聚合器(此处为min_year
和keywords
)及其结果。 以下是此示例的部分响应。
{
..."aggregations": {"keywords": {"doc_count_error_upper_bound": 0,"sum_other_doc_count": 2452,"buckets": [{"key": "pariatur","doc_count": 88},{"key": "adipisicing","doc_count": 75},...]},"min_year": {"value": 1970}}
}
默认情况下,响应中最多返回10个存储桶。 您可以在请求中的field
旁边添加一个size
键,以确定返回的最大存储桶数。 如果要接收所有存储桶,请将此值设置为0。
意见建议
Elasticsearch具有多种类型的建议程序,它们为输入的术语( 此处提供文档)提供替换或完成建议。 我们将在这里查看术语和短语建议者。 术语建议者为输入的文本中的每个术语提供建议(如果有的话),而短语建议者将输入的文本视为整个短语(而不是将其分解为术语),并提供其他短语建议(如果有的话)。 要使用建议API,我们需要在Node.js客户端上调用suggest
方法。 以下是术语建议器的示例。 (链接到源 )
// suggest_term.jsesClient.suggest({index: 'articles',body: {text: 'text goes here',titleSuggester: {term: {field: 'title',size: 5}}}
}).then(...)
在请求主体中,与所有其他客户端方法一致,我们具有一个index
字段,用于确定搜索的索引。 在body
属性中,我们添加要为其寻求建议的文本,并且(与聚合对象一样)为每个建议者命名(在这种情况下为titleSuggester
)。 它的值确定建议者的类型和选项。 在这种情况下,我们在title
字段中使用term
建议者,并将每个令牌的最大建议数目限制为五个( size: 5
)。
提示API的响应为每个请求的提示提供了一个键,该键是一个数组,其大小与text
字段中的术语数相同。 对于该数组内的每个对象,都有一个options
对象,该对象在其text
字段中包含建议。 以下是上述请求的部分响应。
...
"titleSuggester": [{"text": "term","offset": 0,"length": 4,"options": [{"text": "terms","score": 0.75,"freq": 120},{"text": "team","score": 0.5,"freq": 151}]},...
]
...
要获取词组建议,我们可以采用与上述相同的格式,只需将建议者类型替换为phrase
。 在以下示例中,响应遵循与上述相同的格式。 (链接到源 )
// suggest_phrase.jsesClient.suggest({index: 'articles',body: {text: 'phrase goes here',bodySuggester: {phrase: {field: 'body'}}}
}).then(...).catch(...);
进一步阅读
Elasticsearch提供了广泛的功能,这些功能远远超出了本文的范围。 在本文中,我试图从较高的角度解释其功能,并为您提供适当的参考资料以供进一步研究。 Elasticsearch非常可靠,并且具有出色的性能(希望您在运行示例时注意到这一点)。 再加上社区支持的增加,Elasticsearch在行业中的采用率有所提高,尤其是在处理实时或大数据的公司中。
看完这里提供的示例后,强烈建议您阅读文档。 它们提供了两个主要资源,一个是对Elasticsearch及其功能的参考 ,另一个是作为指南 ,其重点更多地放在实现,用例和最佳实践上。 您还可以在此处找到有关Node.js客户端的详细文档。
您已经在使用Elasticsearch吗? 你有什么经验? 或者,也许您在阅读本文后会尝试一下。 在下面的评论中让我知道。
From: https://www.sitepoint.com/search-engine-node-elasticsearch/
使用Node.js和Elasticsearch构建搜索引擎相关推荐
- slack 使用说明_如何使用Node.js为Slack构建Meetupbot
slack 使用说明 by premprakashsingh 通过premprakashsingh 如何使用Node.js为Slack构建Meetupbot (How to build a Meetu ...
- node.js 组件_使用Node.js和TransloadIt构建用户头像组件
node.js 组件 在本系列的第一部分中,我们介绍了TransloadIt -一种文件处理服务,专门处理图像,视频和音频. 如果您还没有阅读它,我建议您立即阅读,因为它涵盖了很多背景概念,您需要阅读 ...
- 使用Node.js和TransloadIt构建用户头像组件
在本系列的第一部分中,我们介绍了TransloadIt -一种文件处理服务,专门处理图像,视频和音频. 如果您还没有阅读它,我建议您立即阅读,因为它涵盖了很多背景概念,您需要阅读这些概念才能继续阅读本 ...
- Node.js 系列:构建原生 Node.js 应用
原生 Node.js 应用 Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境 Node.js 使用了一个事件驱动.非阻塞式 I/O 的模型,使其轻量又高效 Nod ...
- 有没有办法为Node.js项目自动构建package.json文件
本文翻译自:Is there a way to automatically build the package.json file for Node.js projects Is package.js ...
- bootstrap3 表单构建器_Knex - 灵活轻便的 Node.js SQL 查询构建器
不管你承认与否,Node.js 都是一个后端语言平台.那么,操作数据库,这个后端最为常用的代码逻辑之一,Node.js 自然也需要拥有.我们当然也可以使用数据库驱动直接执行 SQL 语句,但我们往往需 ...
- 如何在Ubuntu 18.04上使用Node.js和MongoDB构建和部署GraphQL服务器
The author selected the Wikimedia Foundation to receive a donation as part of the Write for DOnation ...
- 使用Keras,TensorFlow.js,Node.js和Firebase构建,训练和部署Book Recommender系统(第2部分)
Welcome back to the second part of our recommender engine tutorial series. In the first part, you le ...
- 如何使用 Javascript/node.js 在 WebRTC 中构建音视频通话APP?
语音和视频通信的嵌入对于现在的互联网产品发展的重要性已经毋庸置疑,WebRTC 事实上是一种通用的技术框架标准,它可以在浏览器之间不需要中介的情况下,实现任意数据流交换.这使得 web 应用程序和移动 ...
最新文章
- mysql 索引 二叉树_MySQL 的索引,为什么是 B+而不是平衡二叉树
- golang defer 关闭文件 报错file may have nil or other unexpected value as its corresponding error
- leetcode算法题--环绕字符串中唯一的子字符串★
- ORACLE ORA-02030: can only select from fixed tables/views
- rfcv函数实现_JAVA_用_JCO连接_SAP,实现调用SAP_的_RFC_函数(整理)(附一篇看起来比较全面的说明)(JCO报错信息)...
- lia人是什么意思_69年属鸡人终身灾难是什么意思
- 计算机专业个人能力评估,计算机应用专业毕业生个人自我评价
- python interactive slider_python3----练习题(过滑块验证)
- linux减小根目录空间_Linux目录结构及文件基本操作详解
- kubenetes 1.4安装kube-UI
- 一个3D引擎Demo 源码
- Redis 介绍-- Redis 3.0 官方文档的翻译版
- 来自资深程序员的 3 条锦囊:永远不要辞职,除非……
- 华为android是什么文件夹,华为手机里的文件夹代表什么?哪些可以清除?看完秒懂!...
- 完全平方数的几种判定方法与算法用时
- 解决 git reject
- LaTeX错误“Unable to read an entire line---bufsize=200000. Please increase buf_size in texmf.cnf.”
- Watching the English:英国社会阶层攀爬指南?
- c语言感叹号加一个括号,车上出现一个感叹号一个括号处理方法
- 微信之旅——微信公众号