【Elastic Engineering】Elasticsearch:使用 Elasticsearch 在键入时实现类似 Linkedin 的搜索

本文涉及的产品
检索分析服务 Elasticsearch 版,2核4GB开发者规格 1个月
简介: Elasticsearch:使用 Elasticsearch 在键入时实现类似 Linkedin 的搜索

作者:刘晓国


原文:Implementing a Linkedin like search as you type with Elasticsearch


在大多数社交网络中搜索时,你的直接联系人的排名将高于其他用户。 让我们看一下 Linkedin 的搜索,看看我们是否可以用 Elasticsearch 复制类似的东西。在这里也告诉大家一个小秘密:Linkedin 上面的搜索也是使用 Elasticsearch 完成的哦!

请注意,这篇文章仅在你输入建议时处理自动完成/搜索,并且在发送搜索后不会深入搜索搜索结果,从而产生搜索结果页面。


让我们看看 Linkedin 的搜索界面:

image.png


所以让我们看看这个搜索响应。 输入是 Philip。 我们将忽略任何非人的搜索结果或建议 - 前 6 条建议(非人)只是向你展示你可能还在搜索什么。

关注人员结果,列表中的最后五个。 前四个命中是在我的直接联系人中(也即是我的朋友或者同事)。 前两位也在 Elastic 工作。 第三个命中有 Philip 作为他的名字的一部分。 只有最后一个命中不是直接联系人 - 但也在我现在的雇主 Elastic 工作。

另一个需要注意的有趣的事情是,这显然是一个前缀(prefix)搜索,因为 Philipp 末尾有两个 p 也是一个有效匹配。

在收集需求之前,让我们尝试第二次搜索。

image.png

 

现在这很有趣,因为它与第一次搜索有很大不同。 我一点也不知道,为什么这不会在顶部给你任何非人的结果。 此外,似乎还有一些名为 Felix 的公司。 但是让我们看看人员搜索结果。

这次的第一个命中不是来自我的直接联系人,尽管我的直接联系人中有很多 Felix(这是复数,对吗?)。

显然,姓氏的完全匹配得分很高。

接下来是直接联系,首先是同事,然后是其他公司。 最后一个命中是 2 级命中,但也在 Elastic 工作。


计分规则


让我们尝试从两个结果中得出一些评分规则:

  • 搜索的名字和姓氏(first name 及 last name 这是两个不同的字段)
  • 姓氏精确匹配会使得排名靠前(还记得 TF/IDF 吗?与名字相比,Felix 很可能是一个罕见的姓氏,所以这可能是在没有调整的情况下发生的)。
  • 前缀匹配是可以的(见 Philip vs. Philipp)
  • 自己的联系人排名更高
  • 你自己雇主的第二级联系人排名更高


Data Model


接下来,让我们提出一个数据模型。

一、全文检索所需字段:名(first name)、姓(last name)、全名(full name)。

二,排名除了搜索字段外还需要的字段:雇主(employer)、直接联系人(direct contacts)。

三、显示必填字段:职称(title)、雇主(employer)。


映射数据模型


现在我先不解释映射(mapping),因为稍后需要一些映射功能来改进查询,让我们暂时坚持下去。

1. PUT social-network
2. {
3. "mappings": {
4. "properties": {
5. "name": {
6. "properties": {
7. "first": {
8. "type": "text",
9. "fields": {
10. "search-as-you-type": {
11. "type": "search_as_you_type"
12.               }
13.             }
14.           },
15. "last": {
16. "type": "text",
17. "fields": {
18. "search-as-you-type": {
19. "type": "search_as_you_type"
20.               }
21.             }
22.           },
23. "full": {
24. "type": "text",
25. "fields": {
26. "search-as-you-type": {
27. "type": "search_as_you_type"
28.               }
29.             }
30.           }
31.         }
32.       },
33. "employer": {
34. "type": "text"
35.       },
36. "contacts": {
37. "type": "keyword"
38.       },
39. "title": {
40. "type": "keyword"
41.       }
42.     }
43.   }
44. }

在上面,我使用了 search_as_you_type 数据类型。如果你对这个还是不很熟悉的话,请参阅我之前的文章 “Elasticsearch:Search-as-you-type 字段类型”。

接下来,让我们创建一个索引 pipelien 来自动创建全名(full name):

1. PUT _ingest/pipeline/name-pipeline
2. {
3. "processors": [
4.     {
5. "script": {
6. "source": "ctx.name.full = ctx.name.first + ' ' + ctx.name.last"
7.       }
8.     }
9.   ]
10. }

再接下来,让我们索引一些人,一些直接联系人,一些同事和一些根本没有联系人的人:

1. PUT social-network/_bulk?pipeline=name-pipeline
2. {"index":{"_id":"alexr"}}
3. {"name":{"first":"Alexander","last":"Reelsen"},"employer":"Elastic","title":"Community Advocate","contacts":["philippk","philipk","philippl"]}
4. {"index":{"_id":"philipk"}}
5. {"name":{"first":"Philip","last":"Kredible"},"employer":"Elastic","title":"Team Lead"}
6. {"index":{"_id":"philippl"}}
7. {"name":{"first":"Philipp","last":"Laughable"},"employer":"FancyWorks","title":"Senior Software Engineer"}
8. {"index":{"_id":"philippi"}}
9. {"name":{"first":"Philipp","last":"Incredible"},"employer":"21st Century Marketing","title":"CEO"}
10. {"index":{"_id":"philippb"}}
11. {"name":{"first":"Philipp Jean","last":"Blatantly"},"employer":"Monsters Inc.","title":"CEO"}
12. {"index":{"_id":"felixp"}}
13. {"name":{"first":"Felix","last":"Philipp"},"employer":"Felixia","title":"VP Engineering"}
14. {"index":{"_id":"philippk"}}
15. {"name":{"first":"Philipp","last":"Krenn"},"employer":"Elastic","title":"Community Advocate"}

为简单起见,我只为自己添加了直接联系人列表,在实际应用程序中,每个用户都会有自己的联系人列表。


搜索用户


好的,最简单的搜索优先展示 :),任意搜索 Philipp,这次只在 first name 字段中。

1. GET social-network/_search
2. {
3. "query": {
4. "match": {
5. "name.first": "Philipp"
6.     }
7.   }
8. }

如果要减少结果字段,请将 filter_path=**.name.full,**._score 附加到 URL 以仅包含 full name 和 score。

1. GET social-network/_search?filter_path=**.name.full,**._score
2. {
3. "query": {
4. "match": {
5. "name.first": "Philipp"
6.     }
7.   }
8. }

你会看到,所有文档的评分都相同(因为大多数字段仅在名字中包含 Philipp,但最后评分的 Philipp Jean 除外)。

1. {
2. "hits" : {
3. "hits" : [
4. {
5. "_score" : 0.6063718,
6. "_source" : {
7. "name" : {
8. "full" : "Philipp Laughable"
9. }
10. }
11. },
12. {
13. "_score" : 0.6063718,
14. "_source" : {
15. "name" : {
16. "full" : "Philipp Incredible"
17. }
18. }
19. },
20. {
21. "_score" : 0.6063718,
22. "_source" : {
23. "name" : {
24. "full" : "Philipp Krenn"
25. }
26. }
27. },
28. {
29. "_score" : 0.44027865,
30. "_source" : {
31. "name" : {
32. "full" : "Philipp Jean Blatantly"
33. }
34. }
35. }
36. ]
37. }
38. }

没有具体的顺序,因为分数相同并且没有定义 tie breaker。最后一个文档的得分较低是因为 full name 和其它的文章相比较长一些。你可以参阅文章 TF/IDF


给自己的联系人评分更高


好的,所以我的用户(first: Alexander)有一个联系人列表。 他们的影响力如何得分。 我们可以在 bool 查询中使用 should。 假设只有 Philipp Krenn 是我的同事。 我可以查看他的 id (philippk) 并像这样添加:

1. GET social-network/_search?filter_path=**.name.full,**._score
2. {
3. "query": {
4. "bool": {
5. "should": [
6.         {
7. "term": {
8. "_id": {
9. "value": "philippk"
10.             }
11.           }
12.         }
13.       ],
14. "must": [
15.         {
16. "match": {
17. "name.first": "Philipp"
18.           }
19.         }
20.       ]
21.     }
22.   }
23. }

响应如下所示:

1. {
2. "hits" : {
3. "hits" : [
4.       {
5. "_score" : 1.438688,
6. "_source" : {
7. "name" : {
8. "full" : "Philipp Krenn"
9.           }
10.         }
11.       },
12.       {
13. "_score" : 0.43868804,
14. "_source" : {
15. "name" : {
16. "full" : "Philipp Laughable"
17.           }
18.         }
19.       },
20.       ...
21.     ]
22.   }
23. }

在我看来不错! Philipp 现在得分更高。 但是在每次查询之前手动查找 id 太乏味了(想象一下为成千上万的联系人这样做)。 Elasticsearch 已经可以为我们做到这一点了! 有一个内置的术语查找(terms lookup)功能。 使用它,我们可以像这样自动查找我的用户的联系人列表。

1. GET social-network/_search?filter_path=**.name.full,**._score
2. {
3. "query": {
4. "bool": {
5. "should": [
6.         {
7. "terms": {
8. "_id": {
9. "index": "social-network",
10. "id": "alexr",
11. "path": "contacts"
12.             }
13.           }
14.         }
15.       ],
16. "must": [
17.         {
18. "match": {
19. "name.first": "Philipp"
20.           }
21.         }
22.       ]
23.     }
24.   }
25. }

响应如下所示:

1. {
2. "hits" : {
3. "hits" : [
4. {
5. "_score" : 1.6063719,
6. "_source" : {
7. "name" : {
8. "full" : "Philipp Laughable"
9. }
10. }
11. },
12. {
13. "_score" : 1.6063719,
14. "_source" : {
15. "name" : {
16. "full" : "Philipp Krenn"
17. }
18. }
19. },
20. {
21. "_score" : 0.6063718,
22. "_source" : {
23. "name" : {
24. "full" : "Philipp Incredible"
25. }
26. }
27. },
28. {
29. "_score" : 0.44027865,
30. "_source" : {
31. "name" : {
32. "full" : "Philipp Jean Blatantly"
33. }
34. }
35. }
36. ]
37. }
38. }

好吧,前两个命中是直接联系人中的,所以这对我来说听起来是一个很好的实现。 每当你添加新联系人时,请确保联系人数组已更新并且一切顺利。

然而,还有更多。


完全匹配的姓氏得分更高


我们看到姓氏匹配得更高。 让我们尝试一下,到目前为止,我们只搜索了名字,但也许我们可以使用 multi match 查询来搜索名字和姓氏。

1. GET social-network/_search?filter_path=**.name.full,**._score,**.employer
2. {
3. "query": {
4. "bool": {
5. "should": [
6.         {
7. "terms": {
8. "_id": {
9. "index": "social-network",
10. "id": "alexr",
11. "path": "contacts"
12.             }
13.           }
14.         }
15.       ],
16. "must": [
17.         {
18. "multi_match": {
19. "query": "Philipp",
20. "fields": [
21. "name.last",
22. "name.first"
23.             ]
24.           }
25.         }
26.       ]
27.     }
28.   }
29. }

让我们看看结果:

1. {
2. "hits" : {
3. "hits" : [
4. {
5. "_score" : 1.6739764,
6. "_source" : {
7. "name" : {
8. "full" : "Felix Philipp"
9. },
10. "employer" : "Felixia"
11. }
12. },
13. {
14. "_score" : 1.6063719,
15. "_source" : {
16. "name" : {
17. "full" : "Philipp Laughable"
18. },
19. "employer" : "FancyWorks"
20. }
21. },
22. {
23. "_score" : 1.6063719,
24. "_source" : {
25. "name" : {
26. "full" : "Philipp Krenn"
27. },
28. "employer" : "Elastic"
29. }
30. },
31. {
32. "_score" : 0.6063718,
33. "_source" : {
34. "name" : {
35. "full" : "Philipp Incredible"
36. },
37. "employer" : "21st Century Marketing"
38. }
39. },
40. {
41. "_score" : 0.44027865,
42. "_source" : {
43. "name" : {
44. "full" : "Philipp Jean Blatantly"
45. },
46. "employer" : "Monsters Inc."
47. }
48. }
49. ]
50. }
51. }

谢谢标准评分算法(best_fields)和我们非常小的数据集匹配 last name 得分最高。我们甚至可以使用加权的办法确保 last time 的得分较高:

1. GET social-network/_search?filter_path=**.name.full,**._score,**.employer
2. {
3. "query": {
4. "bool": {
5. "should": [
6.         {
7. "terms": {
8. "_id": {
9. "index": "social-network",
10. "id": "alexr",
11. "path": "contacts"
12.             }
13.           }
14.         }
15.       ],
16. "must": [
17.         {
18. "multi_match": {
19. "query": "Philipp",
20. "fields": [
21. "name.last^2",
22. "name.first"
23.             ]
24.           }
25.         }
26.       ]
27.     }
28.   }
29. }

在上面,我们使用 name.last^2 使得 last name 在计算分数时进行加权。


给同事打分更高


如果我们找到两个直接联系人,但一个用户为你的雇主(比如 Elastic)工作,那么如何给他们更高的评价? 幸运的是,我们可以添加一个 should 子句。

1. GET social-network/_search?filter_path=**.name.full,**._score,**.employer
2. {
3. "query": {
4. "bool": {
5. "should": [
6.         {
7. "terms": {
8. "_id": {
9. "index": "social-network",
10. "id": "alexr",
11. "path": "contacts"
12.             }
13.           }
14.         },
15.         {
16. "match": {
17. "employer": "Elastic"
18.           }
19.         }
20.       ],
21. "must": [
22.         {
23. "multi_match": {
24. "query": "Philipp",
25. "fields": [
26. "name.last",
27. "name.first"
28.             ]
29.           }
30.         }
31.       ]
32.     }
33.   }
34. }

结果是这些:

1. {
2. "hits" : {
3. "hits" : [
4. {
5. "_score" : 2.5486999,
6. "_source" : {
7. "name" : {
8. "full" : "Philipp Krenn"
9. },
10. "employer" : "Elastic"
11. }
12. },
13. {
14. "_score" : 1.6739764,
15. "_source" : {
16. "name" : {
17. "full" : "Felix Philipp"
18. },
19. "employer" : "Felixia"
20. }
21. },
22. {
23. "_score" : 1.6063719,
24. "_source" : {
25. "name" : {
26. "full" : "Philipp Laughable"
27. },
28. "employer" : "FancyWorks"
29. }
30. },
31. {
32. "_score" : 0.6063718,
33. "_source" : {
34. "name" : {
35. "full" : "Philipp Incredible"
36. },
37. "employer" : "21st Century Marketing"
38. }
39. },
40. {
41. "_score" : 0.44027865,
42. "_source" : {
43. "name" : {
44. "full" : "Philipp Jean Blatantly"
45. },
46. "employer" : "Monsters Inc."
47. }
48. }
49. ]
50. }
51. }

现在有了两个 should 子句,你可以看到得分发生了变化,并且 Philipp 作为姓氏不再得分最高。 这可能是期望的行为,也可能不是。 我们能做些什么来再次增加姓氏得分? 或者可能减少两个 should 从句? 另一个解决方案是给联系人打分更高,但员工只有在他们还没有联系人的情况下 - 因为这个查询变得更加复杂,这对你来说是一个练习。

另一种解决方案是通过将查询的必须部分更改为

1. "must": [
2. {
3. "multi_match": {
4. "query": "Philipp",
5. "boost": 2,
6. "fields": [
7. "name.last",
8. "name.first"
9. ]
10. }
11. }
12. ]

这样,must 部分变得更加重要。 如你所见,有很多方法可以调整和尝试使用你自己的数据。

还有最后一件事。


使用 “search-as-you-type” 数据类型


我们还没有涉及的一件事是部分匹配。 搜索 Philip 还应该返回我们数据集中的所有 Philipps。

现在下面的查询只返回 Philip Jan Kredible,我们唯一的只含有一个 p 字母的 Philip。

1. GET social-network/_search?filter_path=**.name.full,**._score,**.employer
2. {
3. "query": {
4. "bool": {
5. "should": [
6.         {
7. "terms": {
8. "_id": {
9. "index": "social-network",
10. "id": "alexr",
11. "path": "contacts"
12.             }
13.           }
14.         },
15.         {
16. "match": {
17. "employer": "Elastic"
18.           }
19.         }
20.       ],
21. "must": [
22.         {
23. "multi_match": {
24. "query": "Philip",
25. "boost": 2, 
26. "fields": [
27. "name.last",
28. "name.first"
29.             ]
30.           }
31.         }
32.       ]
33.     }
34.   }
35. }

还记得一开始的映射吗? name 字段包含我们现在利用的 search-as-you-type 类型映射。 该字段针对搜索进行了优化,因为你通过存储字段 shingle 和 edge ngram 标记过滤器来开箱即用地键入用例,以确保查询尽可能快 - 以需要更多磁盘空间为代价。

让我们切换 multi match 查询的类型:

1. GET social-network/_search?filter_path=**.name.full,**._score,**.employer
2. {
3. "query": {
4. "bool": {
5. "should": [
6.         {
7. "terms": {
8. "_id": {
9. "index": "social-network",
10. "id": "alexr",
11. "path": "contacts"
12.             }
13.           }
14.         },
15.         {
16. "match": {
17. "employer": "Elastic"
18.           }
19.         }
20.       ],
21. "must": [
22.         {
23. "multi_match": {
24. "query": "Philip",
25. "boost": 2, 
26. "type": "phrase_prefix", 
27. "fields": [
28. "name.last.search-as-you-type",
29. "name.first.search-as-you-type"
30.             ]
31.           }
32.         }
33.       ]
34.     }
35.   }
36. }

这将返回:

1. {
2. "hits" : {
3. "hits" : [
4. {
5. "_score" : 5.47071,
6. "_source" : {
7. "name" : {
8. "full" : "Philip Kredible"
9. },
10. "employer" : "Elastic"
11. }
12. },
13. {
14. "_score" : 3.3479528,
15. "_source" : {
16. "name" : {
17. "full" : "Felix Philipp"
18. },
19. "employer" : "Felixia"
20. }
21. },
22. {
23. "_score" : 3.1550717,
24. "_source" : {
25. "name" : {
26. "full" : "Philipp Krenn"
27. },
28. "employer" : "Elastic"
29. }
30. },
31. {
32. "_score" : 2.2127438,
33. "_source" : {
34. "name" : {
35. "full" : "Philipp Laughable"
36. },
37. "employer" : "FancyWorks"
38. }
39. },
40. {
41. "_score" : 1.2127436,
42. "_source" : {
43. "name" : {
44. "full" : "Philipp Incredible"
45. },
46. "employer" : "21st Century Marketing"
47. }
48. },
49. {
50. "_score" : 0.8805573,
51. "_source" : {
52. "name" : {
53. "full" : "Philipp Jean Blatantly"
54. },
55. "employer" : "Monsters Inc."
56. }
57. }
58. ]
59. }
60. }

首先是完全匹配(philip),第二是得分最高的姓氏(Philipp),然后是我的同事 Philipp Krenn。 看起来不错!

现在我们得到了完美的搜索? 好吧……尝试搜索 Philipp K - 我们没有得到任何结果。 那很糟!

然而,由于我们的摄入管道,我们也获得了全名索引,让我们将其添加到正在搜索的字段中:

1. GET social-network/_search?filter_path=**.name.full,**._score,**.employer
2. {
3. "query": {
4. "bool": {
5. "should": [
6.         {
7. "terms": {
8. "_id": {
9. "index": "social-network",
10. "id": "alexr",
11. "path": "contacts"
12.             }
13.           }
14.         },
15.         {
16. "match": {
17. "employer": "Elastic"
18.           }
19.         }
20.       ],
21. "must": [
22.         {
23. "multi_match": {
24. "query": "Philipp K",
25. "boost": 2, 
26. "type": "phrase_prefix", 
27. "fields": [
28. "name.full.search-as-you-type",
29. "name.last.search-as-you-type",
30. "name.first.search-as-you-type"
31.             ]
32.           }
33.         }
34.       ]
35.     }
36.   }
37. }

现在搜索 Philip、Philipp 和 Philipp K 会返回正确的结果。

还有一件事……


不关心 term 的顺序


不是每个人都知道他正在搜索的人的全名,所以有时你可能只输入姓氏。 搜索 Krenn 按预期工作,但是搜索 Krenn P 不会产生任何结果!

那么,我们能做些什么呢? 让我们的查询更大一点:

1. GET social-network/_search?filter_path=**.name.full,**._score,**.employer
2. {
3. "query": {
4. "bool": {
5. "should": [
6.         {
7. "terms": {
8. "_id": {
9. "index": "social-network",
10. "id": "alexr",
11. "path": "contacts"
12.             }
13.           }
14.         },
15.         {
16. "match": {
17. "employer": "Elastic"
18.           }
19.         }
20.       ],
21. "must": [
22.         {
23. "bool": {
24. "should": [
25.               {
26. "multi_match": {
27. "query": "Krenn P",
28. "operator": "and",
29. "boost": 2,
30. "type": "bool_prefix",
31. "fields": [
32. "name.full.search-as-you-type",
33. "name.full.search-as-you-type._2gram",
34. "name.full.search-as-you-type._3gram"
35.                   ]
36.                 }
37.               },
38.               {
39. "multi_match": {
40. "query": "Krenn P",
41. "boost": 2,
42. "type": "phrase_prefix",
43. "fields": [
44. "name.full.search-as-you-type",
45. "name.last.search-as-you-type",
46. "name.first.search-as-you-type"
47.                   ]
48.                 }
49.               }
50.             ]
51.           }
52.         }
53.       ]
54.     }
55.   }
56. }

此查询在所有先前情况下的行为相似,但还支持以任意顺序搜索术语(如姓氏在前),同时仍提供补全支持。上面的搜索结果为:

1. {
2. "hits" : {
3. "hits" : [
4. {
5. "_score" : 7.384149,
6. "_source" : {
7. "name" : {
8. "full" : "Philipp Krenn"
9. },
10. "employer" : "Elastic"
11. }
12. }
13. ]
14. }
15. }

现在作为最后一步,让我们在搜索端使它更易于维护。


使用搜索模板


最后一步是存储此搜索,以便搜索客户端只需提供一次输入查询。

让我们存储一个 mustache 脚本:

1. POST _scripts/social-query
2. {
3. "script": {
4. "lang": "mustache",
5. "source": {
6. "query": {
7. "bool": {
8. "should": [
9.             {
10. "terms": {
11. "_id": {
12. "index": "social-network",
13. "id": "{{own_id}}",
14. "path": "contacts"
15.                 }
16.               }
17.             },
18.             {
19. "match": {
20. "employer": "{{employer}}"
21.               }
22.             }
23.           ],
24. "must": [
25.             {
26. "bool": {
27. "should": [
28.                   {
29. "multi_match": {
30. "query": "{{query_string}}",
31. "operator": "and",
32. "boost": 2,
33. "type": "bool_prefix",
34. "fields": [
35. "name.full.search-as-you-type",
36. "name.full.search-as-you-type._2gram",
37. "name.full.search-as-you-type._3gram"
38.                       ]
39.                     }
40.                   },
41.                   {
42. "multi_match": {
43. "query": "{{query_string}}",
44. "boost": 2,
45. "type": "phrase_prefix",
46. "fields": [
47. "name.full.search-as-you-type",
48. "name.last.search-as-you-type",
49. "name.first.search-as-you-type"
50.                       ]
51.                     }
52.                   }
53.                 ]
54.               }
55.             }
56.           ]
57.         }
58.       }
59.     }
60.   }
61. }

现在查询超短,我们只需要提供一些查询信息:

1. GET social-network/_search/template
2. {
3. "id": "social-query", 
4. "params": {
5. "query_string": "Philipp",
6. "own_id" : "alexr",
7. "employer" : "Elastic"
8.     }
9. }

这种方法的另一个优点是,你现在可以在不更改应用程序的情况下切换查询的底层实现。 你甚至可以做一些花哨的事情,比如 a/b 测试。


最终优化:排除自己


尽管这在开始时听起来很有用,但我敢打赌,每个人都会时不时地在每个社交网络上搜索自己。 关闭自恋很难 :-)

你可以在 bool 查询中添加另一个过滤  {undefined{own_id}} 的 must_not 子句,并确保你在搜索内容时永远不会看到自己,但我认为这可能是一种不错的感觉。 此外,如果你继续包括自己,你可能希望使用 should 子句给自己打高分。

我特意没有在此处包含此示例,请随意尝试。

相关实践学习
使用阿里云Elasticsearch体验信息检索加速
通过创建登录阿里云Elasticsearch集群,使用DataWorks将MySQL数据同步至Elasticsearch,体验多条件检索效果,简单展示数据同步和信息检索加速的过程和操作。
ElasticSearch 入门精讲
ElasticSearch是一个开源的、基于Lucene的、分布式、高扩展、高实时的搜索与数据分析引擎。根据DB-Engines的排名显示,Elasticsearch是最受欢迎的企业搜索引擎,其次是Apache Solr(也是基于Lucene)。 ElasticSearch的实现原理主要分为以下几个步骤: 用户将数据提交到Elastic Search 数据库中 通过分词控制器去将对应的语句分词,将其权重和分词结果一并存入数据 当用户搜索数据时候,再根据权重将结果排名、打分 将返回结果呈现给用户 Elasticsearch可以用于搜索各种文档。它提供可扩展的搜索,具有接近实时的搜索,并支持多租户。
相关文章
|
2月前
|
存储 自然语言处理 BI
|
23天前
|
存储 缓存 固态存储
Elasticsearch高性能搜索
【11月更文挑战第1天】
34 6
|
21天前
|
API 索引
Elasticsearch实时搜索
【11月更文挑战第2天】
30 1
|
2月前
|
人工智能
云端问道12期-构建基于Elasticsearch的企业级AI搜索应用陪跑班获奖名单公布啦!
云端问道12期-构建基于Elasticsearch的企业级AI搜索应用陪跑班获奖名单公布啦!
177 2
|
2月前
|
Web App开发 JavaScript Java
elasticsearch学习五:springboot整合 rest 操作elasticsearch的 实际案例操作,编写搜索的前后端,爬取京东数据到elasticsearch中。
这篇文章是关于如何使用Spring Boot整合Elasticsearch,并通过REST客户端操作Elasticsearch,实现一个简单的搜索前后端,以及如何爬取京东数据到Elasticsearch的案例教程。
205 0
elasticsearch学习五:springboot整合 rest 操作elasticsearch的 实际案例操作,编写搜索的前后端,爬取京东数据到elasticsearch中。
|
4月前
|
人工智能 自然语言处理 搜索推荐
阿里云Elasticsearch AI搜索实践
本文介绍了阿里云 Elasticsearch 在AI 搜索方面的技术实践与探索。
19173 21
|
3月前
|
存储 缓存 自然语言处理
深度解析ElasticSearch:构建高效搜索与分析的基石
【9月更文挑战第8天】在数据爆炸的时代,如何快速、准确地从海量数据中检索出有价值的信息成为了企业面临的重要挑战。ElasticSearch,作为一款基于Lucene的开源分布式搜索和分析引擎,凭借其强大的实时搜索、分析和扩展能力,成为了众多企业的首选。本文将深入解析ElasticSearch的核心原理、架构设计及优化实践,帮助读者全面理解这一强大的工具。
209 7
因为一个问题、我新学了一门技术 ElasticSearch 分布式搜索
这篇文章讲述了作者因为一个检索问题而学习了ElasticSearch技术,并分享了排查和解决ElasticSearch检索结果与页面展示不符的过程。
因为一个问题、我新学了一门技术 ElasticSearch 分布式搜索
|
3月前
|
JSON 监控 Java
Elasticsearch 入门:搭建高性能搜索集群
【9月更文第2天】Elasticsearch 是一个分布式的、RESTful 风格的搜索和分析引擎,基于 Apache Lucene 构建。它能够处理大量的数据,提供快速的搜索响应。本教程将指导你如何从零开始搭建一个基本的 Elasticsearch 集群,并演示如何进行简单的索引和查询操作。
233 3
|
4月前
|
存储 人工智能 安全
保障隐私的Elasticsearch AI搜索解决方案
【8月更文第28天】随着大数据和人工智能技术的发展,搜索引擎在日常生活中扮演着越来越重要的角色。然而,用户隐私保护成为了一个不容忽视的问题。本文将探讨如何在确保用户数据隐私的同时,利用Elasticsearch实现智能搜索功能。我们将介绍一种综合方案,该方案结合了加密技术、差分隐私、匿名化处理以及安全多方计算等方法,以保障用户数据的安全性
178 0

相关产品

  • 检索分析服务 Elasticsearch版