MDN 的 yari 使用了 Elasticsearch 和 Kibana 来实现搜索功能。
Elasticsearch 是一个开源的搜索引擎,它提供了分布式、多租户、全文搜索和分析等功能。在 MDN 的 yari 中,Elasticsearch 负责存储和搜索文档内容,并提供高效的搜索结果返回。
Kibana 是一个可视化的数据分析和展示工具,它可以与 Elasticsearch 配合使用,通过图表、表格等形式展示 Elasticsearch 中存储的数据。在 MDN 的 yari 中,Kibana 提供了搜索结果的可视化界面。
具体来说,yari 的搜索功能主要包含以下几个步骤:
-
收集数据:yari 会从 MDN 的数据库中获取文档内容、标签等信息,并利用 Elasticsearch API 将这些数据存储至 Elasticsearch 中。
-
索引文档:在存储数据时,yari 会将文档内容分析成词条,并根据一定的算法建立索引,以便后续搜索。例如,yari 会将 HTML 标签、JavaScript 函数等词条索引到不同的字段中,并设置不同的权重和搜索规则。
-
搜索查询:yari 会根据用户的查询请求,利用 Elasticsearch 提供的搜索 API 在索引中进行检索。搜索算法会根据查询语法、词条、权重等因素进行排名,以获得尽可能精确的搜索结果。当搜索结果超过某个阈值时,yari 会利用 Kibana 将结果可视化展示。
-
展示结果:yari 会将搜索结果展示在搜索页面中,并提供一些筛选和排序等功能以帮助用户更准确地找到所需信息。
总的来说,yari 的搜索功能借助了 Elasticsearch 和 Kibana 提供的高效、全面的搜索和分析能力,可以为用户提供快速、准确的搜索结果。
我参考的资料主要有以下几个来源:
-
官方文档:我阅读了 Elasticsearch 和 Kibana 的官方文档,了解了它们的基本概念、使用方法、API等内容。
-
MDN yari 的代码:我分析了 MDN yari 的源代码,特别是搜索模块的代码,了解了它们是如何使用 Elasticsearch 和 Kibana 实现搜索功能的。
-
技术文章:我阅读了一些关于 Elasticsearch 和 Kibana 的技术文章,例如《Elasticsearch 权威指南》、《Kibana 实战》等,了解了它们的一些高级用法和最佳实践。
-
互联网资料:我查找了一些互联网上的资料,例如博客文章、Stack Overflow 问答等,了解了 Elasticsearch 和 Kibana 在实际应用中的一些问题和解决方法。
MDN 的 yari 使用 ElasticSearch 实现搜索功能。具体实现如下:
-
应用中使用了 ElasticSearch 的 JavaScript API client,该客户端提供了操作 ElasticSearch 的方法。
-
在应用的服务端代码中,先定义了一个 ElasticSearch 的客户端实例,然后定义了一个搜索函数,在该函数中使用客户端的
search()
方法来实现搜索操作。search()
方法接受一个包含查询条件的 JavaScript 对象作为参数,返回一个 Promise,该 Promise 解析出来的结果是一个 JSON 对象,其中包含搜索到的文档信息。
以下是服务端代码的示例:
js
const { Client } = require('@elastic/elasticsearch');const client = new Client({ node: 'http://localhost:9200' });async function search(query) {return await client.search({index: 'mdn',body: {query: {multi_match: {query: query,fields: ['title^3', 'tags^2', 'summary', 'content']}},highlight: {fields: {content: {}}}}});}
上述代码中,我们使用了 ElasticSearch 的 multi_match
查询。这个查询会在多个字段中搜索指定的搜索关键字,并按照指定的权重进行计算,最终返回一个包含匹配度的分数,分数越高,表示该匹配越相关。在这里,我们赋予了标题字段 title
更高的权重,标签字段 tags
次之,其余字段的权重相同。
为了让搜索结果更加人性化,我们还进行了高亮处理。在查询结果中,会将匹配到的关键字标记为带有样式的 HTML 标签,以突出显示搜索结果。
- 在前端代码中,我们使用了 ElasticLunr.js 作为客户端搜索库,该库提供了类似 ElasticSearch 的查询能力,并支持对搜索结果进行分页、高亮等操作。
以下是客户端代码的示例:
js
const index = elasticlunr(function() {this.addField('title');this.addField('tags');this.addField('summary');this.addField('content');});async function loadData() {const response = await fetch('/data/mdn.json');const data = await response.json();for (const item of data) {index.addDoc(item);}}function search(query) {const results = index.search(query, {fields: {title: { boost: 3 },tags: { boost: 2 },summary: {},content: {}},bool: 'OR',expand: true,wildcard: elasticlunr.Query.wildcard.LEADING | elasticlunr.Query.wildcard.TRAILING});return results.map(result => ({...result.doc,score: result.score}));}
上述代码中,我们在客户端中定义了一个 ElasticLunr 的索引,并为不同的字段分配了权重。这里和服务端的 multi_match
查询类似,区别在于 ElasticLunr 不支持在同一字段中指定不同权重,而是需要为每个字段单独指定权重。
在搜索过程中,我们调用了索引实例的 search()
方法,并传入查询字符串和一些其他参数。其中,fields
参数指定了每个字段的权重;bool
参数指定了多个关键字之间的逻辑关系(是 AND
还是 OR
);expand
参数指定了是否自动扩展查询字符串(例如将用户输入的 JS
扩展为 JavaScript
);wildcard
参数则指定了是否允许使用通配符查询。
具体实现细节可以参考以下资料: