原文:Algolia Blog
使用 Algolia、Mapbox 和 Twilio 在 React 中构建商店定位器——第 3 部分
本文完成了构建商店定位器的 3 部分系列。请务必查看 构建商店定位器-第 1 部分 和 构建商店定位器-第 2 部分 。
如今,电子商务购物者期望便利,希望现实世界和网络世界融合,允许他们通过任何渠道开展业务。这就是商店定位器的用途,这样用户就可以:
- 在线搜索产品,然后在店内购买
- 亲自浏览和比较产品,然后在线购买
- 在网上购物并购买产品,然后亲自提货
- 亲自退还之前购买的物品,而不是将它们寄回
尽管如此,我们发现太多的网站没有为用户提供一种优雅的方式来找到他们的“最近的商店”,无论是测试、线下购买还是在线购买。
构建商店定位器似乎很复杂,因为它需要实施地理搜索、地址/兴趣点(POI)搜索,并在地图上显示结果。为了让每个人尽可能容易地理解,我们将在 React 中创建一个商店定位器,分三次现场编码会议,并附有三篇博文,使用:
到目前为止我们所看到的
在第 1 部分 中,我们创建了所有必需的帐户,搭建了 React 项目,并在 Algolia 索引中用我们的商店索引数据集,然后通过配置其文本和业务相关性来结束。
在第 2 部分 中,我们在应用程序中添加了地理搜索功能,使用 Algolia,React InstantSearch 和 Mapbox,在连接到 Algolia 的 InstantSearch 的地图上显示结果,这要归功于connectGeoSearch高阶组件。我们还增加了“移动地图时搜索”选项,类似于你在 Airbnb 或 GetAround 上可以找到的选项。
今日关注
https://www.youtube.com/embed/rKFMPYDwOn4
视频
为了完成这个系列,我们要做以下事情:
- 使用Algolia Autocomplete和 Mapbox 地理编码 API ,添加一个自动完成下拉菜单,允许用户查找城市周围最近的商店,同时查找商店本身
- 添加短信提醒功能,通知用户产品是否可以提货,类似于宜家在线购买、店内提货(BOPIS)功能
代码可以在项目的 Github 库中找到:
添加自动完成功能
自动完成体验
在任何网站或应用程序中,自动完成都是用户旅程中至关重要的一部分,因为它能有效地引导用户。您的用户不必知道他们要查找的确切术语——他们可以键入几个字母,自动完成菜单会显示可用的搜索选项,随时可供选择。
它可能在电子商务平台、搜索引擎或地图上,在那里你不再需要知道完整的地址。
什么是 Algolia 自动完成?
Algolia Autocomplete是一个免费开源的 JavaScript 库。我们最近对它进行了彻底的重构,以交付最佳的开发人员体验,重点是用自动完成 UX 模式创建流畅的搜索体验。
通过设计,它提供了一种在多个来源中进行搜索的简单方法,这些来源可以是 Algolia 索引或外部 API。构建联合搜索体验从未如此简单。
今天,我们将为自动完成插件创建并添加两个源代码,这样你就可以在自己的代码库中重用它们:
- 第一个数据源的目标是 Algolia 索引中的商店,因此用户可以根据商店的名称或城市来搜索商店
- 第二个来源以 Mapbox 地理编码 API 为目标,因此用户可以在世界各地搜索任何可用的城市或兴趣点
在我们的项目中,我们使用自动完成来搜索位置和商店。如上所述,它可以以许多其他方式使用,例如,通过Algolia DocSearch项目增强文档网站上的搜索体验,您可以在 TailwindCSS 、 React 、或 Twilio 等网站上找到该项目。
安装 AutocompleteJS
我们先安装需要的包:
$ yarn add @algolia/autocomplete-js @algolia/autocomplete-theme-classic
让我们也安装一下@algolia/autocomplete-plugin-query-suggestions
,因为我们一会儿就要用到它。
现在,让我们创建一个<Autocomplete/>
组件。
在这里,我们不会深入细节,但是你可以在文档中找到关于这个组件的所有信息。
这里你唯一应该注意的是展开操作符……**props**
,它将允许我们在组件初始化上展开更多的道具。
组件/自动完成/Autocomplete.tsx
import React, { createElement, Fragment, useEffect, useRef } from 'react';
import { autocomplete, AutocompleteOptions } from '@algolia/autocomplete-js';
import { render } from 'react-dom';
type Optional<TObject, TKeys extends keyof TObject> = Partial<
Pick<TObject, TKeys>
> &
Omit<TObject, TKeys>;
function Autocomplete = any>(
props: Optional<
AutocompleteOptions,
'container' | 'renderer' | 'render'
>
) {
const containerRef = useRef(null);
useEffect(() => {
if (!containerRef.current) {
return undefined;
}
const search = autocomplete({
container: containerRef.current!,
renderer: { createElement, Fragment },
render({ children }, root) {
//@ts-ignore
render(children, root);
},
...props,
});
return () => {
search.destroy();
};
}, []);
return <div className={'w-full'} ref={containerRef} />;
}
export default Autocomplete;
现在,让我们把它作为一个孩子添加到我们的Header
组件中。
首先,让我们更新我们的header
组件,让它处理子组件。
Components/Header/Header . tsx
const Header: React.FC = ({ children }) => {
return (
<header className={“...''}>
<Logo className={'w-auto h-16'} />
<div className={'sm:w-full md:w-1/2'}>{children}</div>
</header>
);
};
然后,让我们将刚刚创建的<Autocomplete/>
组件添加到我们的**App.tsx file**
中的这个头部
组件/App/App.tsx
…
<div className="App flex flex-col w-screen h-screen mx-auto bg-gray-50">
<Header>
{<Autocomplete
initialState={{
query: searchState.query,
}}
placeholder={'Enter address, zip code or store name'}
openOnFocus={true}
onStateChange={onSubmit}
onSubmit={onSubmit}
onReset={onReset}
plugins={plugins}
/>}
</Header>
<div
className={
'sm:flex md:hidden w-full uppercase text-xl font-sans font-bold text-bold gap-4'
}
>
…
自动完成组件接受这些属性:
- 搜索输入的
placeholder
文本 - 如果搜索字段被聚焦,
openOnFocus={true}
将打开内容面板。 - 每当 autocomplete 中的内容发生变化时,就会触发
onStateChange={onSubmit}
- 当您按下“enter”键或选择一个结果时,会触发
onSubmit={onSubmit}
- 点击输入中的 x 按钮时会触发
onReset={onReset}
这些方法负责更新状态:
// Handle search results updates
const onSubmit = useCallback(({ state }) => {
setSearchState((searchState) => ({
...searchState,
query: state.query,
}));
}, []);
// Click on the little cross on autocomplete field
const onReset = useCallback(() => {
setSearchState((searchState) => ({
...searchState,
query: '',
}));
}, []);
Theuse callbackhook返回一个 内存化的 版本的回调,只有当其中一个依赖关系发生变化时,该版本才会发生变化。这有助于防止不必要的渲染。
添加 createquerysuggestionplugin
现在我们已经设置好了场景,是时候用数据填充自动完成组件了。您可以使用插件从许多来源获取数据:比如您自己的数据库、第三方 API 和 Algolia。Algolia 为一些数据源提供了 官方插件 ,例如,一个 Algolia 索引。
对于我们的应用程序,我们将创建两个插件:
createSuggestionsPlugin
mapboxGeocodingPlugin
我们在 src/
下新建一个文件夹,命名为 AutocompletePlugins
。
我们将创建一个名为createSuggestionsPlugin
的函数,它将是 Algolia 在@algolia/autocomplete-plugin-query-suggestions
包中提供的createQuerySuggestionsPlugin
的包装器。这样,我们可以扩展和丰富默认插件的行为,以便在我们的 Algolia 商店索引中进行搜索。
const createSuggestionsPlugin = (
searchClient: SearchClient,
indexName: string,
onSelectHandler: (query: string) => void,
onClick: (item: any) => void,
HitComponent: React.ComponentType
) => {
return createQuerySuggestionsPlugin({
searchClient,
indexName,
transformSource({ source }) {
return {
...source,
sourceId: 'AlgoliaStores',
onSelect(params) {
onSelectHandler(params.item.query);
},
templates: {
item({ item, components }: { item: any; components: any }) {
return <HitComponent item={item} onClick={onClick} components={components} />;
},
},
};
},
});
};
export { createSuggestionsPlugin };
我们的函数取:
- 一个 AlgoliaSearch 客户端(我们在博客文章 2 中创建的)
- 一个索引名(相同)
- 一个
HitComponent
,它与我们在第 2 部分中用来渲染侧边栏中每个点击的组件是同一个组件 - 一个
onClick
处理程序,用来映射当用户点击HitComponent
时哪个函数被调用 - 、、负责更新搜索输入的状态。
搜索客户端和索引名称在方法初始化中调用,其他的在插件的 transformSource
函数中使用,该函数负责在从我们的远程源(这里是 Algolia API)检索到数据后转换数据。
现在,让我们将这个插件添加到我们的Autocomplete
实例中,并检查一切是否如预期的那样工作。
// Memoize plugins to then leverage useCallback hooks
const plugins = useMemo(() => {
const querySuggestionPlugin = createSuggestionsPlugin(
searchClient,
indexName as string,
(query) => {
setSearchState((searchState) => ({
...searchState,
query: query,
}));
},
(item) => console.log(item),
SuggestionComponent
);
return [querySuggestionPlugin];
}, []);
如果我们刷新浏览器,当我们在搜索输入中键入时,我们应该会看到商店名称,这意味着我们的插件功能齐全!
创建我们自己的插件,用地图框添加兴趣点搜索
除了通过名称或城市名称搜索来找到特定的商店,用户还应该能够搜索给定的位置,然后找到该位置周围的所有商店。
最好的方法是地理编码服务。这里,我们将使用地图框位置 API 。来自最终用户的每个新搜索都会触发对此 API 的新请求,返回位置名称及其纬度和经度信息。一旦用户选择了一个结果,我们可以使用 lat/long 属性来触发针对 Algolia API 的地理搜索,并检索该位置周围的商店。
要创建你的自定义插件,你需要 实现一个给定的接口 …
在我们的例子中,为了减少对 Mapbox API 的 API 调用次数,我们使用了一种去抖动策略:
- 避免在每次击键时都发送 API 调用,但只在经过一段时间间隔后才发送,在我们的例子中是 300 毫秒。
- 基于一个。首先,它将超时设置为作为参数传递的值。如果在超时结束前再次调用该函数,那么它将清除该函数,并以相同的持续时间再次设置它。
让我们构建 Mapbox API 请求
在创建插件之前,我们想创建一段负责调用 Mapbox API 的代码。
const mapboxURL = `https://api.mapbox.com/geocoding/v5/mapbox.places/${encodeURIComponent(
query
)}.json`;
const requestParams = {
...options,
types: options.types,
country: options.country,
access_token: process.env.REACT_APP_MAPBOX_TOKEN,
};
const endpoint = [
mapboxURL,
qs.stringify(requestParams, { arrayFormat: 'comma' }),
].join('?');
注意:您可以在 Mapbox docs 中找到请求的所有可用参数。
将结果作为源插件传递给 Autocomplete
现在,我们需要将这个函数连接到我们的自动完成功能。这个想法是将结果传递给由Autocomplete
等待的响应,并将其封装在一个函数中以便重用。
const createMapboxGeocodingPlugin = (
options: IMapboxRequestParameters,
HitComponent: React.ComponentType < { item: IMapboxFeature; onClick: (item: IMapboxFeature) => void;
} > ,
onClick: (result: IMapboxFeature) => void
) => {
return {
getSources({
query
}: {
query: string
}) {
const mapboxURL = `https://api.mapbox.com/geocoding/v5/mapbox.places/${encodeURIComponent(
query
)}.json`;
const requestParams = {
...options,
types: options.types,
country: options.country,
access_token: process.env.REACT_APP_MAPBOX_TOKEN,
};
const endpoint = [
mapboxURL,
qs.stringify(requestParams, {
arrayFormat: 'comma'
}),
].join('?');
return debouncedFetch(endpoint)
.then((response: any) => response.json())
.then((data: IMapboxGeocodingResponse) => {
return [{
sourceId: 'mapboxPlugin',
getItems() {
return data.features;
},
templates: {
header() {
return 'Mapbox Places results'
},
item({
item
}: {
item: IMapboxFeature
}) {
return ( &
lt; HitComponent item = {
item
}
onClick = {
(item: IMapboxFeature) => onClick(item)
}
/>
);
},
noResults() {
return 'No results.';
},
},
}, ];
});
},
};
};
这段代码将新插件添加到我们的Autocomplete
实例中。
和以前一样,我们现在想将插件添加到我们的 Autocomplete 实例中。
const plugins = useMemo(() => {
const mapboxGeocodingPlugin = createMapboxGeocodingPlugin({
fuzzyMatch: true,
autocomplete: true,
types: ['country', 'place', 'poi'],
country: ['FR', 'BE', 'GB', 'DE', 'CH', 'IT', 'ES'],
access_token: process.env.REACT_APP_MAPBOX_TOKEN!,
},
MapboxAddressComponent,
(item) => {
setCurrentStoreCoordinates([item.geometry.coordinates[0], item.geometry.coordinates[1]])
}
);
const querySuggestionPlugin = createSuggestionsPlugin(
searchClient,
indexName as string,
(query) => {
setSearchState((searchState) => ({
...searchState,
query: query,
}));
},
(item) => setCurrentStoreCoordinates([item._geoloc.lng, item._geoloc.lat]),
SuggestionComponent
);
return [mapboxGeocodingPlugin, querySuggestionPlugin];
}, []);
注意:在我们的实现中,我们将结果限制在几个国家和几类地方,所以 MapBox API 返回最相关的结果。您可以根据需要调整这些变量。
types: ['country', 'place', 'poi'],
country: ['FR', 'BE', 'GB', 'DE', 'CH', 'IT', 'ES'],
一旦完成,我们现在可以检查我们的应用程序,看看地图框结果是否已经添加到我们的自动完成。让我们在搜索栏中键入“Marsel ”,看看我们是否能找到位于马赛-普罗旺斯机场外的商店…
而且它似乎正在工作!万岁!
将点击的信息传递给我们的即时搜索实例
既然用户可以在 Autocomplete 下拉列表中选择一个结果,我们希望将信息传递给 InstantSearch 实例,这样我们就可以:
- 显示所选商店位置及其详细信息
- 使用所选位置的纬度和经度运行 Algolia 地理搜索,检索并显示离该位置最近的商店
因为我们将使用地理位置坐标,这个方法对两个插件都有效。
创建存储当前坐标的位置
为了在自动完成中存储所选的地点/商店,让我们创建一个状态变量来存储这些数据,我们称之为currentStoreCoordinates
const [currentStoreCoordinates, setCurrentStoreCoordinates] = useState< [number, number] | null >(null);
创建处理程序
接下来,让我们创建一个方法,它根据我们单击的元素更新这个存储。从createSuggestionsPlugin
返回的条目将有一个带有 lat
和 lng
键的_geoloc
对象,它们本身来自存储在 Algolia 索引中的记录。
由createMapboxGeocodingPlugin
返回的项目将有一个几何对象,带有一个 坐标 数组。
首先,让我们创建一个方法来处理对建议的点击:
const handleClickOnSuggestion = (hit: Hit) => {
const { lat, lng } = hit._geoloc;
const coordinates: [number, number] = [lng, lat];
setCurrentStoreCoordinates(coordinates);
setCurrentStoreName(hit.name)
setIsOpen(true)
};
将它作为onClick
处理程序添加到querySuggestionPlugin
实例中。
现在,让我们更新地图框插件的onClick
处理程序:
(item) => setCurrentStoreCoordinates([item.geometry.coordinates[0], item.geometry.coordinates[1]])
将纬度和经度传递给即时搜索和我们的组件
在第 2 部分,我们配置了我们的<InstantSearch/>
包装器:
<Configure aroundLatLngViaIP={true} />
现在,我们将利用aroundLatLng
属性来触发基于纬度和经度参数的地理搜索。
&lft;Configure
aroundLatLngViaIP={!currentStoreCoordinates?.length}
aroundLatLng={!!currentStoreCoordinates?.length ? '' : currentStoreCoordinates?.join(',')} />
这一次,我们将 aroundLatLngViaIP
设置为真或假,这取决于 currentStoreCoordinates
的状态。如果currentStoreCoordinates
为空,我们将 aroundLatLngViaIP
设置为 true 并基于用户的 IP 地址执行地理搜索,否则我们将坐标作为字符串传递给 aroundLatLng
以使用这些坐标执行地理搜索!仅此而已!
现在,让我们将 currentStore={currentStoreCoordinates}
添加到我们的StoreComponent
中,并添加到地图中以突出显示所选的商店。
至此,我们已经完成了自动完成部分!我们现在有一个全功能的商店定位器,它允许用户找到商店:
- 他们当前的位置附近,由于他们的 IP 地址和从页面加载
- 基于当前的
viewport
,每次地图移动或放大或缩小时都会更新 - 通过自动完成功能使用关键字搜索,根据商店名称或城市名称搜索商店
- 通过自动完成功能使用关键字搜索,搜索一个地点名称并查找附近的所有商店
添加 Twilio 短信体验
什么是 Twilio?
Twilio 是领先的 CPaaS(通信平台即服务)公司,由 Jeff Lawson 于 2008 年在旧金山创立。像 Deliveroo、优步、亚马逊 GetAround 这样的公司都是客户,所以你很可能在不知情的情况下使用了 Twilio 的服务。
他们为许多通信渠道提供服务,从短信、语音通话和推送通知,一直到完全可配置的企业呼叫中心。他们还通过收购 SendGrid 和 Segment 扩展到电子邮件和客户分析领域。
在这个项目中,我们将使用 SMS,原因有三:
- BOPIS 功能(在线购买,店内提货)通过短信接收店铺位置
- 缺货通知,因此只要产品有货,您就会收到一条短信
- 营销通知
创建您的帐户
让我们创建自己的账户,并获取账户 SID 和认证令牌。
到Twilio.com点击报名。输入创建免费 Twilio 帐户所需的信息。
一旦你登录,你将登陆“控制台”,在那里你会找到两条关键信息:你的 Twilio 账户 SID 和 Auth Token。
我们将使用他们的无服务器功能( 功能 ),而不是我们自己的后端。如果有一天你需要从你的服务器发送 API 请求到 Twilio,你知道在哪里可以找到它!
获得您的第一个电话号码并创建您的第一个短信请求
要发送短信(尤其是在美国和加拿大),您需要购买一个专用电话号码,对于其他国家,您可以在 Twilio 网站上查看 Twilio 的监管指南
如果您想在法国发送手机短信,可以跳过这一步,因为购买一个法国电话号码很麻烦。这不是 Twilio 的错,而是 ARCEP ( )规则的后果。 你可以去“创建你的第一个短信服务”。对于法国,我们将使用阿尔法发送器。,它将您的品牌标识为发送者—这是法国法律的要求。
如需购买电话号码,请前往左侧栏,进入 电话号码>管理>购买电话号码
接下来,选择您想要购买电话号码的国家,然后点击购买。
确认后,您现在自豪地拥有了一个新的电话号码!
创建您的第一个信息服务
设置新的电话号码(如果您在法国,则为 Alpha 发送者)后,在搜索栏中输入“信息服务”,然后输入“信息服务”(您可以体验另一种自动完成功能)。
- 从建议列表中选择 创建消息服务
- 将您的新消息服务命名为,例如, 存储定位器 并选择 通知我的用户 。
- 接下来,点击 添加发件人 ,然后点击 阿尔法发件人 ,输入您的企业名称。
- 如果您购买了电话号码,您可以从列表中选择您的电话号码。
最后,您的消息服务应该类似于下面的截图
现在,进入 属性 ,复制你的消息服务 SID。
创建发送短信的功能
使用消息 SID,导航到功能(您可以搜索它或在 浏览产品 >开发人员工具>功能 ) 下找到它)。
再次创建一个服务,给它命名,点击 下一个 。浏览器中将打开一个 IDE。
点击 +添加 > 新建功能 创建一个新功能,命名为“下单”。将的可见性设置为“public ”,因为我们需要在 Twilio 之外调用它。
现在,转到 依赖项 并添加 date-fns
包来处理日期。
在模块字段中,键入 date-fns
,然后单击添加。
现在,让我们添加负责发送消息的代码:
// Let's require date-fns functions, we'll use them to manipulate dates.
const parse = require('date-fns/parse');
const format = require('date-fns/format');
exports.handler = async function(context, event, callback) {
// Let's fix CORS, this is required because we are calling this function from outside the twil.io domain
const response = new Twilio.Response();
response.appendHeader('Access-Control-Allow-Origin', 'https://localhost:3000'); // Change this by you domain
response.appendHeader('Access-Control-Allow-Methods', 'GET, OPTIONS, PUT, POST, DELETE');
response.appendHeader('Access-Control-Allow-Headers', 'Content-Type');
// Now we're grabbing data from the request payload
const {
store,
customer,
time,
phoneNumber
} = event;
// We're using format to display a nice date in the SMS
const formattedDate = format(parse(time, 'dd-MM-yyyy::HH:mm', new Date()), "eee, d LLLL yyyy 'at' kk:mm");
// Let's write the message
const message = `Hey ${customer}. Your order will be ready to pick-up at ${store} on ${formattedDate}. Thanks for beeing a Spencer & William Customer`;
// Time to hit the send button !
const client = context.getTwilioClient();
await client.messages.create({
body: message,
messagingServiceSid: 'MG9378a33499ec5b0201374e6e8b0adb67',
to: phoneNumber
})
// Don't forget the callback otherwise you'd raise an error as the function will keep running
return callback(null, response)
};
仅此而已!点击 保存****部署所有 ,大概需要 2 分钟左右,你的函数名旁边会出现一个绿色的复选标记。现在可以从外部使用我们的 Twilio 凭证调用 Twilio API 来使用这个函数。
注意:y 你可以使用一个 API explorer 来测试它,比如 Postman 或者 Paw.cloud(在 macOS 上)
从你的代码中调用下单函数
您将在组件/ 目录中找到表单组件。当您从列表或地图上选择商店时,它会出现在屏幕上。
它有三个字段:客户名称、提货日期和电话号码。现在,我们需要在单击“Place Order”按钮时执行请求。
我们将使用 axios 来执行请求,但您也可以使用自己喜欢的库。
yarn add axios
让我们填充 sendRequest()
方法:
async sendRequest() {
const {
customer,
time,
phoneNumber,
phoneCountry
} = this.state
const {
store
} = this.props
this.setState({
isLoading: true
});
await axios.post(process.env.REACT_APP_TWILIO_FUNCTION_URL as string, {
store,
customer,
time,
phoneNumber: parsePhoneNumber(phoneNumber, phoneCountry).number
});
this.setState({
isLoading: false
});
}
仅此而已,你的应用程序现在将向你的客户发送短信。这是我们为这个应用程序编写的最后几行代码,现在是时候将它部署到智能云上了!
在智能云上部署您的应用
最后一步,我们将把商店定位器部署到 智能云 托管平台,这样你就可以向你的朋友和同事展示你新开发的应用。
转到您的智能云仪表盘,点击 +创建 / 一个应用
选择 创建新应用 :
选择应用类型: 节点 。点击 继续下一步
为您的应用命名,并选择您的数据中心。
最后,选择 配置提供者 。这将替换我们的 .local.env 文件,并在构建时在我们的应用程序中注入变量。然后点击 下一个 并给你的配置提供者起一个名字。
在下一个屏幕上,点击 专家 并复制/粘贴您的.local.env
文件。
将这两行添加到环境变量中,以使用 yarn 并在安装完依赖项后构建项目:
CC_POST_BUILD_HOOK="yarn build"
NODE_BUILD_TOOL="yarn"
点击绿色按钮两次,点击左侧菜单中的节点机。按照屏幕上方的步骤,将 Clever 的 git URL 添加到您的项目中,并推送它!使用 “域名”下的网址,3 到 4 分钟后就可以使用了。
包装
总结一下我们本周的成就:
- 我们增加了一个自动完成下拉菜单,补充了现有的应用程序体验,允许用户按名称或位置名称搜索商店,这样他们就可以找到该位置附近最近的商店。
- 我们增加了 Twilio 支持,可以向客户发送短信。
- 我们已经在智能云上部署了我们的应用。🎊
这就是我们关于使用 Algolia、Mapbox 和 Twilio 构建商店定位器的系列报道。但是你还可以添加更多的功能:
- 利用商店定位器提供 BOPIS 特色
- 使用 Twilio SendGrid 发送电子邮件而不是短信
- 使用 Twilio 段跟踪和更新点击次数最多的商店
- 使用 Stripe APIs 添加支付选项
我希望你喜欢这个系列!套用一位我非常钦佩的首席执行官兼开发人员的话:我迫不及待地想看看你会开发什么。
为所有人建立一个开源索引
原文:https://www.algolia.com/blog/engineering/building-an-open-source-index-for-all/
在阿尔戈利亚,我们本质上是一群业余爱好者。我们不仅仅是为财富 500 强建造,我们也是为修补者建造。这就是为什么我们在 DocSearch 这样的工具上投入了如此多的精力——我们喜欢任何在像 Astro 、家庭助手和 SASS 这样的工具背后有回报、开源软件思维的人,就像 React 、 Twilio 和 Discord 一样。
我们一直在酝酿一个想法,特别是关于回馈发现驱动的开发人员,他们从 Algolia 开始就一直在试验:开放索引。互联网上已经存在许多开放数据集,但它们的质量并不为人所知。即使是高质量的也不总是我们需要的形式,而且没有什么激励让制作者来帮助我们,因为他们通常不会因为维护他们的数据集而得到报酬。这似乎是我们在 Algolia 要解决的完美问题,所以我们中的一些人一直在努力设计我们的第一个开放式指数。让我们在本文中浏览一下这个过程;它是相当概念性的,所以对于那些自己艰难地完成偶尔复杂的索引创建过程的人来说,它仍然是一个有用的指南。
不过,在我们开始之前,我们需要谈一谈可组合性。
可组合性——小事情的大词
可组合性是一个系统的各个部分在独立和不同组合中有用程度的主观度量。
以一首歌为例,制作人不仅要考虑歌手是否唱得好,吉他是否走调,或者鼓手是否合拍,还要考虑这些曲目配合得如何。在歌曲的不同点,这些曲目的不同组合将同时播放,因此它们需要独立工作,并在不同的环境中工作。我们的指数也是如此。
当您为公司创建一个应用程序时,不太可能只有一个应用程序一次性使用给定记录的所有数据—大型应用程序通常会为不同的页面和视图请求数十种不同的数据组合。但对于我们的索引来说,这种影响更加突出:我们不知道哪些数据将被谁使用,所以我们需要确保所有这些数据都是高质量的,彼此独立,但也可以很容易地组合成高质量的超级结构,就像音乐制作人希望每张唱片独立工作,同时也能在任何配置下整齐地融入整个轨道一样。
让我们试着做一个食谱,特别是厨师约翰在 Allrecipes 上提供的这道看起来很美味的希腊柠檬鸡肉和土豆食谱。让我们看看是否可以从 Allrecipes 的食谱模型开始,然后将其改进为更加具体和可组合的。就目前的情况来看,配方模型似乎具有这样的结构:
title
(字符串)description
(字符串)times
(物体阵列)name
(一对预定义选项的字符串)number
(数字)unit
(一对预定义选项的字符串)
ingredients
(对象数组)amount
(数字)unit
(一对预定义选项的字符串)ingredient_name
(字符串)is_header
(布尔型)
directions
(对象数组)step_content
(字符串)is_header
(布尔型)
notes
(对象数组)title
(字符串)note
(字符串)
servings
(数字)yield
(字符串)public
(布尔型)media
(字符串数组,验证为 URL)author
(字符串)
这已经是相当全面了!他们可以用它做很多事情,比如计算完成一份食谱需要的总时间,营养信息,以及不同份量的配料量。不过,我们可能会提出一些建议:
- Allrecipes 使用配料行在列表中的配料之间创建一种标题。我们选择的食谱没有使用这个功能(它看起来不像许多人做的,但是你可以设想这样一种情况,你在指导读者如何先制作两个独立的项目,然后再将它们组合起来(像馅饼或芝士蛋糕的外皮和馅料)。这绝对是一个有用的特性,更多的食谱作者应该利用它,但是没有在食谱的结构中将其形式化,而是选择使用配料行作为“标题”,只是在视觉上而不是从根本上区分配料组,这感觉有点奇怪。我可能会建议创建一个名为
ingredient_groups
的高级数组,其中至少包含一个带有title
(即标题文本)的对象和一个名为ingredients
的数组。只有当需要描述多个组时,才会显示该标题,并且该内部数组将包含该标题下特定部分的所有成分。然后我们可以去掉那个讨厌的is_header
布尔值,否则他们需要将部分标题渲染得与其他成分不同。同样的变化也适用于说明书,说明书同样使用标题线来划分章节。 - 说到配料,Allrecipes 实际上并不要求提交者将配料分成数量、单位和项目名称——他们只是要求你输入一个简单的字符串,就像这样:
我怀疑他们在内部将它存储为三部分,因为他们用数字和单位进行数学计算(你可以让它将 4 份食谱转换为 3 份,这通常需要改变单位)。所以这已经是可组合的了,但是我们可以做得更好。如果我们分别要求所有这三个组件,我们可以用它做一些有趣的事情。例如,我们可以有一个可接受成分的列表(如果他们的成分在我们的数据库中不存在,用户可以添加),让用户选择成分,而不是以字符串的形式输入。在生产环境中,我们的数据库中会有这些成分,这里只通过 UUID 引用。每种配料都将在它们自己的数据库记录中存储几个表单选项——例如,我将“黄油”称为一种配料,而“冷冻的”、“软化的”、“融化的”、“切片的”和“切块的”作为一种“黄油”配料的可选表单。配料也可以有其偏好的单位类别(面粉应该总是按重量或干体积来测量,但决不能按长度来测量),这可以可选地是定制的(像“黄油棒”)或者甚至是空的(你不需要一个特殊的“土豆”单位)。然后,这个特定配方中的配料表单将存储在我们的配方索引中的配料对象中,旁边是一个与这个特定配料的可用单位相匹配的单位字符串和一个经过验证的配料数值。我们可能会在将来完全发布这个系统(如果你在数据库或 CMS 公司,你知道在哪里可以找到我们),但是现在,我们只是将这些信息放在一个 JSON 对象中,这个对象表示索引中食谱中使用的所有配料。现在对我们来说,这将是更多的手工工作,但是每个使用索引的人都不必担心启动他们自己的数据库实例。
这是我们新的recipes
指数形状:
title
(字符串)description
(字符串)times
(对象数组)name
(一对预定义选项的字符串)number
(数字)unit
(一对预定义选项的字符串)
ingredient_groups
(对象数组)title
(字符串)ingredients
(对象数组)ingredient
(UUID,匹配ingredients
JSON 中的一种成分)forms
(字符串数组,匹配成分的forms
)amount
(数量)unit
(字符串,匹配该成分的unit_categories
之一)
direction_groups
(对象数组)title
(字符串)directions
(字符串数组)
notes
(对象数组)title
(字符串)note
(字符串)
servings
(数字)yield
(字符串)public
(布尔型)media
(字符串数组,验证为 URL)author
(字符串)
然后是我们的新成分 JSON ,其中每个记录都与这个形状匹配:
uuid
(UUID)name
(字符串)plural_name
(字符串)unit_categories
(字符串数组)custom_unit
(字符串数组,除非unit_category
包含“自定义”,否则不存在)forms
(字符串数组)
单元列表是一个足够合理的对象,也可以作为 JSON 保存在内存中,所以这里有一个小的实用 JavaScript 程序来跟踪这些单元并在它们之间轻松转换,它是由我的同事 Jaden 编写的。
这是我们要上传到 Algolia 的食谱 JSON。为了获得最佳结果,你通常会希望只存储你将在 Algolia 中搜索的内容,然后将其余内容存储在一个快速数据库中,如 Fauna ,但是因为这是一个测试数据集,我们将所有内容都进行了搜索,这就是为什么 JSON 对于一个食谱来说如此之大。如果你想把你的个人食谱添加到这个数据集中,我们很乐意把它们包括进来!只需在这里为每个食谱填写谷歌表单,我们会筛选并手动添加最好的。
您一直在等待的部分:由于这个索引是开放的并且在不断增长,所以在加载生产就绪数据之前,对您来说试验 Algolia 和测试您自己的集成将是非常有用的!如果你想试一试,以下是凭证:
*只读公钥:*ea 2f 27 cfed 9 ddeed 93 f 7532424 a 64480
申请 ID: OKF83BFQS4
*索引名称:*食谱
我们很高兴看到你用什么来填充这个数据集(同样, Google 表单在这里可用)!我们将利用我们团队中数百名 Algolia 开发者的配方来改进它。如果你对数据集本身做了一些有趣的事情,一定要在 Twitter 上给我们喊一声!
为客户和员工构建企业搜索
新冠肺炎加速了全球数字化转型。一切都转移到了网上,从礼品购物到杂货店购物,再到流媒体消费。客户期望轻松、顺畅、个性化的数字体验。简而言之,企业搜索。
对于消费者来说,这种转变不仅仅发生在网上:员工正在寻找内部网和知识管理工具来找到他们需要的信息,以便在世界各地远程工作和协作时保持高效。再次:企业搜索。
我们为外部公共用户(客户)和内部用户(员工和业务团队)构建企业搜索产品。高效的搜索引擎能让您的客户和员工更快地访问您最重要的信息。它引发了更多的消费、参与和协作,同时极大地提高了效率。
搜索是一个无名英雄,一个强大的应用程序,它统一了您的数据和元数据,使它们更容易被发现、消化和操作。数据可以是任何格式—产品、视频、电子表格、文档、文章、博客、客户信息、内部网财务报告—或许多其他市场或工作相关类型的内容。好的搜索技术可以与现有的内部和第三方工具和数据集集成。
什么是企业搜索?本文回答了这个问题,然后提供了如何优化您的企业搜索软件功能的路线图,从捕获分析到获得业务洞察力,以及构建与您的后台系统集成的强大内部搜索体验。
构建企业搜索解决方案的路线图
企业通常遵循基于需求的搜索策略。他们首先升级在线搜索,以提高客户参与度和转化率。只有这样,领先的企业才能重组并开发一个强大的基于搜索的框架,与他们的后台系统、数据和工作流集成,使业务团队能够以最佳方式运作。
让我们概述一下 Algolia 提供的 3 步路线图。您可以:
- 利用我们的员工和产品提供的专业知识和灵活性,构建成功的在线搜索功能。我们的软件完全可定制,以满足任何行业和独特的业务需求。
- 将内部搜索与多用途索引框架和基于云的托管服务相集成,旨在支持后台系统、不同的数据源、员工任务、业务工作流和生产力工具。
- 收集分析以跟踪使用情况,然后将这些信息输入数据库,用于报告和人工智能驱动的商业见解、建议、个性化信息以及对所有搜索平台的 A/B 测试。
创建企业搜索的三大需求和九大行动
1。需要有竞争力的、丰富的在线企业搜索体验
Algolia 的所有客户都需要出色的在线搜索。他们需要实现更好的数字客户体验,从而提高参与度和转化率。他们需要在资源较少的情况下快速启动并运行。他们需要搜索专业知识来构建在线体验,从而提高投资回报率。
- 世界领先的商业体重管理项目 WW (Weight Watchers) 允许其成员追踪他们在什么时候吃了什么。快速准确地跟踪饮食习惯是其成员成功的核心。然而,该组织的用户生成数据量迅速从几十万个数据点增长到几亿个数据点。尽管信息量如此巨大, Algolia 的 WW 搜索平台的运行速度比 WW 之前的搜索解决方案快 100 倍,90%的搜索查询在不到 14 毫秒的时间内被返回。此外,Algolia 会在 WW 会员实时搜索时刷新搜索结果。
- 此外,Algolia 支持的不仅仅是 WW 的数字搜索体验。WW 使用我们的技术为其 Recipe Explorer 和 CRM 搜索提供支持,并不断研究利用 Algolia 产品支持其创新的新方法。
行动 1:在网上建立有竞争力的搜索
首先决定你的搜索界面应该在哪里,应该是什么样子。它是出现在你主页上的第一个项目吗?隐藏在二级页面上的补充工具?此外,考虑一下你希望搜索结果如何显示:标题和链接可能没问题,但你的用户可能会想要更多,这取决于你所在的行业,例如,图片、简短摘要或价格。
如果你的业务团队在构建网络搜索工具方面没有很多经验,你可以和我们合作。我们提供了一个快速响应的企业搜索引擎,具有高级功能,如推荐、个性化,以及许多管理您的内容和微调您的相关性的方法,无论是手动还是使用人工智能的自动方式。您还将获得开箱即用、完全可定制的前端 UI 工具和库,帮助您构建丰富的搜索和发现体验,与您的业务用例及品牌无缝集成。
行动 2:通过分析和 A/B 测试向客户学习
随着时间的推移,我们的分析引擎会提高搜索的相关性和可用性。分析可以帮助你追踪人们在寻找什么,他们点击和转化了什么,以及哪些搜索是最有效的。
您还可以利用分析来推动内容创作和扩大产品种类。搜索分析告诉你你的用户想要什么样的产品和内容。使用这些数据来帮助您创建已经拥有潜在受众的新内容和产品。
行动 3:不断迭代以改进您的企业搜索功能
对不断变化的市场和客户需求做出反应。这是什么意思?在快速交付第一版网站搜索解决方案以解决最紧迫的问题后,通过提高相关性进行迭代和优化,添加人工智能自动化的相关性工具,如动态重新排序和动态同义词建议,并使用更高级的功能升级您的前端 UI,如销售、个性化、分面和自动完成。这些都是用户期待的领先企业搜索体验的属性。
2。对灵活高效的内部企业搜索的需求
一个企业的数据通常是大量的和无组织的。信息丢失或不为人知。系统已经过时,难以适应。员工生产力、协作和沟通都不理想。任务和工作流效率低下。
- 领先的时装零售商迪奥开始使用 Algolia 作为其电子商务网站。然后,其管理层决定使用 Algolia 来管理其店内应用程序。他们创建了一个应用程序,使用连接器与 Algolia 的 API 集成。商店员工现在可以根据购物者的偏好(例如,面料、颜色、类型)搜索商品。他们可以看到特定商店有什么商品,也可以很容易地从附近的商店发货,避免顾客失望。
- 《纽约时报》和其他新闻和金融服务利用 Algolia 的 API改变了他们的编辑管理流程以跟上快速发展的新闻周期。Algolia 使编辑能够搜索、选择和发布最热门的新闻文章。Algolia 最终将被用来发现这些趋势,并自动提出建议。
行动 1:授权给你的员工
您希望从工程师到业务经理的每个人都能够构建、配置和轻松支持运行您组织的在线服务和内部流程。您希望提高工作流效率和员工生产率,并使用一个现代化的、适应性强的 API 和搜索引擎框架来连接人员、软件和数据,从而管理内部内容。
行动 2:用内部搜索工具统一数据,并将正确的内容呈现给正确的用户
提供系统范围的搜索和索引用户体验,统一您的后端堆栈,揭示系统之间的关键数据和信息关系。您可以通过索引来自多个来源的数据或内容并将其发送到我们的托管服务来做到这一点。信息可以是任何结构化和非结构化的数据格式。我们的搜索引擎为搜索目的构建它。此外,您可以通过在一个多方面的“联合搜索”界面中组合不同的数据源来联合您的搜索。
动作 3:将企业搜索功能与您现有的应用程序集成
将定制的搜索连接器和功能与您现有的第三方应用程序集成,如 Salesforce、SAP、Confluence、Google Docs、SharePoint、吉拉和其他内容管理系统(CMS)、企业资源规划(ERP)工具、客户应用程序、存储库、爬虫、微软、亚马逊网络服务(AWS)、社交媒体和业务平台。
3。企业搜索对有组织、有洞察力的知识管理的需求
企业往往拥有大量的信息,但也有太多的数据需要合理管理。没有简单的方法来整理和查看不同数据点或内容片段之间的关系。很难知道什么是重要的,什么是值得发现的。相关内容未得到充分利用。
- Pentair 是一家 B2B 组织,是国际水资源和水处理行业的重要参与者。实施 Algolia 后,他们立即发现客户在线参与度大幅增长。为了衡量这一点,他们将 Algolia 的分析与他们的 Adobe 电子商务平台集成在一起,创建了一个从前到后的分析数据馈送,表明搜索后产品浏览量增加了 500%。随着分析的到位,他们也开始利用个性化,将其受众分为住宅和商业等类别。最后,分析使他们能够执行 A/B 测试,并受益于 Algolia 的人工智能优化相关性。
行动 1:捕捉分析,并提供人工智能和人工智能模型
捕捉使用分析,为强大的人工智能提供机器学习数据集和模型,以便个性化、预测、推荐和持续改进 A/B 测试的结果。
行动 2:构建有洞察力和灵活的搜索报告
创建深度相关的搜索和报告界面,专业地可视化您的分析和人工智能驱动的业务见解和搜索应用程序。
动作 3:外包你的 AI 和 ML 企业搜索能力
不用建立内部机器学习搜索团队——这非常复杂,可能需要数年时间并消耗大量资源——你可以通过 Algolia 的 insights 引擎获得现成的人工智能和人工智能能力。
对于企业搜索来说:旅途与目的地至关重要
企业搜索始于为您的客户创造强大的搜索和发现体验。但是一个托管搜索 API 超越了这种在线体验:它可以改变运行你的业务的内部流程和系统。
这里有一种方式来看待它:每个搜索用户界面都有能力显示一组或多组结果。如果处理得当,这是一项伟大的成就。但是,如果你更进一步,开始将所有的搜索界面组合在一个统一的界面中,你就可以创建一个整合的(联合的)搜索体验。这将您的所有数据和可用项目统一在一个屋檐下。您最终会得到一组可组合的搜索引擎 API,在这些 API 中,您的数据可以在世界上的任何地方托管和访问,从而为您的所有客户和员工提供服务。
旅程:开箱即用
- 用于构建简单或复杂应用程序的可组合 API 和前端工具。完全可配置和定制,适用于任何使用案例或行业。
- 成本更低、资源更少、对专业技术需求更少的快速上线解决方案。
- 现收现付:企业搜索不一定意味着高成本。您只需为您使用的资源付费。
目的地:你能建造什么
- 快速和相关的在线搜索,以满足任何行业和独特的业务需求。因此,您可以获得更多的客户参与和更多的转化。
- 内部搜索构建在多用途托管索引框架之上。您可以利用这一点,通过简化对相关信息的访问来提高效率。
- 一个分析数据库,提供人工智能驱动的在线搜索功能和各种商业见解。
构建身临其境的购物体验:通过 Adobe Experience Manager 和任何商务平台使用 Algolia 搜索
将 Algolia 添加到 AEM 商务体验中,使零售商能够充分利用他们的内容,丰富购买体验,并在向购物者展示产品时更加个性化,从而为他们的在线商店带来更高的转化率和收入。
在这篇博客中,我们将讨论为什么搜索和发现对购物体验如此重要,以及如何以最快的速度实现这一点。
打造沉浸式购物体验
最好的在线零售商努力创造身临其境的购物体验使用内容和丰富的资产来补充他们试图销售的产品。我们所说的身临其境是什么意思?
- 漂亮的登陆页面
- 引导顾客在购买过程中导航
- 向顾客介绍产品的信息
- 具有动态方面的联合随键入搜索结果
- 个性化推荐
- 动态横幅&情境化促销
- 通过对话获得更多关于购物者意向的信息
许多领先的零售商选择使用像 Adobe Experience Manager 这样的 CMS 作为前端来创建这些身临其境的体验。通过 AEM,零售商可以构建网站,管理他们的全球网站,并引入资产来丰富商业体验。
布雷维尔是一个很好的在线零售商的例子,它将内容和产品结合起来,创造了身临其境的体验。作为体验的一部分,他们对搜索和发现进行了深思熟虑,甚至通过互动问答创造了引导销售体验,帮助购物者更好地了解他们的偏好,并发现他们最有可能喜欢的布雷维尔产品。
访问他们的引导体验 这里 亲自去看看,说不定还能找到你的完美咖啡机☕️或榨汁机🍎!
Breville’s eCommerce site
Breville quiz to find the perfect juicer
Algolia、Adobe Experience Manager 和 CIF
搜索和发现是创建沉浸式电子商务体验的关键部分 ,这就是 Algolia 和 Adobe 合作在 Adobe Experience Manager 上提供搜索的原因。Algolia 的搜索引擎允许零售商在他们的网站上提供闪电般的快速搜索。出版商获得了工具,可以根据相关性、业务指标和机器学习模型的洞察力来控制内容&产品。通过 Algolia A/B 测试,他们可以进行实验并衡量改进,以了解更好的搜索能力如何影响他们的底线。最终,Algolia 将科学与艺术相结合,帮助在 AEM 上创造更多引人入胜的体验。
Adobe Experience Manager 提供了一个商业集成框架,称为 商业集成框架 (CIF) 以加速 AEM 上店面的开发。通过安装和配置 CIF,作者可以轻松地将产品和类别数据从 Adobe Commerce 或任何第三方电子商务平台引入 AEM,并构建核心的前端商店体验。Algolia 更进一步,提供了一种在零售商的电子商务数据和 AEM 的丰富内容中构建搜索和发现体验的方式。
Algolia 提供跨商业和内容联盟的 AEM 组件,包括:
- 带自动完成功能的全局搜索
- 联合搜索&使用即时搜索浏览
- 内容推荐
- 产品推荐(可利用 CIF 引用产品 id)
- 类别页面(可以利用 CIF 引用类别 id)
AEM’s WKND demo with Algolia search
如何入门
强大的搜索和发现改变了游戏规则,零售商希望尽快启动并运行它,这样他们就可以开始试验、迭代和衡量结果。在这里,我们分享在 Adobe Experience Manager 中将搜索添加到电子商务体验中的 4 个步骤——以最快的方式实现价值。
1。索引网站上应该可以发现的所有产品和内容
零售商可能会选择一些不同的来源,包括 PIM、电子商务引擎、他们的常见问题服务平台以及他们管理内容的 CMS。Algolia 提供了许多 API 客户端来索引和保持信息与这些系统的同步。对于少数热门平台如Adobe CommerceAdobe Experience Managersales force Commerce CloudCommerce toolsShopify我们
2。使用元数据、业务排名标准和 AI 配置搜索和发现
**配置逻辑发生在 Algolia 仪表板中的 智能地对类别页面、搜索结果进行排名,并提供正确的推荐 。许多用户会在仪表板中运行实验和 A/B 测试,以查看哪些杠杆可以带来最高的转化率。最终,这里的目标是匹配购物者的意图,并通过更好的搜索和发现来增加收入。
在这里,零售商可以管理如下内容:
- 相关性调谐
- 自定义排名
- 动态重新排名
- 个性化
- 商品销售
- 查询规则
- 同义词
- A/B 测试
- 分析学
- 还有更多……
例如,零售商可以添加一个横幅,每当购物者搜索“销售”一词时就会出现。他们会在 Algolia 创建一个“如果这个,那么那个”规则,并绘制一个横幅。该横幅可以在 Adobe Experience Manager 中创建为片段,并使用发布 URL 进行引用。
Algolia query rule
Banner powered by Algolia query rule
3。将 Algolia 添加到前端
在 Adobe Experience Manager 中构建 UI 可以使用两种方法:(1)使用在 Javascript、React、Vue 等中可用的 Algolia 的 UI 库 ,或者(2)使用 Algolia 的 AEM UI 组件加速器 。要创建联合搜索,只需将每个索引添加到 Algolia 组件中,使用 Algolia 中定义的索引名称。在全球搜索栏中,零售商可以为产品添加一个索引,为文章添加另一个索引,从而创建丰富的商务+内容体验。
对于使用商务集成框架的用户,我们提供 Algolia CIF 组件选项,可轻松连接到 Adobe Commerce endpoint(或另一个商务引擎),并根据通过 CIF 定义的类别 id 和产品 id 动态生成类别页面和产品详细信息页面。然后,这些分类页面可以使用 Algolia 中设置的逻辑和人工智能显示所有产品。
AEM author dialogue for Algolia category page
产品详情页面可包含由 Algolia 提供的推荐。与产品详细信息页面一样,这些页面将根据购物者正在查看的产品动态呈现推荐。这些推荐可以从产品索引中提取,甚至可以作为相关内容从另一个索引中共享。
Algolia component for recommended products on PDP
Recommended ‘Related Products’ configuration
4。跟踪分析和机器学习的结果
我们的事件可以通过 AEM 组件进行跟踪。通过组件,选择“跟踪 Algolia 事件”框,将出现第二个选项卡来配置“点击”或“转换”事件。另一种选择是通过类似Adobe Launch的标签管理器发送 Algolia 事件。跟踪结果将使 Algolia 引擎变得更加智能,了解如何为给定用户个性化结果,提供产品推荐,并根据人群动态地重新排列项目。
Click and conversion events tracking through the Recommend AEM component
这些部分将搜索连接到您的商务平台和内容管理系统,并创建丰富的购物体验,引导购物者,展示最相关的商品,并最终推动更多的转化。
想了解更多或了解如何尝试 Algolia?
请致电adobe-algolia-solutions@algolia.com联系我们,获取我们的 AEM 加速器以及如何开始将 Algolia 构建到您的 AEM 解决方案和商务集成框架中的指导!我们很高兴与您讨论最佳实践、权衡,并了解什么最适合您!
查看我们“Adobe x Algolia 集成”系列的其余部分,包括我们的最后一部分:Adobe Experience Manager 上的 Algolia Powered 搜索组件 。**
大规模构建实时分析 API
原文:https://www.algolia.com/blog/engineering/building-real-time-analytics-apis/
我们最近重新设计了我们的分析 API,以便为我们的客户提供每天数十亿次搜索查询的近实时分析。我们是这样做的。
我们的分析系统从一开始就是红色的
我们的第一个分析系统是从一个小项目开始的。它由一批批压缩日志文件组成,这些文件从我们所有的搜索服务器发送到一个中央存储服务,然后被推送到一个 Elasticsearch 集群,我们从那里提供分析查询。
自然,这个系统有其局限性。首先,我们需要为新的点击分析功能铺平道路,我们希望利用一个更加关系化的模型。在 Elasticsearch 中,文档是独立的,这样做太麻烦了。
其次,由于要跨许多节点处理数百亿条记录,管理这样的集群变成了一项全职工作。
我们的搜索分析为我们的客户提供了关于他们的搜索如何被使用的见解。这些见解很容易变大。从搜索数量或独立用户数量等概述,到诸如“用户最感兴趣的类别是什么?”等可操作的业务洞察,不一而足或者“哪些查询没有返回结果?”。所有这些都可以在特定的时间范围内完成,在某些情况下,时间范围可能非常大。
以下是我们在从头开始重建我们的分析时所做的技术选择的解释,以及我们使用的一些设计原则的概述。
选择用于分析的数据存储
我们需要满足的最高要求是:
- 每天处理数十亿个事件的接收、存储和删除。
- 对于大多数查询,无论请求的时间范围如何,都可以在几秒钟内返回结果。
- 与我们一起扩展。我们的规模每年都在翻倍,因此所选的解决方案应该能够轻松地跟上这种增长。理想的情况是增加更多的机器。
我们首先评估了像红移、大查询和点击之家这样的强国。虽然它们对于数据仓库来说肯定是很好的选择,但是我们发现它们对于实时分析工作流来说还不够好。
在我们的例子中,重点是执行亚秒级分析查询,而不是长时间运行的分析。
然而,在非常大的数据集上实现亚秒级的聚合性能对于红移来说是极其昂贵的,对于 BigQuery 来说是不可能的。
此外,我们发现 BigQuery 的另一个问题是定价取决于使用情况,而不是存储。因此,我们不认为支持公共 API 是一个安全的选择。
对于 ClickHouse,我们很想尝试一下,但最终发现托管、维护和微调它需要大量额外的工程开销。
最后,我们的搜索将我们带到了 Citus Data 及其针对 PostgreSQL 的 Citus 扩展,这使得通过跨多个节点分布表和查询来无缝扩展 Postgres 成为可能。
Citus Data 还提供了几个扩展非常适合实时分析,如 HLL (HyperLogLog)和 TopN 。前者是一种快速近似非重复计数的算法,后者的作用类似于一个堆,它允许在 JSONB 字段中按照频率对顶部的项目进行排序。
如果我们选择这个解决方案,我们可以将客户的数据分布在许多节点上,利用搭配,并预先计算指标。额外的好处是,我们仍然可以从运行最新 Postgres 实例的关系数据库中获益。
做出数据存储决策后,下面是我们分析解决方案的其余部分在实践中的工作方式。
创造近乎实时的分析
然而,实现亚秒级分析查询并不是现成的。我们通过跨分片分布数据和使用汇总方法来实现这一点。
为此,我们必须执行以下步骤:
- 将原始事件纳入系统。
- 定期将事件汇总到专用汇总表中。
- 查询汇总表并以毫秒为单位获得结果。
摄取
我们利用 Postgres COPY 命令将批处理事件插入 Citus。正如我们将在下面看到的,我们从不直接查询原始数据,所以这些表可以保持非常简单的模式。
由于没有大量的索引需要更新,插入操作的性能相当可观。Citus 宣称每秒钟可以接收 700 万行数据(也就是每天 600 亿行!)和我们自己的基准测试显示了类似的趋势。
我们按客户分发我们的数据。单个客户的数据存储在同一个碎片上,因此我们可以利用搭配优势。以单个客户应用为目标的请求将只需要以单个 Postgres 实例为目标。
汇总
我们不提供来自原始事件的指标。在某些情况下,如果您希望获得亚秒级的响应时间,即使是单个客户的数据集也会变得太大而无法即时处理。
根据经验法则,使用 PostgreSQL,每个内核每秒可以聚合 100 万行。
我们改用卷式桌子。汇总表保存给定时间范围内预先计算的指标。
正如我们在简介中看到的,我们经常需要返回 tops 和 distinct count。由于上面提到的 TOPN 和 HLL 扩展,这变得很容易。
下面是一个简化的汇总函数,涵盖了几个用例:
此函数将在给定时间范围内收到的所有查询聚合到 5 分钟的桶中,并计算它们的计数,即用户的唯一数量(使用 HLL),并保留排名靠前的查询及其各自的计数(使用 TOPN)。
该功能将在所有节点上同时执行。
对于我们的分析解决方案,我们有几个级别的汇总。我们每 5 分钟汇总一次事件,并进一步按天汇总。我们这样做有几个原因:
- 这意味着 API 返回的指标会频繁更新。大约每隔 5 分钟,数据就会刷新一次,因此客户不必等待很长时间,他们的查询就会反映在控制面板中。
- 为了进一步压缩我们的数据集,我们保留了每日总量。这意味着在某些时候粒度会降低到一天的级别,但这对我们来说是可以接受的。我们甚至可以考虑在某个时间点之后按月滚动我们的数据集,这将允许我们以更粗的粒度为代价继续提供接近无限的保留。反之亦然,增加中间每小时汇总也是将来的一个选项。
- 因为我们预计算 top,所以我们不能一整天都向它们追加查询。这样做会产生非常不正确的顶部。相反,我们在一天中建立了许多顶部,我们通过 EOD 将它们合并在一起。我们仍然在做 top 中的 top,但是考虑到它们的细粒度和我们一次合并它们的事实,最终,我们只看到了与更详尽(和计算更密集)的方法相比的最小差异。
这种方法的结果是,一旦数据被卷起,我们就可以删除它。我们不需要在 Citus 中保存太字节的原始事件来提供指标,并且由于 Citus 能够跨节点并行删除,删除数据变得很容易。
分析查询
API 的目标是汇总表,而不是原始表。如果我们比较原始表和汇总表中的行数,我们会看到平均压缩率从 50,000 到 150 不等(当然,这取决于为聚合选择的维度)。
这就是这种方法如此有效的原因。因为最终我们的指标是每天预先计算的,所以我们很容易理解为什么我们在几乎任何时间范围内都能在毫秒内得到结果:查询时扫描的数据量是微不足道的。
例如,要获得一个给定客户在过去一周的查询计数,快速的索引扫描是获取位于相同实例上的 7 行,后跟一个 sum。
为了获得上个月的前 1000 个搜索,我们获取 30 行,去掉前几个条目,并进一步将它们聚合成最终的前 1000 个。
下面是几个简化的示例查询来演示:
要获取查询计数,请执行以下操作:
因为我们的指标在合并到每日汇总之前首先存在于 5 分钟汇总表中,所以我们查询这两个表并在查询时联合它们的结果。
为了获得不同的用户计数,我们利用了 HLL 类型,它可以计算几个 HLL 字段的交集。
SELECT hll_cardinality(sum(user_count))::bigint FROM ... WHERE ...
最后但同样重要的是,下面是获取前 10 个查询的方式:
SELECT (topn(topn_union_agg(top_queries), 10)).* FROM ... WHERE ...
我们所有的分析查询都遵循这种模式,在查询时只执行最少的聚合逻辑。
大局
让我们后退一步,看看整个系统:
在实际将查询插入 Citus 之前,我们首先将击键聚合到查询中。我们的大多数客户都实现了即时搜索。使用 InstantSearch,您可以在键入时获得结果。这是一个很好的用户体验,它会为给定的搜索生成许多 API 请求。例如,搜索“Algolia”可能会产生多达 7 个查询(A、Al、Alg…等)。说到分析,我们只想提供关于完整查询的见解(有人搜索过 Algolia 一次),而不是中间的击键。
为了确保这一点,我们有一个管道来处理我们的日志,将击键序列聚合到搜索中,然后直接推送到 Citus。
我们使用 Go 作为我们选择的语言来重建这个管道。我们在 Algolia 一直有一个微服务方法,在过去的一年里,我们开始在 Go 中构建我们的大多数服务(除了我们的搜索引擎),到目前为止,在性能和生产率方面都非常满意。
为了完成这幅图,我们依靠 GKE 上的 Kubernetes 进行编排,依靠 Google Pub/Sub 进行跨服务的通信。
结论
由于 Citus 和基于汇总的方法,我们的分析每天处理数千个客户的数十亿次搜索,这个数字还在快速增长。到目前为止,我们对该系统的性能和可伸缩性非常满意,并期待着在它的基础上构建更多的产品。
了解我们如何将 AWS 上的 Citus 迁移到 Azure 上的 Citus而不影响我们的用户或代码库。
为电子商务和媒体建立推荐,有或没有 AI
原文:https://www.algolia.com/blog/ai/building-recommendations-for-ecommerce-media-with-without-ai/
随着电子商务和数字媒体的普及,大多数在线公司用于推荐的工具并没有发生实质性的变化——直到最近。大约从最早的数字市场开始,早期的推荐工具就基于启发式过滤器,将商品分成不同的类别,并跟踪用户购物车或观察列表中的同现情况。
虽然基于过滤的推荐(如下所述)实现起来很简单,并且不一定依赖于复杂的算法,但它们有其局限性。基于机器学习的现代解决方案 提供了重大改进 。
亚马逊处于人工智能推荐系统的最前沿——推荐占其销售额的 35%。他们的算法被小心翼翼地保护着,训练有素——而且很昂贵,但有可能以少得多的投资获得很好的结果。Netlify 和 Spotify 也是如此。
推荐引擎可以围绕 多种车型 。根据你的产品和目标消费者,会根据你的需求使用不同的算法。任何在亚马逊上购物的人都会非常熟悉两个最广泛使用的模型。“相关项目”和“那些谁买了这个也买了”推荐都是 协同过滤 算法,实现它们有一系列选项。
在本帖中,我们将介绍几种不同的推荐工具。您可以使用基于标记和过滤的经典方法。或者,我们将展示机器学习(ML)和人工智能(AI)如何提供隐私安全和更自然的推荐。最后,您将看到 Algolia 推荐 如何解决这些问题,为开发者提供一个 API 级别的推荐引擎。但是首先,理解用户的背景以及他们会如何看待你的推荐是很重要的。
让优质推荐成为搜索旅程的一部分
潜在客户通常通过两种方式进入网站。有了具体的指导方针,他们可能知道自己到底在寻找什么——一顶高质量的儿童自行车头盔、一件天然纤维的白色上衣、一个棕色皮搁脚凳。或者他们可能正在浏览,为一个重要的生日寻找礼物,或者为家庭办公室寻找更好的解决方案。
无论哪种情况,通过识别用户行为模式,推荐都有可能将潜在买家与他们自己可能没有发现的产品联系起来。下面,我们来看看两种可能的方法——一种简单的基于过滤器的方法和一种基于 ML 的解决方案。
用不带 AI 的简单标签获取自定义结果
在几十件白色衬衫中,用户点击了一件束腰亚麻衬衫。在不使用任何 AI 的情况下,利用标签和销售历史就可以进行推荐。
也许那件衬衫被贴上了“休闲”的标签,是你春季编辑活动的一部分。你可以很容易地返回一个简短的清单,列出三四件符合至少两个标准的其他衬衫——休闲风格、春季、亚麻、白色、束腰长度、价位。
准备您的数据到 提供这种类型的建议 需要一些前期工作和持续验证,以确保您库存中的所有产品都被正确索引。对于每个项目,您必须决定要“匹配”什么属性,以及每个匹配属性的相对重要性。当一个新产品添加到您的目录中时,它需要被“标记”并分配匹配的属性,这可能不容易自动上传。衬衫的颜色可能会自动填充,但“款式”或“季节”可能不会。使用这种方法有可能获得精确、高质量的建议,尤其是如果您的库存变化不太频繁的话。
另一个非人工智能的方法是使用销售历史。一个合理的假设是,有一个共同购买经历的客户可能也有其他共同之处。销售历史可以为购买了所选商品的人购买的其他商品提供推荐。查找这些产品-购买者-产品关系的查询可能会比上面的产品-产品关系使用更多的资源,因此对于大量库存来说可能是低效的。对于拥有许多产品类别的公司,这也可能导致推荐中出现一些不必要的“噪音”(例如,最畅销的商品出现是因为它普遍受欢迎,而不是因为它与其他产品相关)。此外,当一个新产品被添加到您的目录中时,将没有购买历史可供参考。
销售历史方法的另一个缺点是,它将消费者数据直接引入匹配算法。当然,以一种完全安全和私密的方式做到这一点是可能的,但是任何时候在面向公众的代码中使用客户数据,都有暴露私密数据的更大风险。避免数据泄露是一项需要时间和知识的承诺。
根据你的情况,这些负面影响可能会很大。虽然好的推荐不需要人工智能,但你可以避免处理用户数据和强行微调推荐。让我们来看看采用基于 ML 的方法是什么样子的。
使用基于 ML 的 AI 解决方案获得更好的推荐
基于过滤的非人工智能推荐的问题在于,它们假设用户知道他们想要什么,并能准确描述。有时候就是这样。但通常,最有效的推荐是针对用户自己可能没有找到或发现的项目。
基于最大似然的推荐的主要优点是有助于发现问题。儿童自行车头盔的购买者可能还有其他共同的需求——儿童安全设备,潜在的户外活动,健康饮食,或替代通勤,或其他更难预测的兴趣。
人工智能算法没有试图预测所有这些联系,而是注意到购物者行为中可能难以预测或描述的模式。基于 ML 的解决方案提供的推荐具有意外收获和“适合”的元素,这有助于它们脱颖而出。要开始观察这些模式,首先要收集用户事件。然而,正如前面提到的个性化一样,重要的是不要暴露私有数据。
捕捉用户事件,以低隐私风险获得高质量的结果
基于 ML 的推荐引擎可用的最丰富的数据是用户事件,如点击和转换。历史上,推荐只反映用户的 当前 动作——最近点击的项目,当前搜索词。搜索一件白色上衣,你会得到白色上衣。与单个事件相比,跟踪用户动作序列可以更深入地了解特定用户的目标和兴趣。从白色衬衫到浅色连衣裙再到凉鞋的点击流,比最初的搜索词更能洞察购物者的兴趣。
这种用户数据跟踪会给你的应用带来不必要的隐私风险。人工智能解决方案的一个幸运之处是,它们在用户隐私和数据安全方面取得了胜利,并提供了更好的建议。他们根据许多人过去的行为进行学习,然后根据模型进行预测。
基于 ML 的解决方案专门针对特定会话期间客户与您的产品和服务的交互方式进行调整。特定的搜索词、点击和用户当前访问你的网站的转换可以帮助你根据他们当时正在寻找的东西来定制推荐。
收集事件数据 支持的不仅仅是推荐。跟踪用户查看、点击和转换事件可以告诉你很多关于用户如何与你的网站和产品交互的信息。您需要对事件数据进行分类和存储,用线性回归和其他基于 ML 的算法训练您的模型。
如果您选择使用 Algolia,其Insights API将成为您收集用户事件数据并将其发送到您的应用程序的中枢。您可以使用这些数据进行 A/B 测试和动态产品重新排名,以响应用户的选择,并提供更有针对性的建议。
下面的代码显示了数据如何发送到 Insights 的简单示例。您前端的一个onClick
事件处理程序发出一个简单的 POST 请求(这里显示的是您可能模拟 cURL 的事件):
curl -X POST \
https://insights.algolia.io/1/events \
-H 'x-algolia-api-key: ${ADMIN_API_KEY}' \
-H 'x-algolia-application-id: ${APPLICATION_ID}' \
-H "Content-Type: application/json" \
-d '{
"events": [
{
"eventType": "click",
"eventName": "Product Clicked",
"index": "products",
"userToken": "user-123456",
"timestamp": 1529055974,
"objectIDs": ["9780545139700", "9780439784542"],
"queryID": "43b15df305339e827f0ac0bdc5ebcaa7",
"positions": [7, 6]
},
]
}'
A queryID
将点击事件绑定到特定的 Algolia 搜索,并且仅在搜索的一个小时内有效。基于会话的令牌将点击事件连接到用户。暴露敏感用户数据的风险很小,因为根本不会收集这些数据。与此同时,用户可以获得与他们当时的行为相应的推荐。
使用协同过滤生成精准推荐
最常见的“频繁一起买”建议先从 协同过滤 算法说起。任何推荐人工智能的基本目标都是找到用户和产品之间的相似之处,并基于这些相似之处提出建议。协同过滤算法被广泛用于数据科学中,根据具有相似偏好的其他用户对产品的评价,预测用户对产品的评价。 协同过滤 很多解释都是以电影为例。一个简化的场景:
- 我爱古装剧,给过 皇冠**叫接生婆这样的电视剧很高的收视率。
- 我真的很反感奇幻太多的电视剧,给了 夏洛克 和 神秘博士很低的收视率。 姐姐爱死他们了!
- 帕特和山姆也都喜爱古装剧,并且对 王冠 评价也很高。
- 帕特也喜欢奇幻类的节目,并给我不喜欢的节目打高分。
- 山姆和我更相似,所以他对奇幻电视节目评价较低。
- 一部被归类为神秘/犯罪的新剧上映了,但它同时包含了历史和幻想的元素。帕特对它评价很高,萨姆评价较低。
- 在此之前,我们没有人给推理/犯罪节目评分。
- 因为我的喜好和山姆的大体匹配,所以不推荐我看这个节目。我妹妹的偏好与帕特的相匹配,她在她的推荐队列中获得了新节目!
在规模上,协同过滤算法比这更复杂,尽管基本原理非常相似。与我们上面讨论的非人工智能解决方案不同,可伸缩性是基于 ML 的推荐系统的一个卖点。数据集越大,使用人工智能算法的情况就越有说服力,因为有更多的机会发现用户行为的模式。亚马逊在很大程度上依赖于协同过滤,这导致产品推荐可以感觉到意外收获和独特的个性化。
协同过滤算法分为 几类——基于用户、基于项目、混合和矩阵分解。即使在混合系统中,也有一系列的选择来决定有多少种方法可以组合以及以什么样的优先顺序组合。根据用户数量、项目类型、每个用户的评级密度和项目类别,每种方法最适合不同类型的数据集。
使用 Algolia 推荐获得一个不断改进的基于 ML 的解决方案
虽然没有适用于所有目的的单一推荐解决方案,但在大多数情况下,一个非常好的选项并不一定很复杂。对于电子商务公司来说,协同过滤方法可能仍然是最好的选择。
Algolia 推荐在一个 API 中交付 高性能 AI 驱动的 推荐。API 外形意味着它实现起来很快,尤其是因为简单的前端 UI 代码片段。这也是确保您的推荐随着时间推移会变得更好的一种方式。那些通过 API 交付的迭代改进会自动实现——无需您重新编码。
如果没有安果指数, 创建账号和 app 。实施 Algolia 推荐,独立或与 Algolia 搜索,将是一个简单的步骤,让您的电子商务网站获得最佳结果。你可以 看一下动作 两个视频,或者从我们的 深入了解一下 。如果您不熟悉 Algolia,这些资源可以帮助您加深对推荐引擎的理解,并让您感受到使用 Algolia 是多么容易。
使用 11ty Serverless、Netlify 和 Algolia-Algolia Blog Blog 为静态网站构建服务器呈现的搜索
在创建任何网站或应用程序时,渐进式改进都是一个重要的主题。当用户的浏览器不能处理任何 JavaScript 或您正在使用的特定 JavaScript 时会发生什么?如果您的前端出现故障,您需要一个后备来允许基本功能继续工作。
这有什么难的?
当您在 Jamstack 上工作时,这可能比在传统堆栈中工作要困难得多。由于 Jamstack 致力于从 CDN 提供 HTML,我们没有传统的服务器,只有静态文件和无服务器功能。因此,我们可能会发现自己在为前端和服务器重写渲染代码。三年和重新设计过去了,突然你在时间机器里看着去年设计的搜索结果。
有了 11ty 新的无服务器包和 Netlify 功能,我们可以从服务器快速启动。在此基础上,我们可以逐步增强使用 InstantSearch.js 等库的体验。
什么是 11ty 无服务器?
11ty 是一个用 Node.js 编写的静态站点生成器,它提供了多种模板语言和多种获取数据的方法。它的构建考虑到了灵活性。
历史上,它在构建过程中完成所有工作,并生成可以存储在 CDN 上的 HTML。这就创建了在 Jamstack 上运行得非常好的快速网站。
对于任何动态内容,它都依赖前端 JavaScript 来获取数据。这在许多情况下都有效,但是没有提供明确的渐进增强的途径。
如果你的前端代码失败了,你的站点的动态方面也会随之失败。随着 11ty 1.0 版本的发布,这将不再是一个问题。11ty 将捆绑可选的 11ty 无服务器插件。这将允许开发者指定可以处理用户输入的路由。该输入可以来自查询参数或 URL 结构本身。
我们在建设什么
在这个演示中,我们将采用一个非常简单的 11ty 站点,并添加一个动态搜索路线。该搜索路径将使用 11ty 和一个模板过滤器在一个无服务器的函数中创建 HTML 所有这些都来自我们习惯的 11ty 代码。这将用于我们渐进增强中的“后退”。虽然我们不会在这个演示中构建一个基于 JavaScript 的搜索,但是使用 InstantSearch.js 创建一个实时搜索是一个坚实的用户体验的基础。
我们将如何构建它:
1.安装插件并配置无服务器功能
2。创建搜索页面
3。创建一个getResults
模板过滤器来查询我们的 Algolia 索引
设置
我们将从一个基本的 11ty 模板开始,只需要一点 HTML 就可以了。
首先,克隆这个库并安装依赖项(11ty 1.0 和 dotenv)。
想看看成品吗?检查存储库的final
分支或者查看这个演示站点。
npm install && npm start
我们项目的结构遵循 11ty 站点的基本结构。各个页面都在项目的根目录下——目前只有index.html
文件。模板在_includes
目录中。配置文件是根目录下的.eleventy.js
。站点模板也相对简单:一个包含页眉和页脚的基础模板。
一旦安装完成,我们将有一个本地运行的 11ty 工作站点。还不是很有意思,只是一个带一点 HTML 的索引页面。让我们添加一个搜索页面来引入一些内容。
安装并配置 11ty 无服务器插件
在其最新的 1.0“金丝雀”版本中,11ty 附带了插件 11ty 无服务器。这有助于生成我们需要按需运行 11ty 的无服务器功能。
为了在我们的项目中安装它,我们需要更新.eleventy.js
配置文件。
require("dotenv").config();
const { EleventyServerlessBundlerPlugin } = require("@11ty/eleventy");
module.exports = function(eleventyConfig) {
// Configuration rules
eleventyConfig.addPlugin(EleventyServerlessBundlerPlugin, {
name: "search", // The serverless function name for the permalink object
functionsDir: "./netlify/functions/",
});
};
由于 11ty 正在我们的项目中创建我们不想在版本控制中跟踪的文件,请用以下项目更新您的.gitignore
:
netlify/functions/search/**
!netlify/functions/search/index.js
当我们重新运行npm start
时,11ty 现在将在functionsDir
指定的目录中创建一个无服务器函数——以及所有必要的包文件,其名称由name
属性指定。
在大多数情况下,您不会修改这些文件。该插件生成了index.js
文件,可以对其进行编辑以用于更高级的用例。11ty 将在每次运行时覆盖该目录中的其他文件。
创建页面使用无服务器功能
现在 11ty 已经创建了该函数,我们可以添加一个页面来使用它。
首先在项目的根目录下创建一个名为search.html
的新文件。在文件中,我们可以用 frontmatter 配置页面的数据。
---
layout: "base.html"
title: Search Page
permalink:
search: /search/
---
变量layout
将指示使用_includes
中的哪个模板进行显示。变量title
将显示在 HTML 的
The
permalink`对象中,我们在这里指定这个页面的最终 URL 应该是什么。
如果你熟悉 11ty,你可能记得permalink
变量是一个字符串。对于简单的用例,您仍然可以使用字符串,但是对于无服务器,它将是一个对象。对象的键将是我们在无服务器功能的配置中指定的名称。
您也可以通过这种方式根据 URL 指定不同的无服务器功能。如果希望在构建时和请求时生成页面,也可以为 permalink 指定一个build
键。
一旦添加,页面将在/search/
呈现。除了页眉和页脚之外,它没有任何内容。让我们从查询参数中获取一些动态内容。
---
layout: "base.html"
title: Search Page
permalink:
search: /search/
---
<h2 class="is-size-3 mb-3">This list is built at request from the query "{{ eleventy.serverless.query.query }}"</h2>
这将创建一个标题,查看我们路线的查询参数,并插入query
参数包含的任何值。
如果您访问 URL 末尾带有?query=11ty
的页面,字符串11ty
将出现在标题中。
那么,我们如何进行查询并从 Algolia 得到结果呢?
创建一个getResults
模板过滤器
为了获得呈现模板所需的数据,我们需要创建一个模板过滤器。过滤器将接受来自无服务器页面的查询字符串,根据 Algolia 索引运行查询,并将一组文章返回到我们的搜索页面。
在我们深入研究代码之前,您需要有一个 Algolia 应用程序和一些环境变量。如果你已经有一个 Algolia 索引,请随意使用。我们将使用一个索引,其中包含带有标题、描述和 URL 的博客文章。如果您没有 Algolia 指数,创建一个帐户和应用程序,并使用这些数据手动创建您的第一个指数。
[
{
"title": "Creating an omnibar with Autocomplete",
"description": "In this tutorial, we’ll walk through setting up Autocomplete to fire interactions with JavaScript. Specifically, we’ll build an omnibar to toggle light and dark mode for our website. An omnibar is a search field that has both search and actions that can be taken. A strong example of this is the Chrome or Firefox search and URL bar.",
"url": "https://www.algolia.com/blog/engineering/creating-an-omnibar-with-autocomplete/"
},
{
"title": "Building a Store Locator in React using Algolia, Mapbox, and Twilio – Part 1",
"description": "These days, ecommerce shoppers expect convenience and want the physical and online worlds to mesh allowing them to conduct their business on whichever channel they want. For example, users may choose to:",
"url": "https://www.algolia.com/blog/engineering/building-a-store-locator-in-react-using-algolia-mapbox-and-twilio-part-1/"
},
{
"title": "Introducing Algolia Recommend: The next best way for developers to increase revenue",
"description": "Now, with the introduction of Algolia Recommend, Algolia further enables developers to unleash the component of the experience that drives the remaining part of the product discovery experience: product recommendations. ",
"url": "https://www.algolia.com/blog/product/introducing-algolia-recommend-the-next-best-way-for-developers-to-increase-revenue/"
}
]
一旦有了索引,创建一个.env
文件并添加以下变量:
# The app id
ALGOLIA_APP = ""
# The search-only API key
ALGOLIA_SEARCH_KEY = ""
# The index name
ALGOLIA_INDEX = ""
一旦这些都准备好了,我们就可以通过 Algolia JavaScript 客户端提交查询来获得结果。因为我们的查询可以在模板中访问,所以我们将创建一个新的模板过滤器来使用查询并返回结果。
要创建一个新的过滤器,我们需要在.eleventy.js
配置文件中扩展 11ty。
首先,我们将安装algoliasearch
NPM 软件包。
npm install algoliasearch
require("dotenv").config();
const { EleventyServerlessBundlerPlugin } = require("@11ty/eleventy");
const algoliasearch = require("algoliasearch");
const client = algoliasearch(process.env.ALGOLIA_APP, process.env.ALGOLIA_SEARCH_KEY);
const index = client.initIndex(process.env.ALGOLIA_INDEX);
module.exports = function (eleventyConfig) {
eleventyConfig.addPlugin(EleventyServerlessBundlerPlugin, {
name: "search", // The serverless function name from your permalink object
functionsDir: "./netlify/functions/",
});
eleventyConfig.addFilter("getResults", function (query) {
return index.search(query, {
attributesToRetrieve: ["title", "url", "date", "description"],
}).then(res => {
return res.hits;
})
});
};
在文件的顶部,我们将使用 API 键、应用程序名称和索引名称来设置 Algolia 搜索客户端。之后,在导出的函数内部,我们将使用 11ty 的addFilter()
方法添加一个过滤器。
该方法接受两个参数:用作过滤器的字符串和使用时要执行的函数。该函数将接收从页面文件传递的数据。在这种情况下,它将是用户输入的查询。
在这个简单的例子中,我们将查询传递给index.search()
方法,并只请求回我们需要的属性,以保持我们的响应较小。当结果返回时,我们可以将结果返回到我们的页面,以便在模板循环中使用。
---
layout: "base.html"
title: Search Page
permalink:
search: /search/
---
<h2 class="is-size-3 mb-3">This list is built at request from the query "{{ eleventy.serverless.query.query }}"</h2>
{% assign results = eleventy.serverless.query.query | getResults %}
<div class="card-grid">
{% for result in results %}
{% include "article.html" %}
{% endfor %}
</div>
在页面中,我们使用 Liquid 中内置的assign
标签将数据赋给一个变量。然后,我们可以遍历返回的数组,并将该信息传递给 include。这个 include 可以用于这些结果以及网站上的任何文章显示。应该在_includes
目录中创建article.html
文件。
<article class="card column">
<h2 class="title"><a href="{{ result.url }}">{{ result.title }}</a></h2>
<p class="content">{{ result.description }}</p>
</article>
由于 11ty 无服务器,我们现在在静态生成的网站中有了一个工作服务器呈现的搜索。11ty 无服务器可以帮助我们克服静态站点中的其他模式吗?在我们的开源代码交换平台上查看相关解决方案。
在 VivaTech 2019 上庆祝整个欧洲的创新
原文:https://www.algolia.com/blog/algolia/celebrating-innovation-across-europe-at-vivatech-2019/
住在巴黎时,风投公司经常问我欧洲的投资环境有多吸引人,尤其是巴黎。
2012 年 Algolia 成立时,美国风投对巴黎的印象相当负面。我听到了关于法国工作文化的所有典型的定型观念和误解——从每周 35 小时的工作到夏天的长假期。虽然这种刻板印象与历史有一定的相关性,但我不得不多次解释,法国人其实工作很努力!
时间快进到 2019 年,欧洲和巴黎的生态系统已经发生了巨大变化,变得既有活力,又对投资者和公司都具有吸引力。近年来,许多总部位于巴黎的科技公司,包括 Criteo、Deezer 和 Dailymotion,已经成长为全球舞台上的重要参与者。Algolia 目前为全球 6,500 家公司所使用,随着我们最近向 APAC 和日本的扩张,我们在每个主要地区都设有办事处。
相比 2012 年,现在我从风投和美国初创公司那里听到的关于如何在巴黎开设办事处的问题越来越多,而在欧洲其他城市中这种情况更甚。仅在过去一年,巴黎就有超过 35 亿美元的风投投资和超过 300 笔与总部位于巴黎的科技公司的交易,巴黎是最活跃、最有吸引力的科技生态系统之一。
最近,我参加了在本月早些时候举行的为期三天的“T4”2019 VivaTech 大会,与最有前途的初创企业和明日的颠覆者共聚一堂,探讨全球范围内的变革思路,就清楚地表明了这一点。正如其口号所言,VivaTech 是“全世界初创企业和领导者欢庆创新的聚会”。
自从 2016 年 Viva Technology 的第一次活动以来,我一直在关注它,并且对这一活动在科技界的重要性印象深刻。VivaTech 2019 的数字说明了一切,超过 120,000 人参加了,其中包括超过 13,000 家最具创新性的初创企业。我还对前来巴黎参加 VivaTech 2019 的世界各地领导人和 3300 名投资者的国际形象着迷。
作为活动的一部分,VivaTech 主办了首届下一届欧洲独角兽奖。Algolia 很荣幸成为深度技术类的获奖者,我也很荣幸代表我们全球的所有员工接受这个奖项。任何时候你得到行业的认可,这都是一个伟大的里程碑,提醒我们自 2012 年开始以来已经走了多远。
这些奖项让我们受宠若惊。它为我们提供了一个视角,让我们了解我们已经走了多远,我们是如何走到这一步的,我们为谁服务,以及我们还希望如何继续创新、发展并为客户的成功做出贡献。随着我们的快速增长(去年增长了 90%以上),这给了我们一个认可、庆祝和感谢 300 多名员工和全球 6,500 名客户的机会,是他们让我们取得了今天的成就。谢谢大家!
建立和扩大一家科技公司是一项艰苦的工作,需要激情、创新和毅力。正是这样的时刻进一步证实了我们走在正确的道路上,并激发了我们加快努力的愿望。如果你受到创新的启发,有动力,有合作精神,并想加入我们,我们希望收到你的来信,我鼓励你看看我们的职业页面上的空缺职位。
祝贺其他获奖者,包括同样获得大奖的pay fit(B2B SMB)Snyk(B2B 企业)Vinted(B2C)Olio&open classrooms(Tech 4 Good)。随着我们继续在世界上留下我们的印记,并成为一个现代和持久的创新中心,为所有欧洲初创企业的更多成功干杯。
使用 React 挂钩集中状态和数据处理,创建可重用组件
应用程序开发通常是被动的。我们看到了需求,我们会尽快提供解决方案。在这个快速的软件周期中,我们收集需求,并在需求出现时立即实现它们。我说的不是又快又脏。我指的是使用最好的 RAD 实践——快速应用程序开发。
RAD 循环如下:你实现伟大的核心特性( MVP 风格),依靠多年的经验来创建可维护的代码。但是随着时间的推移,会发生一些事情:需求发生变化,编写了更多的代码,代码库开始违背您直觉上优秀但可能不完全健壮的架构。所以你开始重构。此外,您会发现技术在变化,提供了新的方法来使您的代码更简单、更清晰、更强大。
进入游戏规则 反应钩子 。而且,一个快速增长的业务需要你用大量的新特性重写你的应用程序。
重写——从头开始。生活提供了第二次机会。
React Hooks 如何保存我们的管理应用
应用程序开发也可以是主动(被动)的。我们的管理应用程序是数据密集型的。以前,许多独立的(和竞争的)组件独立地管理它们的数据——连接、格式化、显示、更新等等…
一个 Admin 应用程序的要求
管理应用程序是集中数据处理的理想选择。管理员需要按原样查看数据,因此屏幕视图通常与底层数据的结构相匹配。因此,虽然我们面向客户端的仪表板为业务用户提供了功能视图,但管理员需要以一致和直观的方式查看用户或客户端订阅信息。
我们需要的是一个更具可扩展性的解决方案。由于我们从多个来源提取数据——所有这些都可以通过一个具有多个端点的 API 来访问——我们希望集中数据处理的常见方面。这不仅给我们带来了直接的好处(更好的测试、缓存、同步、标准输入),还促进和简化了未来的数据集成。
定制挂钩
我们实现了一个名为useData
的定制 React 钩子,它管理并因此集中了所有数据检索 API 调用、数据交换、类型检查、缓存和其他此类基于数据的功能。单单缓存就极大地提高了面向用户的速度。
同样重要的是,速度和集中化使我们的前端开发人员能够在界面的不同部分重用他们的组件和 UI 元素。这种可重用性创建了功能丰富、用户友好的 UI/UX,前端开发人员无需在每个组件中维护唯一的状态信息。最后,在幕后,数据可重用性使得驱动前端功能的模型一致。
我们将在以后的文章中讨论 React 钩子的前端好处;这篇文章是关于我们如何用一个可靠的和可伸缩的数据处理层来服务前端。
我们的useData
钩子如何集中这个过程
我们使用不同的数据源,有些比其他的更复杂,但是都遵循相同的 JsonAPI 规范。此外,他们都有相同的需求,即:
- 检索数据
- 反序列化并格式化它
- 验证其格式
- 执行错误处理(数据质量、网络)
- 与应用刷新和其他数据/工作流同步
- 缓存数据并保持其最新
说够了,下面是我们的useData
钩子代码:
import { useCallback } from 'react';
import { useQuery, useQueryClient } from 'react-query';
import { ZodObject, infer as Infer } from 'zod';
import { useApi } from 'hooks';
import { metaBuilder, MetaInstance } from 'models';
interface Options {
forceCallApi?: boolean;
preventGetData?: boolean;
}
interface ApiData<T> {
data?: T;
meta?: MetaInstance;
}
export interface DataResult<Output> {
data?: Output;
meta: any;
loading: boolean;
errors: Error[];
refresh: () => Promise<void>;
}
export const useData = <Model extends ZodObject<any>, ModelType = Infer<Model>, Output extends ModelType = ModelType>(
builder: (data: ModelType) => Output,
url: string,
{ forceCallApi = false, preventGetData = false }: Options = {}
): DataResult<Output> => {
const queryClient = useQueryClient();
const { getData } = useApi(url);
const getDataFromApi = useCallback(async (): Promise<ApiData<Output>> => {
// here we get the data (and meta) using getData, and handle errors and various states
return { data: builder(apiData), meta: metaBuilder(apiMeta) }
}, [getData, builder, queryClient, url, forceCallApi]);
const { data: getDataResult, isLoading, error } = useQuery<ApiData<Output>, Error>(
[url, forceCallApi],
getDataFromApi,
{ enabled: !preventGetData, cacheTime: forceCallApi ? 0 : Infinity }
);
const refresh = useCallback(async () => {
await queryClient.refetchQueries([url, forceCallApi], {
exact: true,
});
}, [queryClient, url, forceCallApi]);
return {
data: getDataResult?.data,
meta: getDataResult?.meta,
loading: isLoading,
errors: ([error]).filter((error) => error !== null) as Error[],
refresh,
};
};
正如您所看到的,这个钩子接受三个参数,当这些参数组合在一起时,我们可以获得以下所有功能:
- 一个“构建器”功能,用于转换和增强供我们的组件使用的数据
- 检索数据的 API 端点的 URL
- 可选参数。例如,在调用 API 之前忽略缓存或等待一些其他数据准备好
结果是我们的组件不再需要管理所有这些。我们已经抽象和封装了复杂性。
useData
钩子返回一些我们可以在组件中使用的值:
- 一些状态:加载和错误(如果有)
- 数据(如果有)
- 元信息(如果有,例如分页信息)
- 刷新函数(通过再次调用 API 来刷新数据)
建筑数据
让我们更深入地看看这段代码做什么以及我们如何使用它。
用 Zod 进行模式验证
得到数据是一回事。确保数据的结构或类型正确是另一个问题。复杂的数据类型需要像 yup 或 zod 这样的验证工具,它们强制执行有效和干净的方法,并提供工具和错误处理基于错误类型的运行时错误。我们的前端依赖于强类型数据集,因此验证阶段对我们来说至关重要。
我们用 zod 。Zod 用于建立数据模型。例如,我们应用程序的模型可能是这样的:
import { object, string, number } from 'zod';
const Application = object({
applicationId: string(),
name: string(),
ownerEmail: string(),
planVersion: number(),
planName: string(),
});
然后,为了构建我们的构建器函数,我们在 zod 模型上使用内部构建的通用助手。这个助手有两个参数:
- 我们的数据模型(上面例子中的应用)
- 用于丰富该模型的转换函数。
在我们的例子中,变压器看起来像这样:
import { infer as Infer } from 'zod';
const transformer = (application: Infer<typeof Application>) => ({
...application,
get plan() {
return `${application.planName} v${application.planVersion}`;
},
});
丰富的另一个例子是如果一个模型有一个日期:我们通常希望它公开一个 javascript 日期而不是字符串日期。
我们有两个版本的助手函数(一个用于对象,一个用于数组)。下面是第一个:
import type { ZodType, TypeOf, infer as Infer } from 'zod';
import { SentryClient } from 'utils/sentry';
export const buildObjectModel = <
Model extends ZodType<any>,
ModelType = Infer<Model>,
Output extends ModelType = ModelType
>(
model: Model,
transformer: (data: TypeOf<Model>) => Output
): ((data: ModelType) => Output) => {
return (data: ModelType) => {
const validation = model.safeParse(data);
if (!validation.success) {
SentryClient.sendError(validation.error, { extra: { data } });
console.error('zod error:', validation.error, 'data object is:', data);
return transformer(data);
}
return transformer(validation.data);
};
};
zod 的类型化输出非常干净,看起来像我们自己编写的 typescript 类型,另外 zod 使用我们的模型解析 JSON。为了安全起见,我们使用 zod 的safeParse
方法,该方法允许我们在解析步骤出错的情况下“按原样”发送回 JSON。我们的错误跟踪工具 Sentry 也会收到一个错误。
在我们的例子中,我们的构建函数看起来像这样:
export const applicationBuilder = buildObjectModel(Application, transformer);
// and for the record, here is how to get the type output by this builder:
export type ApplicationModel = ReturnType<typeof applicationBuilder>;
// which looks like this in your code editor:
// type ApplicationModel = {
// plan: string;
// applicationId: string;
// name: string;
// ownerEmail: string;
// planVersion: number;
// planName: string;
// }
调用 API
在内部,我们使用另一个定制钩子useApi
(不到 200 行代码)来处理 GET/POST/PATCH/DELETE。在这个钩子中,我们使用 axios 调用后端 API 并执行所有典型的 CRUD 功能。例如,在读取端,Axios 将我们收到的数据进行反序列化,然后将它从 JSON API 规范转换为更经典的 JSON,并从 snake_case 转换为 camelCase。它还处理我们收到的任何元信息。
此外,从流程的角度来看,它管理请求取消和调用 API 时的错误。
缓存数据
至此,我们可以总结一下:useApi
钩子获取数据,然后通过构建器进行验证和丰富;并且使用反应查询缓存结果数据。
我们实现了 react-query 来缓存前端的数据,使用 API 端点 URL 作为缓存键。React-query 使用上面提到的useApi
钩子来获取、同步、更新和缓存远程数据,允许我们用非常小的代码库利用所有这些功能。
在此基础上,我们要做的就是实现 react-query 的提供者。为此,我们构建了一个小的 react 组件:
import { FC } from 'react';
import { QueryClient, QueryClientProvider, QueryClientProviderProps } from 'react-query';
export const queryClient = new QueryClient({
defaultOptions: {
queries: {
refetchOnWindowFocus: false,
refetchInterval: false,
refetchIntervalInBackground: false,
refetchOnMount: false,
refetchOnReconnect: false,
retry: false,
},
},
});
type IProps = Omit<QueryClientProviderProps, 'client'> & {
client?: QueryClient;
};
export const GlobalContextProvider: FC<IProps> = ({
children,
client = queryClient,
...props
}) => (
<QueryClientProvider {...props} client={client}>
{children}
</QueryClientProvider>
);
最重要的是,它管理我们的缓存。我们有许多组件需要相同的数据,所以我们希望避免不必要的网络流量来检索相同的信息。性能始终是关键。限制执行不必要的网络调用的潜在错误也是如此。现在,有了缓存,如果一个组件请求数据,我们的缓存将存储该数据并将其提供给请求相同信息的其他组件。在后台,React-query 当然会确保缓存中的数据保持最新。
总而言之,这里有一个使用这个useData
钩子和我们上面定义的应用程序模型构建的组件的例子:
import { FC } from 'react';
interface ApplicationProps {
applicationId: string;
}
export const ApplicationCard: FC<ApplicationProps> = ({ applicationId }) => {
const { loading, data: application, errors } = useData(applicationBuilder, `/applications/${applicationId}`);
return loading ? (
<div>loading...</div>
) : errors.length > 0 ? (
<div>{errors.map(error => (<div>{error}</div>))}</div>
) : (
<div>
<div>{application.applicationId}</div>
<div>{application.ownerEmail}</div>
<div>{application.name}</div>
<div>{application.plan}</div>
</div>
);
};
如你所见,我们的useData
钩子让我们标准化加载和错误状态,鼓励我们编写处理这些状态的可重用组件。例如,我们有可重用的StateCard
和StateContainer
组件。有了现在容易获得的数据,我们就可以着手集成那些可重用的组件,并专注于构建一个出色的前端体验——干净、功能全面、可扩展。
从 Heroku 到 Google Kubernetes 引擎的挑战性迁移
原文:https://www.algolia.com/blog/engineering/challenging-migration-heroku-google-kubernetes-engine/
对于一个仅由开发人员组成的团队来说,Heroku 的简单性使我们很容易将原型投入生产。然而,随着我们产品的成熟和客户期望的增长,我们需要对我们的基础设施有更强的健壮性和细粒度的控制。我们知道 Kubernetes 是我们的正确选择。然而,迁移并不是一项简单的任务。
这是背景故事。大约一年前,我们决定为 Algolia 开发一个网络爬虫原型。如你所知,Algolia 的用户通过使用 Algolia 的搜索 API,将他们的数据上传到一个可搜索的索引,从而使他们的内容可被搜索。一些潜在客户问我们是否可以通过抓取他们网站的内容,自动填充他们的搜索索引。对此,我们很快在 Node.js 中搭建了一个网络爬虫原型,并部署到 Heroku 上。
我们没有失望:添加数据库服务器或 RabbitMQ 之类的服务只需点击一下鼠标。我们所要做的就是git push
部署新版本,然后我们的原型就投入生产了。
几个月后,我们的网络爬虫在 Algolia 的客户中流行起来,许多其他人也开始表达对它的需求。
然而,爬虫需要很多组件——一些在后台运行,另一些按需运行;此外,一些客户需要定制组件。随着产品变得越来越复杂,我们向基础设施同事寻求帮助。
这种复杂性的一个很好的例子是 IP 白名单。我们的一个客户希望我们从一个固定的 IP 地址开始爬行,这样他们就可以将该 IP 列入白名单进行高速爬行,而不会受到他们的负载平衡器的限制。只有两个工程师在开发爬虫,所以我们让其他同事用固定的 IP 地址建立一个 HTTP 代理。然而,随着客户数量的增长,越来越多的人开始提出同样的要求,我们的基础架构团队告诉我们,是时候让我们自己来解决这个问题了。
因此,我们决定迁移到一个云平台,该平台将对我们的基础设施提供更多的控制,并最终允许我们以编程方式设置和拆除代理。这就是我们如何决定是时候从 Heroku 迁移到谷歌 Kubernetes 引擎(GKE) 了。作为第一步,我们希望让我们的爬虫在 GKE 集群上工作,尽可能少地修改代码。只有这样,我们才能使它在生产中更加健壮和可维护。
这远不像我们最初想的那样简单。
在本文中,我们描述了我们的爬虫的架构,并解释了我们如何让它在 GKE 上运行,分享了我们在迁移时解决的三个挑战。然后,我们总结了迁移带来的一些经验教训和好处。
设置事物
在我们深入兔子洞之前,让我们对网络爬虫做一个概述——它的架构,底层服务,以及我们如何让它在本地和生产中工作。
爬虫本身是一组三个组件:
- 工人负责获取网页,从其 HTML 内容中提取信息,并将这些信息存储到 Algolia 索引中;
- 管理器负责将待爬行的 URL、与每个客户相关联的规则和约束(例如,速率限制)以及他们可能已经请求的任何配置更新分派给工作器;
- web 服务器负责处理寻址到爬虫的 API 请求(例如,从 Algolia 仪表板)并服务于其自己的管理和监视仪表板。
这些组件位于几个服务之上:
- RabbitMQ 队列,保存要爬网的 URL 列表;
- 一个 PostgreSQL 数据库,保存爬虫的状态,如客户配置、URL 列表和外部数据,以提高搜索记录的相关性;
- 一个 Redis 存储,保存我们仪表板的用户会话;
- Tika 服务器,作为代理从 PDF 文件和其他类型的非 HTML 文档中提取内容;
- 和一个 Rendertron 服务器,它充当代理,从需要执行 JavaScript 代码以在 DOM 中呈现内容的单页面应用程序中提取内容。
为了在开发爬虫时本地运行所有这些组件和服务,我们设置了一个docker-compose
文件,为它们指定 Docker 映像和参数。在 Heroku 上,我们为每个服务激活了附加组件,并编写了一个Procfile
来指定应该执行什么命令来启动每个组件。然后,通过简单地执行git push heroku master
,我们确保了组件的最新版本会自动上传并在我们的 Heroku dynos 中启动。轻而易举。
Kubernetes 是一个可以根据开发者定义的服务和部署来分派 pods 的系统。我们的第一个目标是让我们的组件和服务以与我们现有的docker-compose.yaml
文件相同的方式运行。我们只需要将文件转换成 Kubernetes 格式,并找到正确的命令来启动它们。
在花了几个小时试图用 kompose 做这件事之后,没有太大的成功,我们决定寻求帮助。一位同事以三种方式帮助了我们:在 GKE 上建立一个集群,为我们提供了用于部署和服务的 Kubernetes 定义文件的示例,并建议我们使用由 Google 管理的服务(即 PubSub 和 CloudSQL),而不是将我们自己的 RabbitMQ 和 PostgreSQL docker 容器作为 pods 运行。这都是很好的建议,但是太快了。为了更好地理解 Kubernetes 的工作方式,并对它更有信心,我们决定一次解决一个问题:首先,通过镜像我们的docker-compose
定义,让我们的服务在容器中运行,只有到那时,才考虑用谷歌管理的服务来取代它们。
因此,我们开始为每个服务编写 Kubernetes 定义文件。
实现——让我们先让 Kubernetes 运行起来
我们这样定义它们:
总结一下:
- 部署是对可以部署、在给定数量的实例上运行和停止的软件的描述;
- 服务是可以处理来自系统其他部分的请求的部署。
例如,要在 Kubernetes 上运行 RabbitMQ,我们需要:
- 通过指定运行 RabbitMQ 服务器的 Docker 映像来定义部署;
- 并定义一个公开两个端口的服务:一个用于 AMQP 查询,一个可选端口用于管理 UI。
除了需要被定义为服务的 web 服务器之外,我们以与部署相同的方式定义了我们的爬虫组件。因为这些组件不是 DockerHub 上的公共 Docker 映像,所以我们还必须编写一个 Docker 文件来从我们的源代码生成一个映像,将该映像上传到我们的 Google Registry,然后从我们的三个部署中引用它的标识符。为此,我们必须学习如何使用 gcloud 和 kubectl 命令行界面(CLI)工具。
在 YAML 文件中定义了我们的部署和服务之后,我们需要它们相互连接。例如,我们的三个爬虫组件期望环境变量包含它需要连接的所有服务的 URL。在 Heroku 中,我们有一个所有 dynos 共享的全局环境变量列表。我们可以从 Heroku 仪表板或通过他们的 CLI 编辑它们。也就是说,我们的大多数插件(例如托管 PostgreSQL 数据库)会自动设置环境变量来提供对其数据的直接访问,因此我们不需要做太多工作。
在 Kubernetes 世界中,环境变量是在部署级别设置的。这意味着每个部署文件都应该包含必要的环境变量的值。此外,考虑到 Kubernetes 可以随时动态终止和重启不同节点(例如,集群的物理机器)上的部署,它们的 IP 地址和端口可以改变。因此,我们不能为组件的环境变量提供硬编码的值。
幸运的是,我们了解到 Kubernetes 为所有服务动态生成集群范围的环境变量,格式为<SERVICE-NAME>_SERVICE_HOST
和<SERVICE-NAME>_SERVICE_PORT
。我们还发现,通过使用以下 YAML 语法,可以将环境变量的值注入到其他变量中:
像密码这样的机密环境变量需要不同的过程。为此,我们使用了 Kubernetes 秘密。
秘密是可以保存机密值的 Kubernetes 实体。建议将它们用于存储密码、证书和任何其他类型的私人信息:这些值永远不会以纯文本形式添加到 YAML 文件中,访问它们需要特殊权限。
要存储为环境变量,还必须在需要的部署的 YAML 文件中声明机密。然而,它们的结构与环境变量不同:我们需要挂载一个卷来加载秘密,然后将它们的值作为环境变量导入。
我们后来了解到,使用 ConfigMaps 可以在几个部署之间共享环境变量。这些是 Kubernetes 实体,可以保存几个命名值,并作为环境变量导入到部署中。
使用 ConfigMaps 阻止了我们复制配置,但是我们找不到任何方法来包含秘密,或者任何其他实体,这将在配置映射中包装其他环境变量的值(例如,使用$()
语法,如上所示)。因此,我们最终将 ConfigMaps 用于不变的配置值,将 Secrets 用于密码和密钥,将 inline 环境变量定义用于依赖于其他环境变量的环境变量。
此外,由于我们希望我们的 YAML 文件在不同的域名上提供两个不同的集群(例如,生产和暂存),我们最终使用 sed 将其中一些转换为模板并编写一个脚本,将它们转换为最终的 YAML 文件。我们非常确定有一个更标准的方法来实现这一点,但考虑到我们能够在这一迁移上花费的时间,这种方法对我们来说是一个很好的妥协。
那时,我们已经编写了 10 个 YAML 文件和 5 个 bash 脚本来定义我们的组件和服务。我们终于准备好供应我们的 GKE 集群,并看到他们运行。上传我们的 YAML 文件并让它们在我们的集群上运行的命令是:kubectl apply -f .
。
为了举例说明我们编写的脚本,下面列出了在部署可能包含数据库迁移的更新后,我们为重启所有组件而运行的命令:
没那么快。一位同事警告我们,为了使我们的仪表板可以从互联网上访问,我们必须定义一个入口资源来将我们的“web”服务连接到 Google 的 HTTP 负载平衡器。
他举了一个例子,结果是这样的:
几分钟后,我们的仪表盘终于启动了!
遗憾的是,在允许 HTTPS 访问该端点之前,我们无法使用单点登录系统登录。让我们深入研究一下。
有线 SSL 证书
在 Heroku 世界中,启用 HTTPS/SSL 是小菜一碟。你所要做的就是点击一个按钮。
Heroku 会使用 Let’s Encrypt 自动生成一个免费的 SSL 证书,回复 ACME 挑战,并每 3 个月自动重复该过程以在我们不知情的情况下更新证书。刚刚成功了。
我们希望 Google 也能提供一个简单的方法来在我们的 GKE 集群上设置它。再想想!GKE 的文档明确指出,虽然可以通过 kubectl 或 Google Cloud Console 将 SSL 证书与 Google 的负载平衡器关联起来,但它们没有提供生成证书的方法。
我们使用 Google 来寻找解决方案,我们发现有几个项目承诺为您的 GKE 集群生成和更新一个 SSL 证书,并且会自动将它关联到我们的负载平衡器。不幸的是,它们都包含了免责声明,如“不要在生产中使用”或“我们目前不提供关于 API 稳定性的强有力的保证”。因此,我们决定,在 Google 提供一种可靠的方法来自动完成这项工作之前,我们将手动生成一个 Let’s Encrypt 证书,然后将其附加到我们的负载平衡器上。唯一的问题是,我们需要记住每隔几个月做一次。
我们的爬虫在那时是完全功能性的。迁移前唯一剩下的问题是 PostgreSQL 数据库中的数据可能会丢失,因为它仍然从 Docker 容器中运行,没有持久卷,也没有任何备份例程。
免责声明:自从我们迁移以来,其他解决方案让这个过程变得更加容易。我们还没试过。
插入托管数据库
数据是一件严肃的事情。我们的客户依赖于我们,因此他们的数据应该随时可用,无论规模如何都能响应,没有泄漏,并且在发生事故时能够快速恢复。这些都是信任托管数据库服务,而不是从 Kubernetes 可以随时终止的 Docker 容器中运行数据库的绝佳理由。
作为谷歌云生态系统的一部分,CloudSQL 产品最近将他们的托管 PostgreSQL 服务宣传为“生产就绪”,所以这对我们来说是显而易见的:我们应该将我们的爬虫插入到该服务中。我们的同事告诉我们,我们必须集成一个所谓的 CloudSQL 代理来连接到 CloudSQL 管理的 PostgreSQL 服务器。
为此,我们遵循了谷歌提供的教程。除了用 CloudSQL 代理服务替换 PostgreSQL 服务之外,我们还必须:
- 创建数据库用户;
- 将用户密码安全地存储为 Kubernetes 秘密;
- 创建一个服务帐户,从我们的组件访问 CloudSQL 实例;
- 在所有需要连接到数据库的部署中,将秘密作为动态环境变量加载。
尽管我们得到了帮助,但要将它集成到我们的系统中并不容易。Google 提供的教程解释了如何以“sidecar”的方式运行代理,这意味着 CloudSQL 代理将与应用程序本身运行在同一个 Pod 上,从而可以轻松连接到该代理。
在我们的系统中,我们有三个独立的组件需要访问同一个数据库,我们觉得给每个组件附加一个独立的 CloudSQL 代理会有些过头,而且更难维护。因此,我们必须花时间更好地理解如何配置部署。除此之外,有时有必要从集群外部访问我们的生产数据库(例如,出于调试目的从我们的开发笔记本电脑访问)。由于所有数据库连接都必须通过 CloudSQL 代理,我们有两个选择:
- 通过在我们的生产集群中运行的 CloudSQL 代理进行连接;
- 或者设置一个本地 CloudSQL 代理,每个开发人员有一个专用的服务帐户。
出于安全原因,我们选择了第二种解决方案。在下载了与我们为每个人创建的服务帐户相关联的 JSON 密钥之后,下面是我们如何能够在我们的笔记本电脑上运行 CloudSQL 代理:
如果您决定遵循这条路线,请确保您没有将与您的服务帐户相关联的 JSON 密钥保存在您的笔记本电脑上。我们建议使用像 Vault 这样的系统来更安全地存储这些密钥,或者甚至在每次连接时生成一个新的短期密钥。
免责声明:现在可以直接从 GKE 访问 CloudSQL 数据库了。我们还没试过这个。
结论
迁移需要时间,尽管我们采取了一些捷径,例如首先镜像我们系统的 docker 容器以达到 iso 功能阶段,然后用托管解决方案替换我们的数据库容器。最后,我们很高兴采取了循序渐进的方法。它让我们更好地了解 Kubernetes 如何工作,并掌握我们用来维护 GKE 集群的工具。它还防止我们不得不一次处理一个以上的问题,鉴于 GKE 的复杂性以及在这个生态系统中解决问题的无数方式,这可能成为沮丧和消极情绪的主要来源。
我们花了几周时间让我们的爬虫在 GKE 上可持续运行,并最终关闭了我们的 Heroku dynos 和附加组件。虽然迁移比我们预期的更加繁琐和不简单——尽管我们得到了拥有 Kubernetes 和谷歌云产品经验的同事的帮助——但最终,我们对它带来的东西感到满意。例如:
- 现在,我们对每个组件的硬件要求及其独立行为有了更好的理解。迁移到 Kubernetes 使它们在动态基础设施上更加健壮(例如,可以随时关闭和重新分配不同 IP 地址的节点)。
- 我们目前正在探索如何自动水平扩展我们“工作人员”部署的副本数量,并且比我们在 Heroku 上所能做到的更有效。
- 我们相信,我们能够根据客户的需求,在我们的集群上以编程方式设置静态 IP 代理服务器。
好消息是,Google Kubernetes 引擎最近的发展已经解决了我们的一些困难,使这个过程变得更加容易。
顺便说一下,我们将于 3 月 7 日在巴黎办公室与一些谷歌专家组织一次关于 Kubernetes 的活动。如果那时你在欧洲,请随意注册!
作者感谢 Rémy-Christophe Schermesser、Sarah Dayan、Peter Villani、Angélique Fey 和 Tiphaine Gillet 对本文的贡献。以及所有帮忙校对的同事。❤️
如何选择合适的电子商务网站搜索工具
原文:https://www.algolia.com/blog/ecommerce/choosing-ecommerce-site-search/
因此,你的网站需要一个电子商务网站搜索解决方案。
现在,你可能正在想象研究、比较、测试并最终选择一个网站搜索解决方案的艰巨任务。在你沉溺于并排的比较或屈服于另一个普通演示视频的沉闷头痛之前,问自己这个问题:
新的电子商务网站搜索解决方案应该解决哪些首要需求或挑战?
- it 部门需要提高客户参与度吗?
- 您是否需要一个更加简单而直观的搜索界面?
- 你想通过网站上的搜索活动推动更多的销售和转化吗?
- 您是否正在为您的搜索工具寻找更好的投资回报?
考虑到您的首要任务,您可以专注于将推动结果的相关功能。您的业务和客户需求可以构成您分析的基础,也有助于您为供应商确定问题。毕竟,如果一个网站搜索工具不能处理你的电子商务网站目前做的所有事情,以及它未来需要做的事情,为什么还要有一个网站搜索工具呢?
一旦你确认你所关注的网站搜索工具涵盖了基本内容,专注于你的需求将确保你找到最好的电子商务网站搜索合作伙伴。
这一切要花多少钱?
你应该购买还是建立你的电子商务搜索?
伟大电子商务网站搜索的基础
为了有效,所有的电子商务网站搜索工具都需要一些基本的东西:
相关结果
电子商务工具的基本功能是寻找和排列最符合客户查询的结果。虽然这看起来很简单,但所有电子商务网站搜索解决方案的搜索算法并不都是一样的。
一些算法依赖于简单的关键字匹配。其他人则依赖于该术语在页面上出现的频率、点赞或评论的数量,或者这些因素的某种组合。然而,单靠这些方法并不能获得令人满意的结果——对于一个强大的搜索功能,你需要更多。
该算法应考虑每个搜索 的 上下文,并基于文本和业务相关性呈现结果。为了提供一流的相关性,工具应该使用 排名标准 ,包括:
- 容忍用户输入错误
- 区分不同产品属性的重要性
- 允许企业设置自定义排名标准
- 如果与您的业务相关,按距离排列结果
- 动态过滤结果
搜索引擎应该按照 的顺序将这些结果呈现给用户 。
为了向用户提供最大价值,电子商务网站搜索也应该在产品的同时呈现相关内容。例如,关于当前相关趋势的产品指南或博客文章可以与产品一起出现在搜索中。这促进了搜索和发现,增加了用户对网站的参与,并为网站搜索者增加了价值。
可靠性、覆盖率和速度
开箱即用的解决方案以快速实施的承诺吸引着企业。然而,如果解决方案无法提供可靠性、覆盖范围和速度,那么在安装上节省的资金可能会增加维护和保养费用。
- 速度。 创建一个快速的站点搜索很容易,做一个相关的也相对容易。但是 两者都掌握 很难。等待相关结果的几秒钟的延迟会累积起来,损害用户体验。网站搜索供应商应维护广泛的基础设施,以支持为您的所有客户提供即时搜索和即时搜索结果 而没有延迟 。
- 全球覆盖。 每一个网站,尤其是大型网站,都需要保证所有客户都能获得出色的搜索体验——不管他们在哪里。该公司应该拥有基础设施,如一个 全球分布式搜索网络 ,以确保每个客户都享有一流的网站搜索性能。
- 可靠性。停机会破坏客户对你的品牌的认知和他们的体验。如果供应商不能保证世界各地的数据中心确保 最大正常运行时间 ,你可能会想去别处看看。
网站搜索工具的必备功能
现在您已经有了一些基本要求,您需要考虑一些额外的高级功能来提升您和您的客户的搜索体验。让我们考虑一些主要领域:
- 索引
- 定制
- 个性化
- 分析学
- 销售工具
- 人工智能和机器学习
1。分度
密切关注你考虑的每个网站搜索工具的索引工作方式。
对于某些解决方案,索引的频率和索引项目的数量取决于您的工资级别。如果你的网站每天或每周频繁地添加产品,一个只按月索引的解决方案是行不通的。新产品需要一上网站就出现在用户的搜索中,而不是一个月后。
如果你的网站包含高度专业化的内容,寻找支持非产品内容索引功能的工具,如博客帖子、指南或客户评论。
2。定制
许多网站搜索工具都是现成的,这对于快速实施来说是非常理想的。然而,代价是这些工具很难或者不可能定制。开源解决方案拥有最多的定制选项,但是实现、维护和更新需要大量资源。
搜索即服务解决方案通常恰到好处,具有快速实施、高度定制以及较低的维护和创新长期成本。
考虑您的业务可能需要的各种配置:
- 您能否增强用户界面/UX 功能以满足您的业务需求?
- 您能保留解决方案之前实施的定制吗?
- 你能应用自定义业务逻辑吗?
你的搜索解决方案应该完全符合你的商业案例。如果解决方案缺乏满足你的愿景的能力,从你的列表中删除它是一个好主意。
3。个性化
个性化搜索结果使您能够将文本相关性、业务相关性和商品相关性结合起来,以满足客户的意图。它根据过去的用户行为来引导用户未来看到什么。
更加个性化的搜索体验有助于客户发现更多相关内容以及新产品和资源。这带来了更高的转化率、更大的平均购物车、更高的净推广分数和更多的客户参与度。
个性化 功能应该:
- 易于实施和使用
- 增加参与度
- 减少站点反弹
- 改善客户旅程
4。分析
电子商务网站搜索工具可以提供强大的商业洞察力。一旦你确定了你想通过网站搜索达到的目标,寻找能够提供与这些目标相关的数据的工具。
你的搜索工具应该:
- 帮助您跟踪转化率、点击量、“无结果”查询、跳出率、搜索退出率、平均购物车大小等等
- 在用户友好的仪表盘中显示信息
- 提供自定义报表
- 帮助您推动改进,例如突出某些产品,创建内容以填补关键空白,以及改进结果页面以阻止搜索退出
没有搜索分析,你就无法做出数据驱动的决策来改进你的网站。
5。销售工具
商品销售 是电子商务战略中必不可少的组成部分。你选择的网站搜索工具中的销售工具应该足够直观,网站所有者可以自行重新配置相关性和重新排列因素,以改善买家体验。
一些功能包括但不限于:
- 突出特定品牌
- 提升特定查询的特定项目或项目组的能力
- 在搜索结果的横幅中推广商品
在选择网站搜索解决方案时,您应该评估新工具将如何与您当前的销售配置配合使用。您已经投入时间和精力来开展营销活动,因此您选择的解决方案应该能够有效地支持这些活动。
6。人工智能和机器学习
供应商经常提到机器学习(ML)、人工智能(AI)和自然语言处理(NLP)来使他们的解决方案脱颖而出。然而,这些流行语的重要性取决于它们的相关性和实施。
机器学习、人工智能、自然语言处理是相互关联的概念。ML 和 NLP 是帮助开发和改进人工智能的技术,人工智能反过来为自动化提供智能。
一些公司夸口说,人工智能可以完全自动调整和改进你的网站搜索。虽然释放开发人员的能力似乎是有益的,但是请记住,您最了解您的业务。你真的希望 AI 完全接管你在线战略的重要部分吗?
人工智能应该提出建议,提供商业智能,帮助你做出最好的改进。没有你的直接输入,它不应该做出改变。
如有疑问,请求演示并询问有关解决方案如何使用 AI、ML 和 NLP 的详细问题。如果演示者不能准确解释技术是如何工作的,或者试图向你过度推销它的能力,你就要小心了。
启动并运行你的电子商务网站搜索工具
当你为你的电子商务网站评估网站搜索解决方案时,考虑它将如何在网站上实现。
实施注意事项
如果业务需求和技术需求没有明确定义,实施可能会让企业感到头疼,而客户网站搜索可以提供帮助。有必要考虑以下几点:
- 您的实施时间表是什么?
- 实施所选解决方案需要什么?
- 您是否有合适的开发人员资源来执行实施?
- 供应商是否支持实施,或者这是一个完全自助的过程?
- 从您当前的设置进行迁移将如何影响您当前的数据、跟踪、销售工具或其他定制?
- 实施期间会有停机时间吗?
提前计划是保证一个成功实施的最好方法。有些解决方案需要您购买服务器或安装软件才能开始;尽早了解这一点很重要,这样你就可以相应地规划资源。其他解决方案可能就像传输一些数据和调用 API 一样简单。
实施过程越复杂,评估开发人员的能力和技能以及了解搜索提供商团队的参与程度就越重要。如果您需要考虑高水平的定制或复杂的变量,请寻找一个在整个过程中提供定制实施服务和支持的站点搜索解决方案。
数据评估
数据驱动商业的很多方面,搜索也不例外。评估您当前的数据需求和数据状态,以了解新工具将如何适应:
- 你的数据现在处于什么状态?是否需要清洗或改造后才能使用?
- 新的网站搜索解决方案会接受你的数据转移吗?
- 新的解决方案将如何整合或利用您现有的数据?
- 新工具能让你收集和分析新数据吗?
- 重要的 KPI 如何在搜索工具中显示?
如果你已经用旧工具收集了搜索数据,检查这些数据是否可以集成到你的新工具中。如果这些数据对您来说至关重要,那么您将需要一个能够集成这些数据的解决方案。
你也要放眼未来。该工具是否允许您生成新数据并为您提供分析数据的工具?如果没有,想想这如何限制了你从搜索数据中学习的能力,以及如何随着时间的推移改进你的搜索功能。
管理和维护
一旦实施了新工具,就需要持续的管理来确保它以最佳状态运行。
使用“搜索即服务”解决方案,我们将为您处理维护和保养工作。由于基于云的基础设施,该工具的新更新和创新立即可用。
对于大多数其他工具,你必须自己完成这项工作。您将负责硬件成本,构建适合您的技术堆栈的搜索工具(如果您构建自己的工具),实施数据更改和补丁,以及解决日常问题。在这种情况下,你会想要考虑:
- 你和你的团队需要多长时间来了解产品的来龙去脉?
- 什么类型的资源(硬件、软件、开发团队等。)是新解决方案所必需的吗?
- 该项目是否需要额外的员工或培训?专业技能呢?
- 你将如何继续创新和迭代你的搜索解决方案?
考虑负责配置控制和根据需求变化或波动微调系统的用户。这个用户能直观地使用系统吗?用户能够按照产品文档完成不熟悉的任务吗?如果没有,寻找其他选择。
支持规格
即使有专门的资源、熟练的团队成员和丰富的经验,也总会有需要额外支持的时候。支持应超越实现,以涵盖意外问题。
确保为实施和未来需求提供可接受的支持。要考虑的常见要求包括:
- 您是否需要专门的专家,或者您是否可以利用特定产品的详细文档?请记住,两者都是这个问题可以接受的答案。
- 支持团队什么时候可以为您服务?
- 如何联系支持团队(即电话、电子邮件、聊天等)?
- 将实施哪些 SLA(服务水平协议)?
- 支持是分层的吗?层级基础是紧急程度还是包裹级别?
- 该解决方案是否为开发人员提供了可靠的文档?
这里需要注意的是,实施和未来需求不一定需要相同类型/级别的支持。您可以使用高水平的专用实施支持,但只需要一个快速聊天来指导您在未来找到正确的自助文档。
集成
确保您选择的解决方案与您当前的电子商务平台及其配置的任何扩展相集成。许多网站搜索与常见的电子商务平台,如 Magento 或 Shopify,以及常见的 CMS 平台,如 WordPress 和 Zendesk 一起工作,但没有什么是保证的。创建一个你选择的站点搜索工具必须支持的框架、平台和 API 需求的列表。
这一切要花多少钱?
成本问题是不可避免的,而且可能会极大地影响你的决定。比较价格时,请记住,从长远来看,在基本功能上偷工减料可能会让你付出更高的代价。看看价格结构,决定什么最适合你的公司——不只是现在,而是未来随着你的业务和网站的发展。
当你评估网站搜索解决方案时,考虑一下 无形的利益 以及有形的利益。优秀的网站搜索会影响客户体验、转化率,并最终影响底线。
计算站点搜索的 ROI
在决定最适合你的网站搜索需求时,有三个类别需要考虑:开源、现成的和搜索即服务
- 开源工具可以免费使用和下载,但是会从人员需求、硬件需求和用于设计、维护和改进你的搜索引擎的资源上产生巨大的成本。像这样的劳动密集型搜索项目,成本会迅速增加。虽然初始成本可能会更低,但假设你有一个完善的工具,你的公司需要很长时间才能获得投资收益。
- 现成的工具 因其易于实施和可预测的价格而吸引用户。不幸的是,维护和保养会产生意想不到的费用。这些工具还缺乏业务案例的可定制性。这意味着如果工具不能被定制以最有效地接触到您的客户,收入就会损失。
- 搜索即服务工具 提供托管实施、持续创新、持续维护和强大的定制工具。随着时间的推移,搜索即服务工具通常比其他网站搜索方法产生更大的投资回报率。
你应该购买还是建立你的电子商务搜索?
因此,如果你的公司有资源建立自己的定制搜索,为什么不冒险一试呢?
事实是,在内部构建一个定制的搜索工具是一个复杂、昂贵的项目。 打造自己的搜索工具 意思是你负责:
- 从头开始构建工具。
- 实现搜索工具。
- 记录工具的技术和面向用户的需求。
- 购买搜索所需的硬件/软件/附件。
- 处理所有未来发展。
- 承担所有维护和故障排除费用。
- 微调搜索引擎的相关性。
除非你的开发人员有丰富的从头构建搜索引擎的经验,否则这可能是一项艰巨的任务,尤其是当事情不可避免地发生故障并需要排除故障时。
虽然开始时这似乎是一个不太昂贵的解决方案,但从长远来看,构建自己的工具可能会让你花费更多。
尽管如此,在某些时候,建立自己的搜索引擎是最好的选择,即使它很贵。例如,如果您有一个供应商产品不能充分满足的复杂、严格的专业需求。在这种情况下,在你用一个新项目让你的开发团队大吃一惊之前,花点时间直接和供应商的产品团队谈谈,看看他们是否是合适的合作伙伴。
寻找最佳电子商务网站搜索合作伙伴
无论您选择哪种网站搜索,供应商都应该作为合作伙伴,具备推动您的业务目标和愿景的能力。供应商应该拥有 可靠的基础设施 以及支持您未来发展的能力。他们还应该重视创新和不断改进。
总的来说,就是找到最适合你的业务案例,给你成长的空间。在你做之前不要安定下来。
除了无与伦比的速度和相关性,Algolia 还为其每个搜索合作伙伴带来了持续的创新。凭借无与伦比的开发人员资源和支持,您可以高枕无忧,因为您知道您的站点搜索每次都适用于每个用户。 观看我们的 演示 并阅读更多关于 我们的特色 看看为什么像 LaCoste、Dior 和 Birchbox trust Algolia 这样的电子商务网站。
如何选择合适的企业搜索解决方案
原文:https://www.algolia.com/blog/ux/choosing-the-right-enterprise-search-platform-whats-important/
网站搜索引擎不再是一个简单的工具,它可以从你网站上的任何地方调出搜索结果并呈现所请求的信息。现在,正确类型的企业搜索系统已经成为那些绝对可以决定你的事业成败的事情之一。
为了赢得客户和员工的青睐,今天的企业网站搜索必须是个性化的体验,能够随着个人用户知识的发展而发展,并考虑到他们早期的互动。拥有合适的企业搜索平台无疑可以让您的指标产生显著的变化。
如果你正在寻找最好的企业搜索软件来确保你网站的成功,做一些研究来确保你能自信地做出正确的购买决定是值得的。
在考虑潜在的企业搜索解决方案时,首先考虑有效的现代智能搜索在企业成功大局中的重要性非常重要,无论是对您的客户、员工还是承包商而言。您希望优先考虑将 企业搜索 作为您的客户和员工体验的支柱。
为什么这一点如此重要?因为这是一个行之有效的策略,可以产生连锁反应。它可以交付大大改进的业务成果,例如:
- 更准确的数据 ,这些数据可用于更好地为您团队的销售和营销决策提供信息
- 客户的个性化体验: 更好的数据意味着您可以根据相关性更准确地定制客户旅程
- 更高的客户转换率: 更加个性化的用户体验可以让更多的人采取想要的行动
- 一种统一的数据使用方法, 这种方法可以释放存储库中的信息,并促进团队成员之间的顺畅协作
- 卓越的分析能力, 这意味着可以访问高质量的数据,从而做出更好的决策
在我们考虑企业搜索平台中的一些重要搜索功能之前,让我们确切地定义一下“企业搜索”的含义。
什么是企业搜索解决方案?
企业搜索 从表面上看,仅仅是一个为你的网页编制索引的搜索引擎。它的功能使最终用户能够更快地搜索并立即找到信息和产品,例如,比他们使用菜单在文档管理系统中费力地导航要快得多。
你可能认为内容管理方面的经典搜索功能是企业搜索引擎所能提供的全部,但你错了。企业搜索服务不仅仅是从数据库中提取和显示相关结果。
人们日常使用的消费平台上的搜索和发现体验正在不断改善,如 Spotify、谷歌搜索和网飞。这意味着人们期望更多来自 你的 网站的搜索。如果你渴望品牌忠诚度,但你的搜索体验达不到你的客户在其他企业网站上享受的标准,你可能没有办法获得这种忠诚度。
你知道吗,新一代的搜索应用程序甚至可以在用户在自动完成搜索查询中输入第二个字母之前就预测出他们在找什么?这些解决方案可以推荐人们可能感兴趣的商品,甚至在客户开始需要时建议重新订购定期购买的产品。这种量身定制的个性化已经成为黄金标准。
企业搜索须知
当你寻找一个能满足你公司目标的解决方案时,以下是你要记住的一些最重要的问题。
API vs 自制
首先要考虑的是:你有时间、金钱和专业知识来构建自己的搜索解决方案吗?
虽然定制的搜索和内容发现工具可以提供更多的适应和发展自由,但它也需要更多的资源来构建和维护。因此,对许多公司来说,走这条路在经济上或实际上都没有意义。
如果是你,下一个问题是:专业设计和创建的 API 会是最好的企业搜索工具选项吗?
由 搜索专家 设计、构建和维护的 API 往往比在内部组装解决方案更经济。搜索 API 也经常胜过自制的企业搜索解决方案,因为他们有一个完整的组织致力于使它们变得更好。
数据整合
企业搜索最突出的功能之一是能够从多个数据源(如 Salesforce 或 HubSpot)提取详细信息,以通知交互。如果您的平台具有有限的数据集成,您可能无法连接您组织选择的 CRM、CMS 或 KMS,从而使提供 全渠道交互 的任何希望都化为泡影。
人工智能能力
AI 用于管理大部分搜索引擎算法,但也可用于改善其他重要功能。
智能搜索和发现工具使用人工智能来处理来自各种集成的数据,并通过相关搜索通知与客户的营销互动,或 向员工提供相关信息 【通过 API 仪表板】在他们的内联网上搜索。
智能发现
大多数搜索引擎都提供发现功能。如果你曾经有过流媒体服务推荐的音乐或视频,或者注意到产品出现在你的亚马逊主页上,那么你就体验过智能发现工具的使用案例。
发现工具使用来自企业搜索平台的数据,向客户推荐他们可能感兴趣的产品和服务。这是一个很好的方法,可以在有能力的企业搜索的基础上建立更多样化的定位目标。
分析能力
分析是企业搜索中的一项关键功能。它为您的市场营销、销售和客户成功团队提供了关于客户寻求什么的宝贵数据,以帮助通知他们的方法。
例如,如果一个商业购物者在你的 B2B 网站上已经购买了一件商品,并且随后浏览了几件类似的商品,那么给他们打一个销售电话并提供一些折扣价格可能会更有成效。
一些分析功能走得更远。如果你为你的电子商务网站采用——或者想要创建——一个全渠道战略,你可以使用数据分析来更准确地锁定客户,并进行更个性化和更吸引人的互动。
例如,假设您发现越来越多的客户搜索您的在线商店提供的特定产品。在多面发现软件的帮助下,你的营销团队可以创建一个活动来推广相关商品,并在你的网站或应用程序中向你的购物者展示它们。
需要一个完整的企业搜索平台?看看阿尔戈利亚。
- 世界领先的 SaaS 公司信任我们的搜索 API
- 我们的搜索引擎使用先进的机器学习算法
- 我们非常依赖开源软件,并受益于具有前瞻性思维的个人的贡献
- 我们的托管搜索功能和发现 API 提供搜索和推荐服务,为客户(和员工的工作场所搜索)创造惊人的体验
我们的软件允许你只为你使用的东西付费,这样就不需要雇佣专门的搜索团队。这意味着您可以快速部署解决方案,并随着业务增长轻松扩展。
想了解更多?联系 我们的团队 或 免费注册 ,亲身体验我们如何帮助您发展企业业务。
为 Jamstack 选择 API
原文:https://www.algolia.com/blog/engineering/choosing-your-apis-for-jamstack/
所以你想使用第三方 API 来构建你的网络应用。给你这么多选择,你怎么选?
关于 Jamstack 的美妙之处在于,除了提升性能和可伸缩性,它还允许你使用任意数量的第三方 API 来构建你的 web 应用。结果是,你可以为每一项工作插入一流的产品,并在每个专业领域利用持续创新;在某种程度上,这是一种分拆。
考虑实现 Algolia,而不是构建一个定制的全文搜索模块,或者实现 Contentful,而不是处理托管在您必须维护的服务器上的 CMS,或者使用 Netlify 的无缝开发工作流,而不是自己编译源代码并通过 FTP 上传到 web 服务器。此外,这种模式允许您在为堆栈的任何部分找到更好的解决方案时,轻松地切换出单个服务。
当然,随着选择而来的是责任:在有这么多选择的情况下,你应该如何选择要使用的解决方案?
在本帖中,我们将分享为项目选择 API 时需要考虑的 5 个标准。
以下是我们将涉及的要点:
平衡技术质量和业务需求
API 作为解决方案
数据复杂性
智能 UI 策略
策略和支持
平衡技术质量和业务需求
您购买的服务需要完全符合您的架构,但也要与非技术利益相关方的需求保持平衡,因为这是他们将管理的事情。因此,您需要两全其美:一个拥有同样出色的文档的出色的 API,以及一个可访问的功能完整的业务仪表板,同时为两个利益相关者群体保持灵活性和控制力的平衡。
现在,当构建一个软件产品时,所有的事情都是关于权衡的。对于不太成熟的产品,您可能会发现更侧重于开发人员或业务焦点。因此,第一个要求是寻找一个在这两个领域都有能力的相当成熟的提供商,并尽可能减少这种权衡。
API 作为解决方案
就 API 本身而言,寻找 API 不被视为服务,而是解决方案的迹象:
- API 客户端/开发人员工具的维护情况如何,它们使您的集成变得有多容易?寻求灵活性和易用性。
- 供应商提供的功能中有多少可以通过 API 访问?
- 文档有多好?它是简单的功能规范,还是帮助你实现目标的全套资源?当一个 API 是一个解决方案时,文档将是全面的和易于使用的,有许多常见用例的代码样本。一些好的文档示例有 React ,Gatsby,Vue,以及graph QL。除了文档的直观布局和设计之外,这些 API 还使用搜索使开发人员更容易找到她需要的资源。
- 提供商有开发者体验团队吗?在供应商的业务中有专门致力于帮助工程师在实现他们的产品时更有效率的拥护者会有很大的帮助。这表明供应商非常重视这个涉众群体。
数据复杂性
在添加 API 提供者时,您会希望查看数据流和部署过程中增加的任何复杂性。例如,当使用 headless CMS 时,当内容更新时,您需要触发站点的重新部署。在这种情况下,你需要寻找一个关于如何设置 webhooks 的集成指南。在 Algolia 这样的搜索 API 的例子中,当内容被创建或更改时,您需要通过管道将内容发送到搜索 API,当内容被删除时,您需要将内容移除。此外,您的内容可以来自许多不同的来源,如文章、产品等等。
幸运的是,许多 Jamstack 的提供商让这个问题变得很容易解决。一定要检查他们是否有集成到您正在考虑的其他 Jamstack 技术的工具。如果工具之间有直接的集成,那就更好了。例如,如果您正在使用 Algolia with Netlify,您可以利用 Algolia 的 Netlify 插件 来简化上述过程。
智能用户界面策略
当选择 API 优先的提供商时,你需要考虑你的 UI。API 是为了在前端给你自由而构建的,它们尽量不固执于它们将被嵌入的接口。传统上,这意味着您必须构建所有的 UI。 然而,随着服务的成熟,现在很多提供商都提供 UI 组件供开发者使用。在使用服务的 API 客户端时,这些组件通常在接口中实现了最佳实践 UI。
如果你使用一个带有 UI“组件”或“部件”的提供者,就需要考虑权衡。无头方法在设计和用户体验方面提供了自由度和灵活性。使用提供商的小部件为构建前端提供了更快的途径,尽管您通常会失去一些设计定制的自由。您应该如何验证这些工具?寻找智能默认值,以及覆盖 UI 本身的能力,而不丢失组件内置的逻辑。这样,您可以从缺省值开始,并快速发展,而不必在偏离提供商的标准模式太远时重新构建一切。以 Algolia 为例:开发者有能力 扩展小部件 来定制 UI 并保留小部件提供的功能,甚至 通过直接在底层库之上构建来创建定制的小部件 。
政策和支持
由于您可能在您的应用程序中管理多个提供者——可能每个用例一个提供者——从管理的角度来看,您可能希望让您的生活尽可能简单。在这里,您需要考虑每个服务的一些元素:
- SLA——你需要担心的最后一件事就是你的某个提供商倒闭了,但这确实发生了。在这种情况下,您应该将 SLA 视为您业务的保险。您还可以内置辅助故障转移来切换提供者。
- 支持——文档可以让事情变得自助,但是当行动迅速时,一个小小的澄清或问题的一天延迟会让一切变得不同。确保你有一个团队,当你需要他们的时候,特别是在实施阶段。
- 发布政策——当使用许多 API 时,确保任何一个 API 发布更新都不会影响到你的站点是很重要的。即使是 API 客户端中一个不向后兼容的小变化也会对您的实现造成严重破坏。密切关注您的提供商如何发布更新,并确保他们的 API 实际上是兼容的。
- 安全性和合规性——为工作项目选择 API 时,确保您符合公司的安全性和隐私要求。您可能需要一个拥有 SOC2 认证的供应商,并且知道如何以符合 GDPR 标准的方式处理数据。对于电子商务项目,您可能需要研究 PCI 合规性。金融或医疗保健等监管更严格的行业有更多的要求。大多数提供商在其网站上会有一个 安全 或 合规页面 。
作为 Jamstack 的开发人员,这是一个激动人心的时刻。您可以自由选择最适合您正在解决的问题或您正在构建的产品的 API。在未来的几个月和几年里,我们可以期待推出更多的服务。我们希望这个指南能帮助你为你的下一个项目选择正确的 API。
关于作者
Matt 在 Algolia 从事解决方案工程工作,之前曾在通信 API Twilio 和电子商务 and Moltin 工作过。
Sarfaraz Rydhan 是 Netlify 合作伙伴生态系统总监。Sarfaraz 与技术和商业领袖合作,通过使用 JAMstack web 架构帮助公司更好地接触客户。作为一名经验丰富的前软件工程师,Sarfaraz 利用他的技术和运营专业知识来帮助这些公司服务于新的市场,并在考虑清晰的业务成果的情况下做出技术决策。
比较最佳电子商务搜索解决方案
原文:https://www.algolia.com/blog/ecommerce/comparing-the-best-ecommerce-search-solutions/
电子商务 网站搜索 有助于提升访客体验,建立客户忠诚度,提高现场转化率。根据一项 研究 ,使用搜索的访问者创造了所有电子商务网站收入的 30-60%左右。
尽管改进现场搜索有潜在的影响,但只有 15%的公司拥有专门用于优化现场搜索的资源。
亚马逊的利润和电子商务搜索的重要性
全行业的现场转换率徘徊在 3%左右,但 Amazon.com 的转换率是行业平均水平的五倍(对于 Prime 会员来说甚至更高)。在这个世界上最大的市场上,搜索对于寻找任何东西都是至关重要的,因此自然亚马逊 20 年来在搜索工程上投入了大量资金;今天,超过 1500 人在亚马逊网站搜索上工作。
无论你是市场、零售商还是直接与亚马逊竞争的品牌,都有一个好消息:你不需要雇佣成千上万的搜索工程师。今天现成的电子商务搜索引擎技术可以帮你一把,而不会让你倾家荡产。
接下来,我们将讨论两件事:网站搜索的关键要素和帮助你建立良好搜索体验的工具种类。
现代电子商务栈
2021 年,约 50%的零售商 表示,他们计划花更多时间开发自己的网站搜索能力。
更新的搜索解决方案可以取代你的电子商务软件自带的默认搜索引擎,或者允许你在一个无头商务架构中定制搜索。搜索引擎可以很容易地插入以下关键后端应用程序的高度相互依赖的技术栈:
- 电子商务平台/ CMS
- PIM
- 标签标签:一个产品标签解决方案丰富了 medata,使搜索更加准确
- 库存 :管理你的库存的 ERP 系统
- CRM :在所有接触点和互动中存储客户信息的中心位置
- 支付 :在线支付处理解决方案
为了提高效率,搜索需要在构成你的电子商务业务的不同系统中运行。它需要能够搜索您的产品目录,检查您的库存缺货项目,利用客户关系管理的访问者特征,并显示更新的价格信息。另外,它需要在几毫秒内完成所有这些事情。
电子商务搜索的挑战
成功的电子商务搜索需要多方面的方法。下面,我概述了零售商面临的一些关键问题,以及目前广泛可用的解决方案。
正如 Baymard Research 指出的 ,即使是世界上许多最大的零售商和品牌也没有解决一些更基本的搜索挑战,如拼写检查。成功搜索还需要许多其他基本和高级功能。
你的电子商务网站搜索需要的 8 种能力
虽然电子商务网站搜索解决方案拥有许多功能,但以下八项基本功能是你的网站绝对不能缺少的:
1。相关性
首先,解决方案必须向用户提供 上下文相关的 搜索结果,这样他们就可以轻松找到他们要搜索的内容。因此,电子商务搜索引擎必须能够分解复杂的语义和语法,处理同义词和 拼写错误 ,并智能地对结果进行排序。它还必须使您能够根据业务需求、优先级和销售数量、利润等指标对结果进行排序。
更新的 语义搜索 解决方案由 向量 (一种机器学习)提供更加强大的查询处理。通过结合向量搜索和关键字搜索算法(我们称之为混合搜索),零售商可以获得开箱即用的令人难以置信的结果。
2。速度
谷歌和亚马逊都进行了研究,表明即使 100 毫秒的滞后也会对搜索收入产生负面影响。如果网站搜索没有及时地将相关结果返回给客户,那么这些结果就是无用的。今天的互联网用户习惯了快速的结果。速度慢的网站让用户沮丧,驱使他们去竞争对手的网站。电子商务搜索引擎应该优化计算复杂性并减少网络延迟。
为了获得最佳速度和可用性,最好:
- 将自动建议(也称为自动完成)添加到搜索栏,以便在用户键入查询时显示结果,并自动修复输入错误
- 提供带有产品图片的即时搜索
- 当用户选择不同的过滤器和切面时,动态刷新结果
3。可靠性和可扩展性
电子商务网站需要很高的正常运行时间,以确保不同时区的用户可以在一天中的任何时候购物。同样,最好的电子商务搜索解决方案必须高度可用,索引必须是最新的。系统必须能够 扩展 来处理不断增长的目录大小、用户数量和内容类型。
4。与主要电子商务平台的整合
为了避免大量的定制开发工作,网站搜索系统必须能够轻松地与电子商务平台集成,如 Shopify、Magneto、BigCommerce、Salesforce Commerce Cloud 和 WooCommerce。理想情况下,集成应该是一个简单的插件形式,这样营销人员或企业主可以轻松调整排名因素,并根据需要维护系统。
5。分析
大多数企业和电子商务网站运行谷歌分析进行网站优化,它们包含的关于你的网上商店的数据非常 有价值 ,但并不总是 有帮助 。 网站搜索解决方案附带的搜索分析可以根据转化率和错失的机会,为您的目录确定具体的搜索词和改进查询。
电子商务运营商必须能够跟踪转换指标,如不返回结果、不导致销售或其他重要行为的关键字。一个站点搜索系统应该让非技术用户容易 监控和分析站点搜索数据 。
6。个性化
除了显示用户查询的相关结果,网站搜索系统还应该提供与特定用户查询相关的结果。例如,如果一个服装品牌的客户只购买女装,那么可以合理地假设她将来会对女装感兴趣,并且可以优先搜索结果以首先显示这些商品。个性化可以增加客户对品牌的信任,并为交叉销售和追加销售创造机会。
7。实验和测试
体验上的小变化会对转化率产生很大影响。因此,一个站点搜索系统应该允许 A/B 测试 ,这样你就可以在向所有搜索者发布之前测试出变化和改进。系统还应该确保测试随机分配给用户,以避免引入任何其他可能给测试增加统计噪声的偏差。
8。内置销售工具
商品销售 工具允许电子商务企业策划和推广特定的产品或产品类别。这可以通过在搜索结果中显示某些促销产品,以及通过用不同的 UI 组件强调促销来实现。网站搜索系统应该允许配置搜索规则,以方便地运行这些类型的促销活动。
对比顶级电子商务搜索部署选项
这八种能力构成了一个成功的网站搜索解决方案的基础。现在让我们来看看三个主要的供应商群体,以及他们能给电子商务网站带来的好处。
现成的解决方案
许多主要的第三方平台都提供现成的电子商务网站搜索。他们可以直接集成到电子商务平台,如 Shopify 和 Magento,只需最少的技术专业知识或配置,提供用户期望的一般功能,而无需大量的开发开销。提供商包括 Cludo、Site Search 360、AddSearch、HawkSearch 等。
现成解决方案的优点
易于部署: 开箱即用解决方案的最大优势是快速、易于设置,并且易于插入电子商务平台,只需最少的前期配置或定制。
用户友好的仪表板和分析: 这些工具通常提供有用的仪表板,用于分析常见的搜索查询,以帮助电子商务运营商调整他们的产品供应,以适应用户的口味。通过专门针对电子商务用例定制体验,这些仪表板立即变得相关,并且不需要定制配置。
现成解决方案的缺点
有限的可定制性: 即插即用的解决方案是通用的,不针对特定的业务案例。提供者对用例做了许多假设,这些假设限制了灵活性和可以内置到系统中的个性化数量,从而为客户提供更多上下文相关的内容。定制商店的搜索用户界面可能会很困难,这使得它很难适应您的品牌。
有限的搜索功能: 举例来说,如果你想索引 其他类型的内容——比如博客帖子、视频和常见问题——那么你可能会遇到专门为索引产品和产品类别而构建的现成解决方案的问题。处理其他类型的内容超出了这些产品的范围。
搜索是一个黑匣子:现成的解决方案实际上是黑匣子,很难说明为什么搜索会以某种方式排序,或者它们是如何处理复杂的搜索查询的。对于需要能够定制和调整搜索结果以提供更准确结果的特定领域行业来说,这尤其是一个问题。
电子商务解决方案
一些现成的产品,如 Klevu、SearchSpring 和 Nextopia,宣称自己是专门针对电子商务的。
虽然这可能意味着搜索工具可以支持额外的 UX,用于按类别或推荐产品过滤搜索,但这并不总是意味着它最适合您的使用案例。
这些电子商务专用工具有时缺乏顶级电子商务网站推动转化所需的关键个性化功能和营销工具。这极大地限制了推广合作伙伴产品、推出新产品线或引导用户购买高利润商品的能力。任何大型电子商务公司都知道,这些是品牌长期发展的重要工具。
搜索即服务
搜索即服务 产品为在线商店提供快速部署,同时为不同的使用案例和定制提供更大的灵活性。这些产品处理索引和技术维护的所有复杂性,使运营商能够专注于微调他们的结果,并为客户提供丰富的相关搜索体验。Algolia是搜索即服务解决方案的一个例子。
【搜索即服务解决方案的利弊】
多渠道用户体验: 搜索即服务产品通常会提供出色的多渠道用户体验。这不仅包括桌面和移动,还包括移动应用、语音搜索,甚至店内。随着搜索成为客户导航和探索体验的核心,这可能是非常有价值和成本效益的。
可能的重要定制: 这些产品中的大多数都允许对用户界面和搜索相关性进行重要定制。例如,自定义排名和同义词可以让电子商务运营商将搜索结果调整为更加特定的领域,并向用户提供上下文相关的结果。此外,不同的内容类型可以集成到搜索结果中,以允许用户浏览整个网站,而不仅仅是产品。
搜索即服务解决方案的弊端
需要一些技术能力: 实现搜索即服务确实需要一些技术能力来实现和定制。然而,实现它们通常不需要任何搜索经验。相反,开发人员只需要知道如何集成 SDK 或 API,并进行一些简单的编程来配置和嵌入前端组件。
持续成本: 由于这些是托管产品,它们需要持续的订阅费来支付基础设施和使用成本。这项费用还包括持续创新和发布新功能的成本。虽然搜索即服务工具的费用可能高于现成的工具,但电子商务网站可以获得规模效益:与自己构建和维护工具相比,搜索即服务通常可以以更低的拥有成本提供最先进的功能和增强功能。
开源解决方案
创建网站搜索最灵活的方式是使用开源工具,如 ElasticSearch 和 Solr。这些工具是非常可定制的,并且通常有强大的开发人员社区来帮助解决开发中的技术问题。
开源解决方案的利弊
终极灵活性和控制: 开源搜索解决方案的主要优势是可以灵活地编写任何用例。有了足够的开发人员知识,可以定制和调整工具,使搜索与最终用户非常相关。
初始托管和基础设施: 此外,可以优化托管以降低持续成本。例如,在测试和开发系统时,搜索集群可以运行在一台小型虚拟机上,这将比托管搜索解决方案的订阅费用更便宜。但是,请注意,以经济高效的方式扩展这些系统需要丰富的技术经验,因为它们是复杂的分布式系统,有许多会影响可用性的故障模式。
开源方案的弊端
技术专长和诀窍: 利用开源技术开发搜索系统的主要问题是,开发人员不仅需要从零开始构建系统,还需要大量的经验和时间来持续维护和操作系统。具有这种专业水平的开发团队是昂贵的,并且必须努力适当地扩展系统以确保高水平的可靠性和可用性。
功能必须从零开始构建: 开源解决方案中没有任何 UX 工具或其他解决方案的后端功能(如销售或个性化),因此这些功能也必须构建和维护。这不仅成本高昂,而且需要不断开发,以确保系统的每个组件都符合行业标准。
正在进行的开发: 开源解决方案缺乏好的方法去迭代和实验。每当一个业务用户想要尝试一个新的特性或者甚至做一个小的改变,他们将不得不与开发团队一起工作来确定项目的范围,并且可能需要等待特性被开发、测试和部署。这可能会严重拖累经济增长。
寻找你的电子商务网站搜索伙伴
丰富的搜索栏体验对于任何电子商务企业的成功都是至关重要的。Algolia 提供了所有必要的工具,以快速和成本效益实施成功的电子商务网站的网站搜索。看看 Algolia 如何通过一个 个性化演示 帮助您的电子商务网站成长。