Elasticsearch實戰(zhàn)應(yīng)用:五大業(yè)務(wù)場景深入解析

2024-12-17 16:26 更新

大家好,我是 V 哥。Elasticsearch 是一個強大的全文搜索和分析引擎,廣泛應(yīng)用于各種場景。以下是五個常見業(yè)務(wù)場景中的 Elasticsearch 實戰(zhàn)應(yīng)用案例及其詳細分析。

1. 全文搜索與高亮顯示

業(yè)務(wù)場景: 某電商平臺需要為用戶提供高效的商品搜索功能,要求在海量數(shù)據(jù)中快速返回匹配結(jié)果,并高亮顯示關(guān)鍵字,提升用戶體驗。

解決方案:

  • 索引設(shè)計: 對商品名稱、描述、品牌等字段進行全文索引,使用 Elasticsearch 的分詞器(如 Standard Analyzer)處理數(shù)據(jù),確保用戶輸入的關(guān)鍵字可以正確匹配商品信息。
  • 搜索功能: 使用 match 查詢類型,配合 multi_match 進行多個字段的搜索,確保用戶查詢能匹配到商品名稱、描述等相關(guān)字段。
  • 高亮顯示: 使用 highlight 功能,在返回的結(jié)果中對匹配的關(guān)鍵字進行高亮處理,提升用戶可讀性。

詳細分析: Elasticsearch 提供了強大的倒排索引機制,使得全文搜索非常高效。通過靈活的查詢組合,用戶可以精確匹配多種字段的搜索條件,同時高亮功能可以讓用戶直觀地看到匹配位置。此方案提升了用戶的搜索體驗,并能迅速處理電商平臺的大量商品數(shù)據(jù)。

要實現(xiàn)全文搜索與高亮顯示的功能,主要分為以下幾個步驟,包括 Elasticsearch 環(huán)境的設(shè)置、數(shù)據(jù)的索引、查詢的編寫,以及高亮顯示的處理。具體如下:

1. 環(huán)境準備

確保 Elasticsearch 已經(jīng)安裝并運行。如果尚未安裝,可以通過 Docker 快速啟動一個 Elasticsearch 實例:

docker run -d --name elasticsearch -p 9200:9200 -e "discovery.type=single-node" elasticsearch:8.0.0

然后可以通過以下 URL 訪問 Elasticsearch API:

http://localhost:9200

2. 創(chuàng)建索引與映射

在實際場景中,可能需要為商品(或者其他實體)創(chuàng)建一個索引。首先為該索引配置字段和分詞器,確保字段能夠支持全文檢索。

創(chuàng)建索引和映射

我們?yōu)樯唐沸畔?chuàng)建一個索引,定義商品名稱和描述的字段類型為 text,并指定使用默認的分詞器。

PUT /products
{
  "mappings": {
    "properties": {
      "name": {
        "type": "text"
      },
      "description": {
        "type": "text"
      },
      "price": {
        "type": "float"
      }
    }
  }
}

3. 添加商品數(shù)據(jù)

在創(chuàng)建好索引后,可以開始向索引中插入一些商品數(shù)據(jù)。以下是一些商品的示例數(shù)據(jù):

POST /products/_doc/1
{
  "name": "huawei mate 70",
  "description": "mate 70 手機是搭載純血鴻蒙NEXT 系統(tǒng)的第一款旗艦機",
  "price": 6500
}


POST /products/_doc/2
{
  "name": "huawei Mate XT非凡大師",
  "description": "非凡大師 16GB+1TB玄黑 ULTIMATE DESIGN",
  "price": 23999
}


POST /products/_doc/3
{
  "name": "huawei Mate X5",
  "description": "huawei mate x5 12GB+512GB 羽砂黑 超輕薄四曲折疊,超高清高分辨率臨境雙屏,超智慧靈犀通信",
  "price": 12499
}

4. 實現(xiàn)搜索功能

使用 match 查詢來實現(xiàn)對商品名稱和描述字段的全文搜索。為了能高效地搜索到多個字段中的內(nèi)容,我們可以使用 multi_match 查詢。比如用戶在搜索框中輸入了“iPhone”時,我們希望在商品名稱和描述中都查找匹配項。

基本查詢

GET /products/_search
{
  "query": {
    "multi_match": {
      "query": "X5",
      "fields": ["name", "description"]
    }
  }
}

這個查詢會返回所有匹配“iPhone”關(guān)鍵字的商品。

5. 添加高亮顯示

為了增強用戶體驗,可以使用 Elasticsearch 的高亮功能,顯示搜索結(jié)果中的匹配詞語。通過在查詢中添加 highlight,我們可以讓關(guān)鍵字在返回結(jié)果中高亮顯示。

帶高亮顯示的查詢

GET /products/_search
{
  "query": {
    "multi_match": {
      "query": "X5",
      "fields": ["name", "description"]
    }
  },
  "highlight": {
    "fields": {
      "name": {},
      "description": {}
    }
  }
}

6. 結(jié)果解析

Elasticsearch 返回的結(jié)果中會包含高亮字段。例如,假設(shè)用戶搜索“iPhone”,以下是一個可能的響應(yīng)結(jié)果:

{
  "hits": {
    "total": {
      "value": 1,
      "relation": "eq"
    },
    "hits": [
      {
        "_index": "products",
        "_id": "1",
        "_source": {
          "name": "huawei Mate X5",
          "description": "huawei mate x5 12GB+512GB 羽砂黑 超輕薄四曲折疊,超高清高分辨率臨境雙屏,超智慧靈犀通信",
          "price": 12499
        },
        "highlight": {
          "name": ["huawei <em>x5</em> 14"],
          "description": ["huawei mate <em>x5</em> 12GB+512GB 羽砂黑 超輕薄四曲折疊,超高清高分辨率臨境雙屏,超智慧靈犀通信"]
        }
      }
    ]
  }
}

從結(jié)果中可以看到,高亮部分會以 <em> 標簽包裹,我們可以根據(jù)需求在前端使用 CSS 或 HTML 標簽來調(diào)整高亮顯示的樣式。

7. 前端展示

在前端頁面中,搜索結(jié)果可以通過解析響應(yīng)中的 _sourcehighlight 字段,將高亮部分以更明顯的方式展示給用戶。假設(shè)我們使用 JavaScript 進行結(jié)果展示,代碼可能如下:

<ul id="search-results"></ul>


<script>
  const results = [
    {
      "_source": {
        "name": "huawei Mate X5",
        "description": "huawei mate x5 12GB+512GB 羽砂黑 超輕薄四曲折疊,超高清高分辨率臨境雙屏,超智慧靈犀通信"
      },
      "highlight": {
        "name": ["huawei Mate <em>X5</em>"],
        "description": ["huawei mate <em>X5</em> 12GB+512GB 羽砂黑 超輕薄四曲折疊,超高清高分辨率臨境雙屏,超智慧靈犀通信"]
      }
    }
  ];


  const resultsContainer = document.getElementById('search-results');
  results.forEach(result => {
    const listItem = document.createElement('li');
    listItem.innerHTML = `
      <h2>${result.highlight.name ? result.highlight.name[0] : result._source.name}</h2>
      <p>${result.highlight.description ? result.highlight.description[0] : result._source.description}</p>
    `;
    resultsContainer.appendChild(listItem);
  });
</script>

在上面的例子中,前端會展示包含 <em> 標簽的文本,該標簽會將搜索到的關(guān)鍵字(如“x5”)高亮顯示。

8. 擴展:自定義分詞器和同義詞

如果搜索場景中需要更復(fù)雜的匹配,比如同義詞搜索、拼寫糾錯等,可以進一步定制分詞器或通過同義詞字典進行擴展。

使用自定義分詞器

PUT /products
{
  "settings": {
    "analysis": {
      "analyzer": {
        "synonym_analyzer": {
          "tokenizer": "whitespace",
          "filter": ["synonym_filter"]
        }
      },
      "filter": {
        "synonym_filter": {
          "type": "synonym",
          "synonyms": [
            "x5, mate x5",
            "mate70, 非凡大師"
          ]
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "name": {
        "type": "text",
        "analyzer": "synonym_analyzer"
      },
      "description": {
        "type": "text",
        "analyzer": "synonym_analyzer"
      }
    }
  }
}

通過同義詞分析器,用戶搜索“ huawei mate”時也可以匹配到包含“mate”的文檔,從而進一步提升搜索的準確性。

小結(jié)一下

通過上述步驟,我們可以實現(xiàn)一個完整的 Elasticsearch 全文搜索與高亮顯示的功能。這個功能適用于電商平臺、博客搜索、文檔系統(tǒng)等多種業(yè)務(wù)場景,提供快速、高效、用戶友好的搜索體驗。

2. 日志收集與分析

業(yè)務(wù)場景: 某 SaaS 公司需要對其分布式系統(tǒng)中的應(yīng)用日志進行集中管理、實時監(jiān)控與分析,要求快速定位系統(tǒng)錯誤和性能瓶頸。使用 Elasticsearch 可以集中存儲和分析分布式系統(tǒng)中的日志,快速查詢和監(jiān)控日志數(shù)據(jù)。

解決方案:

  • 日志收集: 使用 Logstash 或 Filebeat 作為數(shù)據(jù)采集工具,將各個應(yīng)用的日志發(fā)送到 Elasticsearch 進行存儲和索引。
  • 日志分析: 使用 Elasticsearch 的 aggregations 聚合功能進行日志的統(tǒng)計分析,如錯誤分類、按時間段的訪問量統(tǒng)計等。
  • 實時監(jiān)控: 配合 Kibana,構(gòu)建實時的日志監(jiān)控和告警系統(tǒng),通過可視化的方式展示日志數(shù)據(jù),快速發(fā)現(xiàn)異常。

詳細分析: Elasticsearch 是 ELK(Elasticsearch, Logstash, Kibana)技術(shù)棧中的核心組件,它不僅支持大規(guī)模日志數(shù)據(jù)的存儲,還能通過內(nèi)置的聚合和搜索功能,實現(xiàn)實時分析與可視化。對于分布式系統(tǒng)中的日志分析場景,Elasticsearch 通過分片和復(fù)制機制提供了高可用性和擴展性,保證了海量日志數(shù)據(jù)的快速查詢和處理。

以下是一個完整的實現(xiàn)案例,包括從日志的收集、傳輸、存儲到實時分析的步驟。

1. 環(huán)境準備

在實際應(yīng)用中,日志的收集與分析一般采用 ELK(Elasticsearch, Logstash, Kibana)或 EFK(Elasticsearch, Filebeat, Kibana)技術(shù)棧。這里我們選擇 Filebeat 作為日志采集工具,Elasticsearch 作為數(shù)據(jù)存儲和查詢引擎,Kibana 作為可視化和監(jiān)控工具。

啟動 Elasticsearch 和 Kibana(Docker 方式)

## 啟動 Elasticsearch
docker run -d --name elasticsearch -p 9200:9200 -e "discovery.type=single-node" elasticsearch:8.0.0


## 啟動 Kibana
docker run -d --name kibana -p 5601:5601 --link elasticsearch:elasticsearch kibana:8.0.0

訪問 Kibana: http://localhost:5601,確保 Elasticsearch 和 Kibana 正常啟動并連接成功。

2. 安裝并配置 Filebeat

Filebeat 是一個輕量級的日志收集工具,能夠監(jiān)控文件變化,并將日志數(shù)據(jù)發(fā)送到 Elasticsearch 或 Logstash。

安裝 Filebeat

可以通過以下方式在系統(tǒng)中安裝 Filebeat:

## 在 Linux 中安裝 Filebeat
sudo apt-get install filebeat

配置 Filebeat

Filebeat 的配置文件 filebeat.yml 是日志收集的核心,它定義了從哪里收集日志,日志如何處理,并發(fā)送到哪里。以下是一個典型的配置文件,用于將日志發(fā)送到 Elasticsearch。

filebeat.inputs:
- type: log
  enabled: true
  paths:
    - /var/log/myapp/*.log  # 日志文件路徑


output.elasticsearch:
  hosts: ["localhost:9200"]  # 指定 Elasticsearch 地址
  username: "elastic"
  password: "changeme"  # 設(shè)置 Elasticsearch 認證


setup.kibana:
  host: "localhost:5601"  # Kibana 的地址

這段配置定義了 Filebeat 從 /var/log/myapp/*.log 目錄下讀取日志文件,并將其傳送到 Elasticsearch 中進行存儲。同時,還配置了 Kibana 的連接,便于后續(xù)可視化分析。

啟動 Filebeat

sudo filebeat modules enable system
sudo filebeat setup
sudo service filebeat start

3. Elasticsearch 索引和映射

在日志數(shù)據(jù)發(fā)送到 Elasticsearch 之前,需要為日志數(shù)據(jù)創(chuàng)建索引,并為其指定字段映射。可以使用 Elasticsearch 動態(tài)映射的功能來自動創(chuàng)建索引,但為了更好地處理日志中的日期、字符串等數(shù)據(jù)類型,建議手動創(chuàng)建索引映射。

創(chuàng)建索引映射

PUT /logs-system
{
  "mappings": {
    "properties": {
      "timestamp": {
        "type": "date"
      },
      "log.level": {
        "type": "keyword"
      },
      "message": {
        "type": "text"
      },
      "service.name": {
        "type": "keyword"
      },
      "host.name": {
        "type": "keyword"
      },
      "process.pid": {
        "type": "integer"
      }
    }
  }
}

在這個映射中,我們?yōu)橄到y(tǒng)日志定義了幾個重要的字段:

  • timestamp: 日志的時間戳,數(shù)據(jù)類型為 date。
  • log.level: 日志級別,如 INFO, ERROR 等,數(shù)據(jù)類型為 keyword。
  • message: 日志的內(nèi)容,使用 text 類型進行全文索引。
  • service.name: 服務(wù)名稱,用于區(qū)分不同的服務(wù)。
  • host.name: 記錄日志的主機名,用于定位具體的機器。
  • process.pid: 進程 ID,用于進一步跟蹤問題。

4. 日志采集與發(fā)送

當(dāng) Filebeat 啟動后,它會監(jiān)控配置文件中的日志文件路徑(例如 /var/log/myapp/*.log),并將新生成的日志行發(fā)送到 Elasticsearch 中。

日志文件示例

假設(shè)應(yīng)用程序生成了如下格式的日志文件 /var/log/myapp/app.log

2024-10-14T12:30:00Z INFO [my-service] Service started
2024-10-14T12:31:00Z ERROR [my-service] Failed to connect to database
2024-10-14T12:32:00Z WARN [my-service] Low disk space on /dev/sda1

這些日志文件會被 Filebeat 采集并自動傳送到 Elasticsearch 中,按配置的索引存儲。

5. 實時日志查詢與分析

一旦日志數(shù)據(jù)進入 Elasticsearch,我們可以使用 Kibana 進行實時查詢和分析。

在 Kibana 中創(chuàng)建索引模式

  1. 訪問 Kibana 管理界面 http://localhost:5601。
  2. 點擊 Management > Index Patterns,創(chuàng)建一個新的索引模式 logs-system-*,這將匹配 Elasticsearch 中的日志索引。
  3. timestamp 字段設(shè)置為時間過濾字段,用于時間范圍篩選。

在 Kibana 中進行搜索

Kibana 提供了一個非常強大的查詢語言——KQL(Kibana Query Language),可以在 Kibana 中對日志數(shù)據(jù)進行各種查詢和過濾。例如:

  1. 查詢所有 ERROR 級別的日志:

   log.level: "ERROR"

  1. 查詢特定服務(wù)的日志:

   service.name: "my-service"

  1. 結(jié)合日志級別和時間范圍查詢:

   log.level: "ERROR" AND @timestamp > "2024-10-14T12:00:00Z"

6. 聚合分析

Elasticsearch 提供了強大的 aggregations 聚合功能,可以用于統(tǒng)計和分析日志數(shù)據(jù)中的各種模式。以下是幾個常用的聚合查詢示例:

統(tǒng)計不同日志級別的日志數(shù)量

GET /logs-system/_search
{
  "size": 0,
  "aggs": {
    "by_log_level": {
      "terms": {
        "field": "log.level"
      }
    }
  }
}

按時間段統(tǒng)計每分鐘的錯誤日志數(shù)量

GET /logs-system/_search
{
  "size": 0,
  "query": {
    "match": {
      "log.level": "ERROR"
    }
  },
  "aggs": {
    "logs_over_time": {
      "date_histogram": {
        "field": "timestamp",
        "interval": "minute"
      }
    }
  }
}

7. 創(chuàng)建告警(Alerting)

為了實現(xiàn)實時監(jiān)控和錯誤告警,我們可以使用 Kibana 的告警功能,設(shè)置觸發(fā)條件和告警機制。

配置告警步驟

  1. 打開 Kibana,進入 Alerts and Actions 頁面。
  2. 創(chuàng)建新的告警規(guī)則,例如:
    • 當(dāng)錯誤日志超過某個閾值時發(fā)送通知(如郵件、Slack 消息等)。
  3. 配置觸發(fā)條件,例如每分鐘的錯誤日志超過 10 條時觸發(fā)告警。

8. 結(jié)果可視化

Kibana 提供了豐富的可視化功能,你可以通過以下方式展示和分析日志數(shù)據(jù):

  • 折線圖:展示一段時間內(nèi)日志數(shù)量的變化趨勢。
  • 柱狀圖:展示不同服務(wù)或主機生成的日志數(shù)量。
  • 餅圖:展示不同日志級別(INFO, ERROR, WARN)的比例。

可視化示例

  • 按服務(wù)統(tǒng)計日志級別分布:在 Kibana 中創(chuàng)建柱狀圖,X 軸為 service.name,Y 軸為日志數(shù)量,按 log.level 進行分組。
  • 實時監(jiān)控儀表盤:創(chuàng)建一個儀表盤,展示不同服務(wù)的實時日志流量、錯誤數(shù)量等,便于運維人員實時監(jiān)控系統(tǒng)健康狀態(tài)。

9. 小結(jié)一下

通過 Elasticsearch、Filebeat 和 Kibana 的配合,我們可以快速搭建一個集中式日志收集與分析系統(tǒng),實現(xiàn)對分布式系統(tǒng)日志的實時監(jiān)控和告警。步驟包括:

  • 使用 Filebeat 收集各服務(wù)的日志。
  • 使用 Elasticsearch 存儲和聚合日志數(shù)據(jù)。
  • 通過 Kibana 實現(xiàn)可視化分析和告警通知。

這種架構(gòu)能夠幫助 SaaS 公司快速定位系統(tǒng)錯誤、分析性能瓶頸,并為系統(tǒng)運維提供實時的可視化支持。

3. 個性化推薦系統(tǒng)

業(yè)務(wù)場景: 某在線視頻平臺希望通過構(gòu)建個性化推薦系統(tǒng),根據(jù)用戶的歷史觀看記錄、興趣偏好和行為數(shù)據(jù),為用戶推薦相關(guān)視頻內(nèi)容。這類推薦系統(tǒng)有助于提升用戶的粘性和轉(zhuǎn)化率,進一步推動平臺的商業(yè)化。為了實現(xiàn)該目標,可以采用基于 Elasticsearch 的內(nèi)容推薦模型,結(jié)合協(xié)同過濾(Collaborative Filtering)、內(nèi)容過濾(Content-Based Filtering)以及基于行為的數(shù)據(jù)分析。

解決方案:

  • 用戶行為數(shù)據(jù)建模: 將用戶的瀏覽歷史、點贊、評論等行為數(shù)據(jù)記錄到 Elasticsearch 中,并構(gòu)建倒排索引以便快速查詢。
  • 推薦算法: 使用 More Like This 查詢,根據(jù)用戶歷史觀看的視頻,推薦相似的視頻。結(jié)合 function_score 查詢,基于用戶行為頻次加權(quán),個性化推薦排序。
  • 動態(tài)調(diào)整推薦結(jié)果: 使用 Elasticsearch 的聚合分析功能,定期統(tǒng)計受歡迎的視頻,并結(jié)合流行度(如播放量、點贊數(shù))來調(diào)整推薦策略。

詳細分析: Elasticsearch 的 More Like This 查詢非常適合用于相似內(nèi)容推薦的場景,能夠根據(jù)用戶的興趣偏好進行相關(guān)視頻的推薦。其高效的索引和查詢機制,加上支持復(fù)雜的查詢組合,使得推薦系統(tǒng)既能保持較高的實時性,又能根據(jù)動態(tài)數(shù)據(jù)調(diào)整推薦結(jié)果。

實現(xiàn)步驟

  1. 數(shù)據(jù)準備與索引設(shè)計
  2. 用戶行為數(shù)據(jù)的存儲與分析
  3. 基于內(nèi)容的推薦算法
  4. 基于協(xié)同過濾的推薦算法
  5. 綜合推薦與實時推薦
  6. 結(jié)果展示與優(yōu)化

1. 數(shù)據(jù)準備與索引設(shè)計

推薦系統(tǒng)的核心是數(shù)據(jù),首先我們需要創(chuàng)建 Elasticsearch 索引來存儲用戶和視頻的數(shù)據(jù)。

視頻內(nèi)容索引

視頻索引中包含視頻的基礎(chǔ)信息,如標題、描述、標簽、類別等,這些信息可以用來計算視頻的相似度。

PUT /videos
{
  "mappings": {
    "properties": {
      "title": {
        "type": "text"
      },
      "description": {
        "type": "text"
      },
      "tags": {
        "type": "keyword"
      },
      "category": {
        "type": "keyword"
      },
      "release_date": {
        "type": "date"
      }
    }
  }
}

用戶行為索引

我們還需要存儲用戶的行為數(shù)據(jù),比如他們看過哪些視頻,搜索過哪些關(guān)鍵詞等。這些數(shù)據(jù)將用于個性化推薦。

PUT /user_actions
{
  "mappings": {
    "properties": {
      "user_id": {
        "type": "keyword"
      },
      "video_id": {
        "type": "keyword"
      },
      "action_type": {
        "type": "keyword"   # 例如: view, like, search, etc.
      },
      "timestamp": {
        "type": "date"
      }
    }
  }
}

2. 用戶行為數(shù)據(jù)的存儲與分析

用戶行為數(shù)據(jù)是個性化推薦的核心依據(jù)。我們可以通過 Filebeat 等工具實時采集用戶的觀看行為數(shù)據(jù),并將其存儲到 Elasticsearch 中。

例如,用戶觀看了某個視頻,行為數(shù)據(jù)可能如下:

POST /user_actions/_doc
{
  "user_id": "weige",
  "video_id": "video789",
  "action_type": "view",
  "timestamp": "2024-10-14T12:30:00Z"
}

為了分析用戶的興趣,我們可以使用 Elasticsearch 的聚合功能。比如,統(tǒng)計用戶觀看最多的類別和標簽,以此作為興趣偏好的基礎(chǔ)。

聚合查詢:統(tǒng)計某用戶觀看最多的視頻類別

GET /user_actions/_search
{
  "size": 0,
  "query": {
    "term": {
      "user_id": "weige"
    }
  },
  "aggs": {
    "favorite_categories": {
      "terms": {
        "field": "category.keyword",
        "size": 5
      }
    }
  }
}

該查詢可以幫助我們了解用戶最常觀看的前 5 個視頻類別。

3. 基于內(nèi)容的推薦算法

基于內(nèi)容的推薦算法通過分析用戶觀看過的視頻內(nèi)容(標題、描述、標簽等),為用戶推薦相似的視頻。我們可以使用 Elasticsearch 的 more_like_this 查詢來找到和用戶已觀看內(nèi)容相似的視頻。

使用 more_like_this 進行基于內(nèi)容的推薦

假設(shè)用戶剛剛觀看了視頻 video789,我們希望找到與該視頻內(nèi)容相似的其他視頻。

GET /videos/_search
{
  "query": {
    "more_like_this": {
      "fields": ["title", "description", "tags"],
      "like": [
        {
          "_id": "video789"
        }
      ],
      "min_term_freq": 1,
      "max_query_terms": 12
    }
  }
}

這個查詢會根據(jù)視頻 video789 的標題、描述和標簽,推薦相似的視頻。min_term_freqmax_query_terms 可以用來調(diào)整推薦的相似度。

4. 基于協(xié)同過濾的推薦算法

協(xié)同過濾(Collaborative Filtering)是另一種常用的推薦算法,它通過分析不同用戶的行為數(shù)據(jù),尋找用戶之間的相似性,從而推薦其他用戶喜歡的視頻。

查詢與用戶行為相似的用戶

我們可以通過 Elasticsearch 的聚合來查找與當(dāng)前用戶行為相似的其他用戶,比如查找同樣觀看過某個視頻的用戶。

GET /user_actions/_search
{
  "size": 0,
  "query": {
    "term": {
      "video_id": "video789"
    }
  },
  "aggs": {
    "similar_users": {
      "terms": {
        "field": "user_id.keyword",
        "size": 10
      }
    }
  }
}

通過這個查詢,我們找到了所有觀看過 video789 的用戶列表。接下來,我們可以根據(jù)這些用戶的觀看歷史,推薦他們喜歡的視頻給當(dāng)前用戶。

基于協(xié)同過濾推薦其他用戶喜歡的視頻

找到與當(dāng)前用戶相似的其他用戶后,我們可以查詢他們共同觀看的視頻,并為當(dāng)前用戶推薦這些視頻。

GET /user_actions/_search
{
  "size": 10,
  "query": {
    "terms": {
      "user_id": ["weige123", "weige456"]  # 與當(dāng)前用戶相似的用戶
    }
  },
  "aggs": {
    "recommended_videos": {
      "terms": {
        "field": "video_id.keyword",
        "size": 5
      }
    }
  }
}

通過這個查詢,可以推薦其他用戶看過且當(dāng)前用戶還沒有觀看過的視頻。

5. 綜合推薦與實時推薦

為了提高推薦的準確性,可以將基于內(nèi)容的推薦和協(xié)同過濾結(jié)合在一起,綜合考慮用戶的興趣和行為數(shù)據(jù)。

結(jié)合用戶興趣和行為的推薦

首先,我們可以獲取用戶最喜歡的類別和標簽,然后結(jié)合用戶歷史行為推薦符合這些興趣的熱門視頻。

GET /videos/_search
{
  "query": {
    "bool": {
      "should": [
        { "match": { "category": "user_favorite_category" } },
        { "match": { "tags": "user_favorite_tags" } }
      ]
    }
  },
  "sort": [
    { "release_date": { "order": "desc" } }
  ]
}

這種推薦方式綜合了用戶的興趣和最新視頻內(nèi)容,有助于提升用戶體驗。

6. 結(jié)果展示與優(yōu)化

在前端展示推薦結(jié)果

推薦結(jié)果可以通過前端 API 展示給用戶,假設(shè)通過 JavaScript 請求 Elasticsearch 來獲取推薦內(nèi)容,代碼示例如下:

fetch('http://localhost:9200/videos/_search', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    "query": {
      "more_like_this": {
        "fields": ["title", "description", "tags"],
        "like": [
          {
            "_id": "video789"
          }
        ],
        "min_term_freq": 1,
        "max_query_terms": 12
      }
    }
  })
})
.then(response => response.json())
.then(data => {
  console.log("Recommended videos:", data.hits.hits);
  // 展示推薦視頻內(nèi)容
});

不斷優(yōu)化推薦算法

  • 用戶反饋:通過用戶對推薦視頻的反饋(如點贊、點擊等),進一步優(yōu)化推薦算法。
  • 實時推薦:通過 Kafka 等流處理工具,實時監(jiān)控用戶行為數(shù)據(jù),并調(diào)整推薦結(jié)果。

7. 小結(jié)一下

構(gòu)建個性化推薦系統(tǒng)的關(guān)鍵在于對用戶興趣和行為的深刻理解。通過 Elasticsearch,可以輕松實現(xiàn)以下功能:

  • 內(nèi)容推薦:基于視頻內(nèi)容相似性為用戶推薦視頻。
  • 協(xié)同過濾:基于相似用戶行為推薦視頻。
  • 實時推薦:結(jié)合用戶實時行為和興趣,提供最新的個性化推薦。

這種推薦系統(tǒng)不僅能提升用戶粘性,還能增加視頻播放量和廣告轉(zhuǎn)化率,為在線視頻平臺帶來更多的商業(yè)收益。

4. 商品價格區(qū)間統(tǒng)計與篩選

業(yè)務(wù)場景: 在在線商城中,用戶經(jīng)常根據(jù)價格來篩選商品。商城需要提供按價格區(qū)間篩選商品的功能,并實時統(tǒng)計每個價格區(qū)間內(nèi)的商品數(shù)量,以便用戶快速選擇符合其預(yù)算的商品。這類功能可以通過 Elasticsearch 的聚合查詢來高效實現(xiàn)。

解決方案:

  • 數(shù)據(jù)存儲: 將商品的價格字段建模為 numeric 類型,并存儲到 Elasticsearch 中。
  • 聚合分析: 使用 Elasticsearch 的 range 聚合功能,將商品按價格區(qū)間分類,統(tǒng)計各區(qū)間內(nèi)商品數(shù)量。例如:0-100 元,100-500 元,500-1000 元等。
  • 篩選與排序: 配合 filter 查詢,支持用戶在前端選擇價格區(qū)間進行篩選,展示符合條件的商品,并按價格升序或降序排列。

詳細分析: Elasticsearch 的聚合功能特別適合用于統(tǒng)計類場景。在價格篩選應(yīng)用中,range 聚合能夠?qū)崟r計算各個價格區(qū)間的商品數(shù)量,配合過濾查詢實現(xiàn)快速篩選。這種機制不僅響應(yīng)速度快,還能動態(tài)適應(yīng)不斷變化的數(shù)據(jù)規(guī)模,保持較高的用戶體驗。

該方案的實現(xiàn)步驟如下:

  1. 創(chuàng)建商品索引,存儲商品信息
  2. 使用 range 查詢進行價格區(qū)間篩選
  3. 使用聚合統(tǒng)計每個價格區(qū)間內(nèi)的商品數(shù)量
  4. 實現(xiàn)實時篩選和動態(tài)更新

實現(xiàn)步驟

1. 商品索引創(chuàng)建

首先,我們需要創(chuàng)建一個 Elasticsearch 索引來存儲商品數(shù)據(jù)。商品數(shù)據(jù)通常包括商品名稱、描述、分類、價格等信息,其中價格字段將用于價格區(qū)間篩選。

PUT /products
{
  "mappings": {
    "properties": {
      "name": {
        "type": "text"
      },
      "description": {
        "type": "text"
      },
      "category": {
        "type": "keyword"
      },
      "price": {
        "type": "float"
      },
      "in_stock": {
        "type": "boolean"
      }
    }
  }
}

2. 插入商品數(shù)據(jù)

接下來,我們插入一些商品數(shù)據(jù)以供后續(xù)使用。

POST /products/_bulk
{ "index": { "_id": "1" } }
{ "name": "Smartphone A", "description": "A high-end smartphone", "category": "electronics", "price": 499.99, "in_stock": true }
{ "index": { "_id": "2" } }
{ "name": "Laptop B", "description": "A powerful laptop", "category": "electronics", "price": 899.99, "in_stock": true }
{ "index": { "_id": "3" } }
{ "name": "Tablet C", "description": "A mid-range tablet", "category": "electronics", "price": 299.99, "in_stock": true }
{ "index": { "_id": "4" } }
{ "name": "Headphones D", "description": "Noise-cancelling headphones", "category": "accessories", "price": 199.99, "in_stock": true }
{ "index": { "_id": "5" } }
{ "name": "Smartwatch E", "description": "A fitness-oriented smartwatch", "category": "accessories", "price": 149.99, "in_stock": false }

3. 按價格區(qū)間篩選商品

用戶在商城中可以按照價格區(qū)間來篩選商品。例如,用戶希望查找價格在 200 到 500 之間的商品。我們可以使用 range 查詢來實現(xiàn)這一需求。

價格區(qū)間篩選查詢示例:

GET /products/_search
{
  "query": {
    "range": {
      "price": {
        "gte": 200,
        "lte": 500
      }
    }
  }
}

該查詢返回價格在 200 到 500 之間的商品。用戶可以通過調(diào)整 gte(大于等于)和 lte(小于等于)參數(shù)來修改篩選的價格區(qū)間。

4. 統(tǒng)計各價格區(qū)間內(nèi)的商品數(shù)量

為了提供用戶選擇不同價格區(qū)間的選項,我們需要統(tǒng)計每個價格區(qū)間內(nèi)的商品數(shù)量??梢酝ㄟ^ histogramrange 聚合實現(xiàn)這一功能。

使用 range 聚合統(tǒng)計價格區(qū)間商品數(shù)量:

GET /products/_search
{
  "size": 0,
  "aggs": {
    "price_ranges": {
      "range": {
        "field": "price",
        "ranges": [
          { "to": 200 },            # 價格在200以下
          { "from": 200, "to": 500 }, # 價格200到500之間
          { "from": 500, "to": 1000 },# 價格500到1000之間
          { "from": 1000 }            # 價格1000以上
        ]
      }
    }
  }
}

該查詢返回每個價格區(qū)間內(nèi)的商品數(shù)量。查詢結(jié)果中的 price_ranges 聚合部分展示了每個區(qū)間內(nèi)的商品數(shù)。

5. 結(jié)果解析

查詢結(jié)果會顯示每個價格區(qū)間內(nèi)的商品數(shù)量:

{
  "aggregations": {
    "price_ranges": {
      "buckets": [
        {
          "key": "*-200.0",
          "doc_count": 2  # 價格在200以下的商品數(shù)量
        },
        {
          "key": "200.0-500.0",
          "doc_count": 2  # 價格在200到500之間的商品數(shù)量
        },
        {
          "key": "500.0-1000.0",
          "doc_count": 1  # 價格在500到1000之間的商品數(shù)量
        },
        {
          "key": "1000.0-*",
          "doc_count": 0  # 價格在1000以上的商品數(shù)量
        }
      ]
    }
  }
}

結(jié)果中 doc_count 表示每個價格區(qū)間內(nèi)的商品數(shù)量。

6. 結(jié)合篩選與統(tǒng)計

在實際應(yīng)用中,用戶希望先查看商品的價格區(qū)間分布,再選擇合適的區(qū)間進行進一步篩選。我們可以結(jié)合上述步驟,先返回各價格區(qū)間的統(tǒng)計數(shù)據(jù),再根據(jù)用戶選擇執(zhí)行相應(yīng)的 range 查詢。

例如,用戶在看到價格區(qū)間統(tǒng)計后,選擇查看 200 到 500 的商品。此時可以執(zhí)行以下查詢:

GET /products/_search
{
  "query": {
    "range": {
      "price": {
        "gte": 200,
        "lte": 500
      }
    }
  }
}

7. 實時篩選與動態(tài)更新

通過結(jié)合 Elasticsearch 的實時索引更新功能,當(dāng)商品信息(如價格或庫存狀態(tài))發(fā)生變化時,索引也會動態(tài)更新。例如,某個商品的價格調(diào)整或庫存狀態(tài)變化時,我們可以通過實時更新索引來反映這些變化。

實時更新商品信息:

假設(shè)我們要更新某個商品的價格和庫存狀態(tài):

POST /products/_update/1
{
  "doc": {
    "price": 479.99,
    "in_stock": false
  }
}

8. 小結(jié)一下

通過 Elasticsearch 的 range 查詢和聚合功能,能夠高效地實現(xiàn)在線商城的商品價格區(qū)間篩選和統(tǒng)計功能,具體實現(xiàn)包括:

  • 價格區(qū)間的篩選:用戶可以根據(jù)價格范圍篩選商品。
  • 價格區(qū)間內(nèi)商品數(shù)量的實時統(tǒng)計:系統(tǒng)可以快速統(tǒng)計每個價格區(qū)間內(nèi)的商品數(shù)量,供用戶進一步篩選。
  • 實時更新與動態(tài)調(diào)整:當(dāng)商品價格或庫存發(fā)生變化時,系統(tǒng)可以實時反映這些變化,確保數(shù)據(jù)的準確性。

通過這種方式,用戶可以更直觀、更方便地根據(jù)價格來篩選商品,提升購物體驗。

5. 地理位置搜索

業(yè)務(wù)場景:

某外賣平臺希望根據(jù)用戶的地理位置,推薦附近的餐館,并根據(jù)與用戶的距離進行排序。為了實現(xiàn)這一需求,可以利用 Elasticsearch 的地理位置查詢(geo-location query)和距離排序功能。通過地理坐標信息(經(jīng)緯度)存儲餐館的位置,并結(jié)合用戶的當(dāng)前位置進行距離計算,快速查詢附近的餐館。

解決方案:

  • 地理位置數(shù)據(jù)存儲: 將餐館的經(jīng)緯度信息存儲為 geo_point 類型,創(chuàng)建相應(yīng)的索引。
  • 地理位置查詢: 使用 Elasticsearch 的 geo_distance 查詢,根據(jù)用戶當(dāng)前的地理位置,搜索附近一定距離內(nèi)的餐館(如 5 公里內(nèi))。
  • 距離排序: 使用 geo_distancesort 功能,根據(jù)距離遠近對餐館進行排序,優(yōu)先展示距離較近的餐館。
  • 精細化篩選: 結(jié)合其他查詢條件(如評分、菜系等)進行進一步篩選,提供個性化的餐館推薦。

詳細分析: Elasticsearch 內(nèi)置的 geo_point 類型和相關(guān)的地理位置查詢功能,非常適合用于位置相關(guān)的業(yè)務(wù)場景。通過 geo_distance 查詢,平臺可以迅速篩選出與用戶距離較近的餐館,并進行距離排序,提升用戶體驗。此外,Elasticsearch 能夠輕松擴展到全球范圍內(nèi)的位置數(shù)據(jù)應(yīng)用,具有極高的靈活性和擴展性。

實現(xiàn)步驟

  1. 餐館信息的地理位置索引創(chuàng)建
  2. 插入餐館數(shù)據(jù)
  3. 用戶當(dāng)前位置的餐館搜索
  4. 根據(jù)距離排序
  5. 設(shè)置搜索范圍(限制半徑)
  6. 實時更新與擴展

1. 餐館信息的地理位置索引創(chuàng)建

首先,為了存儲餐館的地理位置,我們需要為餐館數(shù)據(jù)創(chuàng)建一個包含 geo_point 類型的索引,geo_point 用于存儲地理坐標信息(經(jīng)緯度)。

創(chuàng)建餐館索引:

PUT /restaurants
{
  "mappings": {
    "properties": {
      "name": {
        "type": "text"
      },
      "description": {
        "type": "text"
      },
      "location": {
        "type": "geo_point"  # 存儲餐館的經(jīng)緯度信息
      },
      "rating": {
        "type": "float"
      },
      "category": {
        "type": "keyword"
      }
    }
  }
}

2. 插入餐館數(shù)據(jù)

接下來,我們將插入一些帶有地理位置的餐館數(shù)據(jù)。這些數(shù)據(jù)中包含餐館的名稱、描述、評分、類別以及位置的經(jīng)緯度信息。

插入示例數(shù)據(jù):

POST /restaurants/_bulk
{ "index": { "_id": "1" } }
{ "name": "韭菜雞蛋", "description": "男人的加油站", "location": { "lat": 40.730610, "lon": -73.935242 }, "rating": 4.5, "category": "Italian" }
{ "index": { "_id": "2" } }
{ "name": "Sushi World", "description": "Authentic china sushi", "location": { "lat": 40.742610, "lon": -73.945242 }, "rating": 4.7, "category": " china" }
{ "index": { "_id": "3" } }
{ "name": "Burger Town", "description": "Best burgers in town", "location": { "lat": 40.729510, "lon": -73.914342 }, "rating": 4.3, "category": "china" }
{ "index": { "_id": "4" } }
{ "name": "Vegan Delight", "description": "Healthy and delicious vegan food", "location": { "lat": 40.715610, "lon": -73.935142 }, "rating": 4.6, "category": "china" }

在這些數(shù)據(jù)中,每個餐館的 location 字段存儲了其經(jīng)緯度信息。

3. 用戶當(dāng)前位置的餐館搜索

為了根據(jù)用戶的當(dāng)前位置搜索附近的餐館,可以使用 Elasticsearch 的 geo_distance 查詢來實現(xiàn)。假設(shè)用戶當(dāng)前位于某個位置(經(jīng)緯度:40.730610, -73.935242),我們希望查找這個位置附近的餐館。

按距離搜索附近餐館:

GET /restaurants/_search
{
  "query": {
    "geo_distance": {
      "distance": "5km",  # 搜索5公里范圍內(nèi)的餐館
      "location": {
        "lat": 40.730610,
        "lon": -73.935242
      }
    }
  }
}

這個查詢會返回距離用戶當(dāng)前位置 5 公里以內(nèi)的所有餐館。

4. 根據(jù)距離排序

為了讓用戶能夠優(yōu)先看到離自己最近的餐館,我們可以在查詢中添加基于距離的排序功能。Elasticsearch 提供了 geo_distance 排序方法,可以按距離升序排列餐館。

按距離排序的查詢:

GET /restaurants/_search
{
  "query": {
    "geo_distance": {
      "distance": "5km",
      "location": {
        "lat": 40.730610,
        "lon": -73.935242
      }
    }
  },
  "sort": [
    {
      "_geo_distance": {
        "location": {
          "lat": 40.730610,
          "lon": -73.935242
        },
        "order": "asc",  # 按距離升序排序
        "unit": "km"
      }
    }
  ]
}

這個查詢不僅返回了 5 公里范圍內(nèi)的餐館,還根據(jù)距離從近到遠進行排序。

5. 設(shè)置搜索范圍(限制半徑)

為了控制搜索的范圍,比如用戶希望只查找特定半徑范圍內(nèi)的餐館(如 3 公里以內(nèi)),我們可以通過調(diào)整 distance 參數(shù)來實現(xiàn)。

搜索 3 公里以內(nèi)的餐館:

GET /restaurants/_search
{
  "query": {
    "geo_distance": {
      "distance": "3km",  # 搜索3公里范圍內(nèi)的餐館
      "location": {
        "lat": 40.730610,
        "lon": -73.935242
      }
    }
  },
  "sort": [
    {
      "_geo_distance": {
        "location": {
          "lat": 40.730610,
          "lon": -73.935242
        },
        "order": "asc",  # 按距離排序
        "unit": "km"
      }
    }
  ]
}

6. 實時更新與擴展

餐館的位置和營業(yè)狀態(tài)可能會隨著時間發(fā)生變化,例如某家餐館關(guān)閉或新餐館開張。因此,我們需要支持餐館數(shù)據(jù)的實時更新。Elasticsearch 提供了實時索引更新功能,可以方便地更新餐館的位置信息。

實時更新餐館的地理位置:

如果某家餐館位置發(fā)生了變化(比如遷址),我們可以通過以下命令更新其位置信息:

POST /restaurants/_update/1
{
  "doc": {
    "location": {
      "lat": 40.735610,
      "lon": -73.930242  # 更新后的新位置
    }
  }
}

餐館信息實時更新后,新的查詢結(jié)果將自動反映變化。

擴展功能:根據(jù)餐館評分進行篩選

除了按距離篩選外,用戶還可能希望按餐館評分來過濾結(jié)果。我們可以將評分篩選條件添加到查詢中,確保返回的餐館不僅距離較近,還符合評分要求。

添加評分過濾的查詢:

GET /restaurants/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "geo_distance": {
            "distance": "5km",
            "location": {
              "lat": 40.730610,
              "lon": -73.935242
            }
          }
        },
        {
          "range": {
            "rating": {
              "gte": 4.5  # 篩選評分大于或等于4.5的餐館
            }
          }
        }
      ]
    }
  },
  "sort": [
    {
      "_geo_distance": {
        "location": {
          "lat": 40.730610,
          "lon": -73.935242
        },
        "order": "asc",  # 按距離排序
        "unit": "km"
      }
    }
  ]
}

這個查詢將返回距離用戶 5 公里以內(nèi)且評分不低于 4.5 分的餐館。

7. 小結(jié)一下

通過 Elasticsearch 的地理位置查詢功能,我們可以高效地實現(xiàn)外賣平臺的附近餐館搜索和排序功能,具體實現(xiàn)包括:

  • 地理位置存儲:使用 geo_point 字段存儲餐館的經(jīng)緯度信息。
  • 距離查詢:根據(jù)用戶的地理位置查找附近的餐館。
  • 按距離排序:確保用戶優(yōu)先看到距離最近的餐館。
  • 評分篩選:結(jié)合餐館評分進行篩選,提升用戶體驗。
  • 實時更新:支持餐館信息的動態(tài)更新,確保查詢結(jié)果實時準確。

通過這些功能,用戶可以方便地找到附近的優(yōu)質(zhì)餐館,提升了外賣平臺的用戶體驗和服務(wù)效率。

總結(jié)

這五個案例涵蓋了 Elasticsearch 在全文搜索、日志分析、推薦系統(tǒng)、數(shù)據(jù)聚合與篩選、地理位置搜索等典型業(yè)務(wù)場景中的應(yīng)用。通過合理的索引設(shè)計、靈活的查詢與聚合功能,Elasticsearch 能夠滿足多種復(fù)雜場景下的高效數(shù)據(jù)檢索與分析需求。

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號