<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Item Cold Start | John Nessime</title>
	<atom:link href="https://john-nessime.com/blog/tag/item-cold-start/feed/" rel="self" type="application/rss+xml" />
	<link>https://john-nessime.com/blog/tag/item-cold-start/</link>
	<description>Cloud, DevOps, Data &#38; AI — Built, Tested, Explained</description>
	<lastBuildDate>Mon, 26 Oct 2026 06:37:42 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.1.4</generator>

<image>
	<url>https://john-nessime.com/blog/wp-content/uploads/2026/07/cropped-jn-32x32.png</url>
	<title>Item Cold Start | John Nessime</title>
	<link>https://john-nessime.com/blog/tag/item-cold-start/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Building an Ecommerce Recommendation Pipeline on AWS: The Parts That Bite</title>
		<link>https://john-nessime.com/blog/cloud-computing/aws-ecommerce-recommendation-pipeline/</link>
		
		<dc:creator><![CDATA[John Nessime]]></dc:creator>
		<pubDate>Mon, 26 Oct 2026 06:37:42 +0000</pubDate>
				<category><![CDATA[Cloud Computing]]></category>
		<category><![CDATA[Data Engineering]]></category>
		<category><![CDATA[Machine Learning]]></category>
		<category><![CDATA[Retail Technology]]></category>
		<category><![CDATA[Amazon Personalize]]></category>
		<category><![CDATA[Amazon S3]]></category>
		<category><![CDATA[AWS]]></category>
		<category><![CDATA[AWS Lambda]]></category>
		<category><![CDATA[Batch Processing]]></category>
		<category><![CDATA[Clickstream Ingestion]]></category>
		<category><![CDATA[Cost Optimization]]></category>
		<category><![CDATA[Ecommerce Analytics]]></category>
		<category><![CDATA[Idle Resources]]></category>
		<category><![CDATA[Item Cold Start]]></category>
		<category><![CDATA[Kinesis Data Streams]]></category>
		<category><![CDATA[Model Serving]]></category>
		<category><![CDATA[Recommendation Systems]]></category>
		<category><![CDATA[Schema Design]]></category>
		<category><![CDATA[Training-Serving Skew]]></category>
		<guid isPermaLink="false">https://john-nessime.com/blog/?p=894</guid>

					<description><![CDATA[<p>An idle Amazon Personalize setup does not throw errors. It just bills. A practical walkthrough of the five decisions that shape an AWS ecommerce recommendation pipeline: domain recommenders versus custom recipes, bulk versus streaming ingestion, schema limits, training cadence, and real-time versus batch serving, with the failure modes that stay invisible until the invoice arrives.</p>
<p>The post <a href="https://john-nessime.com/blog/cloud-computing/aws-ecommerce-recommendation-pipeline/">Building an Ecommerce Recommendation Pipeline on AWS: The Parts That Bite</a> appeared first on <a href="https://john-nessime.com/blog">John Nessime</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">The question usually arrives from finance rather than from engineering. Something along the lines of: why is there an Amazon Personalize charge on an account where nobody has shipped a recommendation carousel yet?</p>



<p class="wp-block-paragraph">The answer is almost always the same. Someone followed a tutorial, created a dataset group, trained a solution, deployed a campaign to see if the output looked reasonable, then got pulled onto something else. The campaign is still holding a throughput floor. The solution is still retraining on a schedule. Neither is wired to a storefront. Both are billing.</p>



<p class="wp-block-paragraph">I want that failure mode first because it is invisible. A broken AWS ecommerce recommendation pipeline throws errors and gets fixed by Friday. An idle one throws nothing. It sits there being technically correct and quietly expensive.</p>



<p class="wp-block-paragraph">This post covers the five decisions that actually shape the pipeline: which resource type to train, how events get in, what the schema can hold, how fresh the model needs to be, and how a recommendation reaches the page. I will flag the spots where the default behavior is not the behavior you want.</p>



<h2 class="wp-block-heading">The bill arrives before the carousel does</h2>



<p class="wp-block-paragraph">Two things in Personalize cost money on a clock rather than on demand, and both default toward spending.</p>



<p class="wp-block-paragraph"><strong>Solution training.</strong> New custom solutions use automatic training by default. Personalize creates a new solution version every seven days unless you say otherwise, and the cadence is configurable between one and thirty days. The first run starts within an hour of the solution going active. AWS is explicit that you incur training costs while the solution is active, and that switching automatic training off is how you stop them.</p>



<p class="wp-block-paragraph"><strong>Inference capacity.</strong> A campaign has <code>minProvisionedTPS</code>, a domain recommender has <code>minRecommendationRequestsPerSecond</code>. Both default to 1. Both set a billing floor. Personalize scales above the floor as traffic climbs but never below it, and you are billed on the higher of the floor and your actual rate. A campaign serving zero requests still bills its floor for every hour it stays active.</p>



<p class="wp-block-paragraph">Two habits fix most of this. While you are evaluating rather than serving, create solutions with automatic training off and trigger training yourself. And delete campaigns you are not calling instead of leaving them parked.</p>



<pre class="wp-block-code"><code>import boto3

personalize = boto3.client('personalize')

# Automatic training off while evaluating.
# You then call create_solution_version() yourself when you want a model.
response = personalize.create_solution(
    name='storefront-user-personalization',
    datasetGroupArn='arn:aws:personalize:REGION:ACCOUNT:dataset-group/NAME',
    recipeArn='arn:aws:personalize:::recipe/aws-user-personalization-v2',
    performAutoTraining=False
)
print(response['solutionArn'])</code></pre>



<h2 class="wp-block-heading">Decision one: domain recommender or custom solution</h2>



<p class="wp-block-paragraph">A domain dataset group created with the ECOMMERCE domain exposes pre-configured use cases. A custom dataset group makes you pick a recipe and configure the solution yourself.</p>



<p class="wp-block-paragraph">The ECOMMERCE use cases map onto the modules you were going to build anyway: Recommended for you, Frequently bought together, Customers who viewed X also viewed, Best sellers, Most viewed. Each carries an event-type requirement. The purchase-driven ones need at minimum a thousand Purchase events; the view-driven ones need at minimum a thousand View events. That is a useful early check on your event taxonomy, before you spend a training run finding out.</p>



<p class="wp-block-paragraph">Where the domain route wins: you skip the recipe argument, the defaults are sensible, and you reach a testable result faster. For a catalog under a few thousand SKUs with a normal retail event mix, this is the one I reach for first.</p>



<p class="wp-block-paragraph">Where it hurts: you are constrained to the shape of the provided use cases, you get less control over hyperparameters, and you cannot create next best action resources inside a domain dataset group at all. If you need to recommend actions rather than products, you are in custom territory.</p>



<p class="wp-block-paragraph">On the custom side the recipes worth knowing are User-Personalization-v2 for a personalized feed, Similar-Items for a related-products rail, Personalized-Ranking-v2 for reordering a category or search page, Trending-Now for what is moving, and Popularity-Count as the baseline you should measure against. The v2 recipes use a transformer architecture, handle much larger catalogs, and return item metadata in the inference response, saving a catalog lookup on the render path. They also bill on a different model from the older recipes, so do not carry a cost estimate across.</p>



<p class="wp-block-paragraph">One thing to watch while reading around: the legacy HRNN recipes are no longer available. Their documentation stays online for reference and plenty of third-party tutorials still use them. If a guide points a solution at <code>aws-hrnn</code>, its advice about cold items and training cadence is stale too.</p>



<h2 class="wp-block-heading">Decision two: how interaction data gets in</h2>



<h3 class="wp-block-heading">Bulk imports replace unless you tell them not to</h3>



<p class="wp-block-paragraph">This is the one that costs people a month of confused model quality.</p>



<p class="wp-block-paragraph">A dataset import job defaults to <code>FULL</code>, which overwrites all existing bulk data in the dataset. It leaves records you sent individually through the event tracker alone, but everything previously loaded from S3 is replaced by whatever is in this job. The alternative is <code>INCREMENTAL</code>, which appends and only replaces records sharing an ID.</p>



<p class="wp-block-paragraph">Picture a nightly export producing a rolling thirty-day extract, fed into an import job left on the default. Every night the dataset is truncated to thirty days. Nothing errors. The job reports success. Model quality just degrades as the training window shrinks, and it is not obvious why, because the pipeline is green.</p>



<pre class="wp-block-code"><code>import boto3

personalize = boto3.client('personalize')

# INCREMENTAL appends to what is already there.
# FULL, the default, replaces all previously bulk-imported records.
personalize.create_dataset_import_job(
    jobName='interactions-nightly',
    datasetArn='arn:aws:personalize:REGION:ACCOUNT:dataset/NAME/INTERACTIONS',
    dataSource={'dataLocation': 's3://your-bucket/interactions/'},
    roleArn='arn:aws:iam::ACCOUNT:role/PersonalizeS3Role',
    importMode='INCREMENTAL'
)</code></pre>



<p class="wp-block-paragraph">Two limits shape the schedule. An incremental interactions import is capped well below a full one, so treat it as a delta mechanism and not a backfill. And an interactions import job needs a minimum number of new records to be accepted, so a low-traffic store cannot run one every fifteen minutes and expect success. Batch the deltas into a cadence that clears the floor.</p>



<h3 class="wp-block-heading">Streaming events through an event tracker</h3>



<p class="wp-block-paragraph">The live path is a separate API. Create an event tracker, take the tracking ID it returns, and call PutEvents against the <code>personalize-events</code> client.</p>



<pre class="wp-block-code"><code>import boto3
import time

personalize_events = boto3.client('personalize-events')

personalize_events.put_events(
    trackingId='YOUR_TRACKING_ID',
    userId='user-8842',
    sessionId='sess-19f3ac',
    eventList=[{
        'eventId': 'evt-1',
        'eventType': 'View',
        'itemId': 'SKU-4471',
        'sentAt': int(time.time())
    }]
)</code></pre>



<p class="wp-block-paragraph">Do not put that call inline in the request path of a product page. Recommendation telemetry is not worth a network round trip on your time to first byte, and it is certainly not worth a page error when the API has a bad minute. Push events onto Kinesis Data Streams or Amazon Data Firehose, drain with Lambda, call PutEvents from there.</p>



<p class="wp-block-paragraph">That indirection buys a second thing you want anyway: Firehose can land a durable copy of the same events in S3, which becomes the source for bulk imports and for analysis outside Personalize. Events that only ever existed inside a managed service are events you cannot re-examine when the model does something odd.</p>



<p class="wp-block-paragraph">The <code>sessionId</code> field matters more than it looks. It lets you record anonymous browsing before login and have Personalize associate that session with the user afterward. Skip it and you train on your smallest, least representative slice of traffic.</p>



<h2 class="wp-block-heading">Decision three: schema and event types, decided once</h2>



<p class="wp-block-paragraph">Personalize schemas are Avro. An interactions schema needs a user ID, an item ID and a timestamp. An event type field is optional, but the domain use cases key off it, so you want it.</p>



<pre class="wp-block-code"><code>{
  "type": "record",
  "name": "Interactions",
  "namespace": "com.amazonaws.personalize.schema",
  "fields": [
    { "name": "USER_ID",    "type": "string" },
    { "name": "ITEM_ID",    "type": "string" },
    { "name": "EVENT_TYPE", "type": "string" },
    { "name": "TIMESTAMP",  "type": "long" }
  ],
  "version": "1.0"
}</code></pre>



<p class="wp-block-paragraph">The budget for extra fields is tighter than people expect. An interactions dataset allows only a handful of metadata columns beyond the reserved fields, and the count of distinct event types plus those metadata columns is itself capped. That is a hard design constraint. You cannot ship twenty-eight granular event types and also carry rich per-event context.</p>



<p class="wp-block-paragraph">Spend it deliberately. View, AddToCart and Purchase carry most retail pipelines. Wishlist adds earn a slot if customers use them. Hover, scroll depth and image zoom do not, because they inflate volume without changing what the model learns about intent. Once you have several event types you can weight them differently at training time, which beats the alternative people reach for first, which is dropping views entirely.</p>



<p class="wp-block-paragraph">Before any of that, settle the item ID question. Variants and parent products are different objects in Shopify and WooCommerce alike, and a model trained on variant IDs will happily suggest the blue medium of a shirt the customer already owns in blue medium. Pick a level, write it down, use the same one in your bulk extract and your live payload. Getting those out of step is the most common reason a technically healthy pipeline produces recommendations that feel broken.</p>



<p class="wp-block-paragraph">On volume: the documented floor is a thousand item interactions from at least twenty-five unique users with two or more interactions each, plus a minimum share of your user base clearing that two-interaction bar. AWS recommends considerably more for quality. Near the minimum, the honest read is that you are not building a recommendation pipeline yet. You are building the event capture that lets you build one later, and a popularity-ranked rail will serve customers better meanwhile.</p>



<p class="wp-block-paragraph">Timestamps are Unix time. Mixed timezones, or milliseconds where seconds are expected, will not throw. They will scramble the ordering the model learns from, which is the entire signal.</p>



<h2 class="wp-block-heading">Decision four: freshness without a retraining bill</h2>



<p class="wp-block-paragraph">Two mechanisms get conflated constantly, and the difference sets your monthly cost.</p>



<p class="wp-block-paragraph"><strong>Automatic training</strong> creates a new solution version. The model learns from your latest data. It costs a training run each time.</p>



<p class="wp-block-paragraph"><strong>Automatic updates</strong> are something else entirely. For User-Personalization-v2, User-Personalization and Next-Best-Action, and for the Top picks for you and Recommended for you domain use cases, Personalize refreshes the deployed model every two hours so new items can surface through exploration. That is not retraining. The model does not learn from your recent interactions. It just stops new products from being structurally invisible.</p>



<p class="wp-block-paragraph">So automatic updates solve the cold item problem and do nothing about model drift. AWS&#8217;s own guidance is that even with them, training cadence should stay at least weekly.</p>



<p class="wp-block-paragraph">Trending-Now is the interesting exception. It evaluates interactions over a configurable interval and identifies what is climbing, without waiting for a training run. For a store with promotional spikes or seasonal churn, a Trending-Now rail beside a personalized rail covers a lot of ground for very little retraining.</p>



<p class="wp-block-paragraph">The trap is Similar-Items, which has no automatic updates. Add products daily, run a related-products rail on Similar-Items, and new products only appear after the next training. Same-day visibility means daily training. That is a real budget line, and it is the point where catalog velocity stops being a merchandising detail and becomes an infrastructure decision.</p>



<h2 class="wp-block-heading">Decision five: how the recommendation reaches the page</h2>



<p class="wp-block-paragraph">Real-time means a campaign or a recommender answering GetRecommendations. Batch means an inference job reading input from S3 and writing recommendations back to S3, with no campaign involved and therefore no throughput floor.</p>



<p class="wp-block-paragraph">Most small and mid-sized stores reach for real-time by reflex and do not need it. Ask what the module actually is. A homepage rail refreshed daily, an email send, a merchandising export: those are batch problems. Run the batch overnight, load results into DynamoDB or a Redis instance, serve the carousel from a key lookup. Single-digit millisecond reads, no per-request inference charge, and nothing sitting idle at three in the morning.</p>



<p class="wp-block-paragraph">Real-time earns its cost where the recommendation has to react inside the session, which in practice means product detail and cart pages.</p>



<p class="wp-block-paragraph">Two things belong in the serving layer from day one either way. Filters, so you can exclude out-of-stock items and things the customer already bought; note that Personalize considers a bounded number of interactions per user per event type when filtering, and a user with no imported interactions for several months stops counting toward filtering at all. And a timeout with a fallback, because a carousel must never be able to delay a product page. Fall back to a cached bestseller list and log the fallback rate as a metric, so a rise shows up in CloudWatch or Grafana rather than in a conversion report a fortnight later.</p>



<h2 class="wp-block-heading">Troubleshooting an AWS ecommerce recommendation pipeline</h2>



<ul class="wp-block-list">
<li><strong>Everyone gets the same recommendations.</strong> Usually too few interactions per user, or user IDs that are not stable across sessions. Check that anonymous activity is recorded with a session ID and reconciled at login.</li>



<li><strong>New products never show up.</strong> Check that your recipe supports automatic updates. If it does not, this is a training cadence problem, not a data problem.</li>



<li><strong>Training fails on data volume.</strong> Compare against the documented minimums. The share of users with two or more interactions catches people out: plenty of users is not the same as plenty of returning users.</li>



<li><strong>The dataset shrank and nothing errored.</strong> A bulk import running in FULL mode against a rolling extract. Check the import mode on every scheduled job.</li>



<li><strong>Recommendations ignore what the user just clicked.</strong> Confirm events reach the event tracker, and that the user ID sent to PutEvents matches the one sent to GetRecommendations exactly.</li>



<li><strong>The bill rose during a quiet week.</strong> Automatic training runs on a calendar, not on traffic. Check cadence, and check for campaigns nobody is calling.</li>



<li><strong>Filters are not excluding purchased items.</strong> Filtering looks at a bounded slice of each user&#8217;s history per event type. Heavy users push older purchases outside it.</li>
</ul>



<p class="wp-block-paragraph">Auditing an account you did not build starts with listing what exists, not with reading the application code.</p>



<pre class="wp-block-code"><code>aws personalize list-dataset-groups
aws personalize list-solutions --dataset-group-arn ARN
aws personalize list-campaigns --solution-arn ARN
aws personalize list-recommenders --dataset-group-arn ARN

# Then see what each campaign is holding open
aws personalize describe-campaign --campaign-arn ARN</code></pre>



<p class="wp-block-paragraph">Orphaned campaigns from an abandoned proof of concept show up in that output in about ninety seconds.</p>



<h2 class="wp-block-heading">Common mistakes</h2>



<ul class="wp-block-list">
<li>Leaving automatic training on for a solution that exists only to satisfy curiosity.</li>



<li>Raising the provisioned throughput floor for a traffic spike, then never lowering it afterward.</li>



<li>Modelling on variant IDs in the bulk extract and product IDs in the live events, or the reverse.</li>



<li>Recording events only for authenticated users, starving the model of most of your traffic.</li>



<li>Designing a rich event taxonomy that collides with the cap on event types plus metadata columns.</li>



<li>Calling PutEvents synchronously on the render path.</li>



<li>Following an implementation guide that still references the retired HRNN recipes.</li>



<li>Shipping with no fallback, so the first slow inference call becomes a slow product page.</li>
</ul>



<h2 class="wp-block-heading">Best practices</h2>



<ul class="wp-block-list">
<li>Keep a raw copy of every interaction event in S3, independent of Personalize. Managed services are easier to reason about when you can replay what you sent them.</li>



<li>Start with a domain dataset group. Move to custom recipes when you can name the specific thing the domain route will not do.</li>



<li>Measure against a popularity baseline before celebrating anything. If a personalized rail cannot beat bestsellers, the pipeline is not earning its cost yet.</li>



<li>Set training cadence from catalog velocity, not from habit. A stable catalog of a few hundred products does not need what a weekly fashion drop needs.</li>



<li>Prefer batch inference plus a cache for anything that does not have to react within the session.</li>



<li>Alarm on idle inference resources. Utilization near zero for days is a cost bug, and it is the only bug here that never pages anyone.</li>



<li>Keep the staging storefront on cheap infrastructure. The application side of this runs fine on a modest VPS from a provider like Contabo or InterServer while you are still shaping the event schema, and it keeps experiments off the production account.</li>
</ul>



<h2 class="wp-block-heading">Frequently asked questions</h2>



<h3 class="wp-block-heading">How much data do I need before Personalize is worth it?</h3>



<p class="wp-block-paragraph">The documented training floor is a thousand item interactions from at least twenty-five unique users with two or more interactions each, and AWS recommends substantially more for quality recommendations. Below that, popularity ranking and hand-curated rails serve customers better and cost nothing to run.</p>



<h3 class="wp-block-heading">Can I build this without Amazon Personalize?</h3>



<p class="wp-block-paragraph">Yes, and for some shops you should. Item-to-item collaborative filtering over purchase history is a modest amount of code and runs fine as a scheduled job writing to a cache. You give up cold-start handling, exploration and session-level personalization. You gain a near-zero cost and full visibility into why an item was recommended.</p>



<h3 class="wp-block-heading">What does an idle Personalize setup cost?</h3>



<p class="wp-block-paragraph">More than zero, which is the surprising part. An active campaign bills its provisioned throughput floor whether or not anyone calls it, and a solution with automatic training on bills a training run on its cadence regardless of traffic. Rates change, so apply current pricing yourself, but the shape is a floor plus a recurring training charge.</p>



<h3 class="wp-block-heading">Real-time or batch recommendations?</h3>



<p class="wp-block-paragraph">Batch unless the module has to respond to the current session. Homepage rails, email and merchandising exports are batch problems. Product detail and cart pages are where real-time inference genuinely changes what the customer sees.</p>



<h3 class="wp-block-heading">Do new products appear automatically?</h3>



<p class="wp-block-paragraph">Only with recipes that support automatic updates, or with Trending-Now. Automatic updates refresh the deployed model every couple of hours so new items can be explored, but they do not retrain it. With a recipe like Similar-Items, a new product waits for the next training run.</p>



<h3 class="wp-block-heading">How do I connect a Shopify or WooCommerce store?</h3>



<p class="wp-block-paragraph">There is no first-party connector. Emit events from the storefront to your own endpoint, push them onto a stream, and call PutEvents from a consumer. For history, export orders and product views to S3 and load them with a dataset import job. Ordinary plumbing; the hard part is settling the item ID question first.</p>



<h3 class="wp-block-heading">How often should I retrain?</h3>



<p class="wp-block-paragraph">At least weekly is the documented baseline, even for recipes with automatic updates. Go faster only when your catalog turns over faster, and price the extra training runs before committing to a daily cadence.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">The one thing worth remembering</h2>



<p class="wp-block-paragraph">An AWS ecommerce recommendation pipeline runs two clocks, and they are easy to mistake for one. The freshness clock decides whether a customer can see the product you added this morning. The billing clock runs on training cadence and provisioned throughput, and it keeps running when nobody is looking at the site at all.</p>



<p class="wp-block-paragraph">Get the event schema right, keep a raw copy of everything in S3, stay on batch until the session genuinely demands otherwise, and set training cadence from how fast your catalog actually moves. Do that and the rest is straightforward. Skip it and you end up with something that works, costs more than the revenue it lifts, and nobody can say why.</p>



<h2 class="wp-block-heading">Need a second pair of eyes on your recommendation pipeline?</h2>



<p class="wp-block-paragraph">This is the kind of work I do for ecommerce teams building on AWS:</p>



<ul class="wp-block-list">
<li>Auditing an existing Personalize setup for orphaned campaigns, over-provisioned throughput floors and training cadences that outrun the catalog.</li>



<li>Designing the event schema and item ID strategy before you commit, including the variant-versus-product decision for Shopify and WooCommerce catalogs.</li>



<li>Building the ingestion path: storefront events through Kinesis or Firehose into Lambda, with a durable S3 copy for bulk imports and replay.</li>



<li>Choosing between domain recommenders and custom recipes for your catalog size and event mix, and modelling what each costs to run.</li>



<li>Moving eligible modules from real-time campaigns to batch inference plus a cache layer, then measuring what that takes off the bill.</li>



<li>Setting up monitoring so idle inference capacity and rising fallback rates surface as alerts rather than as a surprise invoice.</li>
</ul>



<p class="wp-block-paragraph">If something is already running, send me your dataset import job configuration and a list of your active campaigns, and I will tell you what I would change first.</p>



<div class="wp-block-buttons is-layout-flex wp-block-buttons-is-layout-flex">
<div class="wp-block-button"><a class="wp-block-button__link wp-element-button" href="https://www.upwork.com/freelancers/~01f15a912ad84a6620" target="_blank" rel="noreferrer noopener">Work with me on Upwork</a></div>
</div>
<p>The post <a href="https://john-nessime.com/blog/cloud-computing/aws-ecommerce-recommendation-pipeline/">Building an Ecommerce Recommendation Pipeline on AWS: The Parts That Bite</a> appeared first on <a href="https://john-nessime.com/blog">John Nessime</a>.</p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
