<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
    <channel>
      <title>Reference Architecture for AI</title>
      <link>https://reference-architecture.ai</link>
      <description>Reference architecture patterns for production AI agent systems. Harness engineering, context architecture, execution guardrails, and memory infrastructure.</description>
      <generator>Zola</generator>
      <language>en</language>
      <atom:link href="https://reference-architecture.ai/rss.xml" rel="self" type="application/rss+xml"/>
      <lastBuildDate>Tue, 08 Sep 2026 00:00:00 +0000</lastBuildDate>
      <item>
          <title>Support the project</title>
          <pubDate>Tue, 08 Sep 2026 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://reference-architecture.ai/docs/donate/</link>
          <guid>https://reference-architecture.ai/docs/donate/</guid>
          <description xml:base="https://reference-architecture.ai/docs/donate/">&lt;p&gt;The patterns described on this site are not theory. They are extracted from
&lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://terraphim.ai&quot;&gt;Terraphim&lt;/a&gt;, a privacy-first AI assistant built across 52 Rust
crates, and every one of those crates is open source.&lt;/p&gt;
&lt;p&gt;The most valuable support is use and scrutiny.&lt;/p&gt;
&lt;h2 id=&quot;use-it&quot;&gt;Use it&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://terraphim.ai&quot;&gt;terraphim.ai&lt;/a&gt;&lt;/strong&gt; — the assistant itself: local-first, your data
stays on your device.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://terraphim.rs&quot;&gt;terraphim.rs&lt;/a&gt;&lt;/strong&gt; — the engine: 52 crates, each with a single
responsibility and usable independently. Start with
&lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://docs.rs/terraphim_automata&quot;&gt;&lt;code&gt;terraphim_automata&lt;/code&gt;&lt;/a&gt; for Aho-Corasick matching,
&lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://docs.rs/terraphim_rolegraph&quot;&gt;&lt;code&gt;terraphim_rolegraph&lt;/code&gt;&lt;/a&gt; for role-based knowledge
graphs, or &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://docs.rs/terraphim_persistence&quot;&gt;&lt;code&gt;terraphim_persistence&lt;/code&gt;&lt;/a&gt; for the
storage layer.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;contribute&quot;&gt;Contribute&lt;/h2&gt;
&lt;p&gt;Issues, benchmarks and architecture critique are worth more than money here. If a
trade-off on this site looks wrong, say so — with evidence — at
&lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://github.com/terraphim&quot;&gt;github.com/terraphim&lt;/a&gt;. Deployment guides and reproducible
benchmarks are especially welcome.&lt;/p&gt;
&lt;h2 id=&quot;sponsor&quot;&gt;Sponsor&lt;/h2&gt;
&lt;p&gt;If your organisation depends on this work, &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://terraphim.pro&quot;&gt;Terraphim Pro&lt;/a&gt; funds
the open-source engine directly: connectors, an LLM proxy and agentic skills for
enterprise deployment.&lt;/p&gt;
</description>
      </item>
      <item>
          <title>The Twelve Core Patterns</title>
          <pubDate>Tue, 08 Sep 2026 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://reference-architecture.ai/docs/patterns/</link>
          <guid>https://reference-architecture.ai/docs/patterns/</guid>
          <description xml:base="https://reference-architecture.ai/docs/patterns/">&lt;p&gt;The harness, not the model, determines agent success. A harness has three jobs — deciding
what the model sees, enforcing what it can do, and ensuring it learns from its own history
— and each job is served by four patterns.&lt;/p&gt;
&lt;p&gt;Every pattern below is documented elsewhere on this site. This page is the index, not the
explanation: each entry links to where the argument is actually made.&lt;/p&gt;
&lt;h2 id=&quot;context-architecture&quot;&gt;Context Architecture&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;What the model sees at each step.&lt;/em&gt; Context is a scarce resource: a 1M token window with
800K of noise performs worse than 200K with 150K of curated signal.&lt;/p&gt;
&lt;h3 id=&quot;1-structural-context-boundary&quot;&gt;1. Structural Context Boundary&lt;/h3&gt;
&lt;p&gt;Put the boundary in configuration, not in a runtime permission check. A role has access
to certain sources; the knowledge graph is built from those sources; the agent therefore
cannot reach anything outside its role. Not a check that could be bypassed — an absence.
The data was never loaded.&lt;/p&gt;
&lt;p&gt;→ &lt;a href=&quot;https://reference-architecture.ai/posts/terraphim-engine-architecture/#layer-1-types-and-configuration&quot;&gt;The Terraphim Engine, Layer 1&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;2-deterministic-concept-matching&quot;&gt;2. Deterministic Concept Matching&lt;/h3&gt;
&lt;p&gt;Resolve text to concepts with finite state automata rather than vector similarity.
Aho-Corasick finds every match in O(n) time, with the same result every run. Probabilistic
retrieval gives you a different context window each time you ask, which makes every
downstream failure irreproducible.&lt;/p&gt;
&lt;p&gt;→ &lt;a href=&quot;https://reference-architecture.ai/posts/mcp-native-agent-architecture/#layer-2-knowledge-graph&quot;&gt;The MCP-Native Agent Architecture, Layer 2&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;3-structured-compaction&quot;&gt;3. Structured Compaction&lt;/h3&gt;
&lt;p&gt;Compact before the window fills, not when it overflows. By 100K tokens a working context
is largely noise: superseded search results, abandoned reasoning paths, old file reads.
Adding capacity without compaction makes performance worse, not better.&lt;/p&gt;
&lt;p&gt;→ &lt;a href=&quot;/#failures&quot;&gt;Three ways 1M token windows fail&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;4-priority-weighted-instruction-injection&quot;&gt;4. Priority-Weighted Instruction Injection&lt;/h3&gt;
&lt;p&gt;Instructions compete, and by default the loudest wins rather than the most important. The
system prompt says one thing, the project file another, the README a third. Weight them
explicitly and re-inject the high-priority ones, rather than trusting position in a
transcript.&lt;/p&gt;
&lt;p&gt;→ &lt;a href=&quot;/#failures&quot;&gt;Three ways 1M token windows fail&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;execution-guardrails&quot;&gt;Execution Guardrails&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;What the model can and cannot do.&lt;/em&gt; Risk-tiered, machine-readable, and enforced by the
system rather than requested in a prompt.&lt;/p&gt;
&lt;h3 id=&quot;5-multi-tenant-agent-isolation&quot;&gt;5. Multi-Tenant Agent Isolation&lt;/h3&gt;
&lt;p&gt;Agents sharing a protocol layer must not share state. Each agent keeps its own role
configuration and its own knowledge graph, discovering the others&#39; tools without
discovering their data.&lt;/p&gt;
&lt;p&gt;→ &lt;a href=&quot;https://reference-architecture.ai/posts/mcp-native-agent-architecture/#pattern-1-multi-tenant-agent-isolation&quot;&gt;Pattern 1: Multi-Tenant Agent Isolation&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;6-deterministic-replay&quot;&gt;6. Deterministic Replay&lt;/h3&gt;
&lt;p&gt;An agent run you cannot replay is an agent run you cannot debug. Record the inputs and the
decisions such that the same run can be reconstructed exactly — which is only possible if
the layers underneath are themselves deterministic.&lt;/p&gt;
&lt;p&gt;→ &lt;a href=&quot;https://reference-architecture.ai/posts/mcp-native-agent-architecture/#pattern-2-deterministic-replay&quot;&gt;Pattern 2: Deterministic Replay&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;7-human-in-the-loop-for-destructive-operations&quot;&gt;7. Human-in-the-Loop for Destructive Operations&lt;/h3&gt;
&lt;p&gt;Classify tools by effect, not by name. Read-only operations run freely; destructive ones
stop for approval. The protocol enforces the distinction, so an agent cannot talk its way
past it.&lt;/p&gt;
&lt;p&gt;→ &lt;a href=&quot;https://reference-architecture.ai/posts/mcp-native-agent-architecture/#pattern-3-human-in-the-loop-for-destructive-operations&quot;&gt;Pattern 3: Human-in-the-Loop for Destructive Operations&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;8-break-glass&quot;&gt;8. Break-Glass&lt;/h3&gt;
&lt;p&gt;Every guardrail needs a deliberate, logged way through it. A guardrail with no override
gets disabled wholesale the first time it blocks something urgent; an override that is
not recorded is indistinguishable from the guardrail not existing.&lt;/p&gt;
&lt;p&gt;→ &lt;a href=&quot;https://reference-architecture.ai/posts/harness-engineering-agents/#harness-3-break-glass&quot;&gt;Harness 3: Break-Glass&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;memory-infrastructure&quot;&gt;Memory Infrastructure&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Ensuring the model learns from its own history.&lt;/em&gt; Without it, agents repeat solved
problems indefinitely and no amount of context helps.&lt;/p&gt;
&lt;h3 id=&quot;9-novelty-filter&quot;&gt;9. Novelty Filter&lt;/h3&gt;
&lt;p&gt;Distinguish output that is new from output that merely looks new. An agent that cannot
tell repetition from progress will re-report the same finding until someone stops reading.&lt;/p&gt;
&lt;p&gt;→ &lt;a href=&quot;https://reference-architecture.ai/posts/harness-engineering-agents/#harness-1-novelty-filter&quot;&gt;Harness 1: Novelty Filter&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;10-calculated-health&quot;&gt;10. Calculated Health&lt;/h3&gt;
&lt;p&gt;Derive a health signal from observable metrics rather than asking the agent how it is
doing. Self-assessment is the least reliable input available; commit recency, unapplied
lessons and stall time are not.&lt;/p&gt;
&lt;p&gt;→ &lt;a href=&quot;https://reference-architecture.ai/posts/harness-engineering-agents/#harness-2-calculated-health&quot;&gt;Harness 2: Calculated Health&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;11-lesson-window&quot;&gt;11. Lesson Window&lt;/h3&gt;
&lt;p&gt;Capture corrections at the moment of failure and apply them within a bounded window.
Lessons with no expiry become noise; lessons never applied were never lessons.&lt;/p&gt;
&lt;p&gt;→ &lt;a href=&quot;https://reference-architecture.ai/posts/harness-engineering-agents/#harness-4-lesson-window&quot;&gt;Harness 4: Lesson Window&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;12-drift-detection&quot;&gt;12. Drift Detection&lt;/h3&gt;
&lt;p&gt;Long-running agents optimise for local coherence and lose the original objective. Ask
periodically, and mechanically: do we actually have the thing we set out to build? The
question has to be asked by the harness, because an agent that has drifted cannot detect
its own drift.&lt;/p&gt;
&lt;p&gt;→ &lt;a href=&quot;/#failures&quot;&gt;Three ways 1M token windows fail&lt;/a&gt; ·
&lt;a href=&quot;/#flywheel&quot;&gt;The nine-step orchestration arc&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;on-this-list&quot;&gt;On this list&lt;/h2&gt;
&lt;p&gt;These twelve are the patterns this site currently makes an argument for, grouped by
&lt;a href=&quot;/#harness&quot;&gt;the three jobs of an agent harness&lt;/a&gt;. The grouping is deliberate: a pattern
that does not serve one of those three jobs probably belongs in a different architecture.&lt;/p&gt;
&lt;p&gt;The list is not a claim to completeness. It is what is documented, and the honest test of
any addition is whether there is an article behind it.&lt;/p&gt;
</description>
      </item>
      <item>
          <title>The Terraphim Engine: Six Layers, Fifty-Two Crates</title>
          <pubDate>Tue, 08 Sep 2026 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://reference-architecture.ai/posts/terraphim-engine-architecture/</link>
          <guid>https://reference-architecture.ai/posts/terraphim-engine-architecture/</guid>
          <description xml:base="https://reference-architecture.ai/posts/terraphim-engine-architecture/">&lt;p&gt;The diagram on the front page of this site is not an illustration. Every box in it is a
published Rust crate you can &lt;code&gt;cargo add&lt;/code&gt; today, read the documentation for, and use
without taking the rest of the system. This article explains what sits behind each box,
and why the decomposition is the interesting part.&lt;/p&gt;
&lt;p&gt;&lt;span id=&quot;continue-reading&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 id=&quot;why-decomposition-is-the-architecture&quot;&gt;Why decomposition is the architecture&lt;/h2&gt;
&lt;p&gt;Most agent frameworks ship as a single dependency. You take the orchestrator, the memory
layer, the retrieval stack and the tool protocol together, or you take none of it. That
is convenient at first and expensive later: when one layer misbehaves you cannot isolate
it, and when you want to replace one you replace all of them.&lt;/p&gt;
&lt;p&gt;The pattern this site argues for is the opposite. Draw the boundaries first, make each
one independently useful, and let the seams stay visible. Terraphim is built that way —
52 crates across six layers, each with a single responsibility — which makes it a
reasonable worked example rather than a product pitch.&lt;/p&gt;
&lt;p&gt;The test of a boundary is whether you can use one side without the other. Here you can:
&lt;code&gt;terraphim_automata&lt;/code&gt; is a text-matching engine that happens to be used by a knowledge
graph; &lt;code&gt;terraphim_persistence&lt;/code&gt; is a storage abstraction that does not know what it is
storing.&lt;/p&gt;
&lt;h2 id=&quot;the-six-layers&quot;&gt;The six layers&lt;/h2&gt;
&lt;p&gt;Terraphim organises its crates into a dependency graph with six levels. Lower layers do
not know the higher ones exist.&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Layer&lt;/th&gt;&lt;th&gt;Concern&lt;/th&gt;&lt;th&gt;Representative crates&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;6&lt;/td&gt;&lt;td&gt;User interfaces&lt;/td&gt;&lt;td&gt;&lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://docs.rs/terraphim_agent&quot;&gt;&lt;code&gt;terraphim_agent&lt;/code&gt;&lt;/a&gt;, &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://docs.rs/terraphim-cli&quot;&gt;&lt;code&gt;terraphim-cli&lt;/code&gt;&lt;/a&gt;, &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://docs.rs/terraphim_server&quot;&gt;&lt;code&gt;terraphim_server&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;5&lt;/td&gt;&lt;td&gt;Orchestration&lt;/td&gt;&lt;td&gt;&lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://docs.rs/terraphim_orchestrator&quot;&gt;&lt;code&gt;terraphim_orchestrator&lt;/code&gt;&lt;/a&gt;, &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://docs.rs/terraphim_kg_orchestration&quot;&gt;&lt;code&gt;terraphim_kg_orchestration&lt;/code&gt;&lt;/a&gt;, &lt;code&gt;terraphim_symphony&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;4&lt;/td&gt;&lt;td&gt;Agent system&lt;/td&gt;&lt;td&gt;&lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://docs.rs/terraphim_spawner&quot;&gt;&lt;code&gt;terraphim_spawner&lt;/code&gt;&lt;/a&gt;, &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://docs.rs/terraphim_router&quot;&gt;&lt;code&gt;terraphim_router&lt;/code&gt;&lt;/a&gt;, &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://docs.rs/terraphim_agent_supervisor&quot;&gt;&lt;code&gt;terraphim_agent_supervisor&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;Service layer&lt;/td&gt;&lt;td&gt;&lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://docs.rs/terraphim_service&quot;&gt;&lt;code&gt;terraphim_service&lt;/code&gt;&lt;/a&gt;, &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://docs.rs/terraphim_middleware&quot;&gt;&lt;code&gt;terraphim_middleware&lt;/code&gt;&lt;/a&gt;, &lt;code&gt;haystack_*&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Core engine&lt;/td&gt;&lt;td&gt;&lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://docs.rs/terraphim_automata&quot;&gt;&lt;code&gt;terraphim_automata&lt;/code&gt;&lt;/a&gt;, &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://docs.rs/terraphim_rolegraph&quot;&gt;&lt;code&gt;terraphim_rolegraph&lt;/code&gt;&lt;/a&gt;, &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://docs.rs/terraphim_persistence&quot;&gt;&lt;code&gt;terraphim_persistence&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Types and configuration&lt;/td&gt;&lt;td&gt;&lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://docs.rs/terraphim_types&quot;&gt;&lt;code&gt;terraphim_types&lt;/code&gt;&lt;/a&gt;, &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://docs.rs/terraphim_config&quot;&gt;&lt;code&gt;terraphim_config&lt;/code&gt;&lt;/a&gt;, &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://docs.rs/terraphim_settings&quot;&gt;&lt;code&gt;terraphim_settings&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;That ordering matters more than the crate count. An agent system that cannot say which
layer a failure came from is a system you cannot debug in production.&lt;/p&gt;
&lt;h2 id=&quot;layer-1-types-and-configuration&quot;&gt;Layer 1: types and configuration&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;terraphim_types&lt;/code&gt; is the shared vocabulary — the structures every other crate agrees on.
&lt;code&gt;terraphim_config&lt;/code&gt; holds role definitions, haystacks and LLM routing;
&lt;code&gt;terraphim_settings&lt;/code&gt; handles runtime preferences.&lt;/p&gt;
&lt;p&gt;Putting roles in configuration rather than code is what makes the context boundary
structural. A role has access to certain haystacks; the knowledge graph is built from
those haystacks; therefore the agent cannot reach information outside its role. That is
not a permission check at runtime that could be bypassed — it is an absence. The data
was never loaded.&lt;/p&gt;
&lt;h2 id=&quot;layer-2-the-core-engine&quot;&gt;Layer 2: the core engine&lt;/h2&gt;
&lt;p&gt;This is the layer the front-page diagram mostly depicts.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://docs.rs/terraphim_automata&quot;&gt;&lt;code&gt;terraphim_automata&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt; is the matching engine:
Aho-Corasick finite state automata that match thousands of patterns simultaneously in
O(n) time, where n is the length of the text. Not &quot;usually fast&quot; — bounded, and the same
bound every time. It compiles to WebAssembly, which is why the same matcher runs in a
browser as on a server.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://docs.rs/terraphim_rolegraph&quot;&gt;&lt;code&gt;terraphim_rolegraph&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt; is the knowledge graph.
It is deliberately not a general-purpose graph database. It maps search roles to
domain-specific graph views, and it exists to do one thing quickly: turn text into
concepts, deterministically. Terraphim reports knowledge-graph inference in the 5-10
nanosecond range and a 15 MB memory footprint, with no GPU — figures worth checking
against your own workload, but the shape of the claim follows from the design rather
than from optimisation tricks.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://docs.rs/terraphim_persistence&quot;&gt;&lt;code&gt;terraphim_persistence&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt; provides the
&lt;code&gt;Persistable&lt;/code&gt; trait and DeviceStorage backends across memory, SQLite and redb. Storage is
an interface here, not an assumption, which is what lets the same engine run on a laptop
and at the edge.&lt;/p&gt;
&lt;h2 id=&quot;layer-3-the-service-layer&quot;&gt;Layer 3: the service layer&lt;/h2&gt;
&lt;p&gt;&lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://docs.rs/terraphim_middleware&quot;&gt;&lt;code&gt;terraphim_middleware&lt;/code&gt;&lt;/a&gt; searches &lt;em&gt;haystacks&lt;/em&gt; —
pluggable data-source backends. This is the boundary the front-page diagram labels
Document Input. A haystack might be a local folder, a repository, or a connector to
something else; the layers above do not change when you add one.&lt;/p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://docs.rs/terraphim_service&quot;&gt;&lt;code&gt;terraphim_service&lt;/code&gt;&lt;/a&gt; handles requests and responses
for the core, which keeps request handling out of the engine itself.&lt;/p&gt;
&lt;h2 id=&quot;layers-4-and-5-agents-and-orchestration&quot;&gt;Layers 4 and 5: agents and orchestration&lt;/h2&gt;
&lt;p&gt;Above the service layer sit the agent system (&lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://docs.rs/terraphim_spawner&quot;&gt;&lt;code&gt;terraphim_spawner&lt;/code&gt;&lt;/a&gt;, &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://docs.rs/terraphim_router&quot;&gt;&lt;code&gt;terraphim_router&lt;/code&gt;&lt;/a&gt;,
&lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://docs.rs/terraphim_agent_supervisor&quot;&gt;&lt;code&gt;terraphim_agent_supervisor&lt;/code&gt;&lt;/a&gt;) and orchestration (&lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://docs.rs/terraphim_orchestrator&quot;&gt;&lt;code&gt;terraphim_orchestrator&lt;/code&gt;&lt;/a&gt;,
&lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://docs.rs/terraphim_kg_orchestration&quot;&gt;&lt;code&gt;terraphim_kg_orchestration&lt;/code&gt;&lt;/a&gt;, &lt;code&gt;terraphim_symphony&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;The distinction is worth holding onto. The agent system is concerned with individual
agents — spawning them, routing to them, supervising them. Orchestration is concerned
with what happens between them. Collapsing those two into one &quot;agent framework&quot; is the
usual mistake, and it is why so many systems cannot tell a stuck agent from a stuck
workflow.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://reference-architecture.ai/posts/mcp-native-agent-architecture/&quot;&gt;The MCP-Native Agent Architecture&lt;/a&gt; goes
into the protocol surface these layers expose, and why treating MCP as an architectural
primitive rather than a transport changes what the system can guarantee.&lt;/p&gt;
&lt;h2 id=&quot;layer-6-the-interfaces&quot;&gt;Layer 6: the interfaces&lt;/h2&gt;
&lt;p&gt;&lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://docs.rs/terraphim_agent&quot;&gt;&lt;code&gt;terraphim_agent&lt;/code&gt;&lt;/a&gt; is the interactive REPL with session
search and learning capture. &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://docs.rs/terraphim-cli&quot;&gt;&lt;code&gt;terraphim-cli&lt;/code&gt;&lt;/a&gt; is the
automation-shaped counterpart, with JSON output for scripting.
&lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://docs.rs/terraphim_server&quot;&gt;&lt;code&gt;terraphim_server&lt;/code&gt;&lt;/a&gt; provides the REST API.&lt;/p&gt;
&lt;p&gt;Three interfaces over one engine, none of them privileged. That is the payoff of the
layering: the CLI is not a thin wrapper around the server, and the server is not a
special case. They are peers over the same core.&lt;/p&gt;
&lt;h2 id=&quot;what-to-take-from-this&quot;&gt;What to take from this&lt;/h2&gt;
&lt;p&gt;You do not need to adopt Terraphim to use the pattern. The transferable parts are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Draw layers that a failure can be attributed to.&lt;/strong&gt; If you cannot name the layer, you
cannot fix the bug.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Make each boundary independently useful.&lt;/strong&gt; A crate nobody would use on its own is
usually not a boundary, it is a split file.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Put the context boundary in configuration, not in runtime checks.&lt;/strong&gt; Structural
impossibility beats a permission test.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Keep the expensive guarantees low.&lt;/strong&gt; Determinism in the matching engine is worth more
than determinism bolted onto the orchestrator.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;documentation&quot;&gt;Documentation&lt;/h2&gt;
&lt;p&gt;Every crate named above is published and documented:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://terraphim.rs&quot;&gt;terraphim.rs&lt;/a&gt;&lt;/strong&gt; — the engine: all 52 crates, grouped by layer,
with the dependency graph and installation instructions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://docs.rs/terraphim_automata&quot;&gt;docs.rs&lt;/a&gt;&lt;/strong&gt; — per-crate API documentation,
generated from source. Start with
&lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://docs.rs/terraphim_automata&quot;&gt;&lt;code&gt;terraphim_automata&lt;/code&gt;&lt;/a&gt; for matching,
&lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://docs.rs/terraphim_rolegraph&quot;&gt;&lt;code&gt;terraphim_rolegraph&lt;/code&gt;&lt;/a&gt; for the knowledge graph,
or &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://docs.rs/terraphim_persistence&quot;&gt;&lt;code&gt;terraphim_persistence&lt;/code&gt;&lt;/a&gt; for storage.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://docs.terraphim.ai&quot;&gt;docs.terraphim.ai&lt;/a&gt;&lt;/strong&gt; — the full documentation site:
guides, deployment and integration patterns.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://terraphim.ai&quot;&gt;terraphim.ai&lt;/a&gt;&lt;/strong&gt; — the assistant built on all of it, if you
would rather see the system working before reading its parts.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Installation is a single command, or &lt;code&gt;cargo install terraphim_agent&lt;/code&gt; if you would prefer
to start from the REPL.&lt;/p&gt;
</description>
      </item>
      <item>
          <title>The MCP-Native Agent Architecture</title>
          <pubDate>Mon, 07 Sep 2026 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://reference-architecture.ai/posts/mcp-native-agent-architecture/</link>
          <guid>https://reference-architecture.ai/posts/mcp-native-agent-architecture/</guid>
          <description xml:base="https://reference-architecture.ai/posts/mcp-native-agent-architecture/">&lt;p&gt;A reference architecture for production AI systems, drawn from five years building Terraphim — a privacy-first AI assistant with ~50 Rust crates, MCP-native interfaces, and role-based multi-agent orchestration.&lt;/p&gt;</description>
      </item>
      <item>
          <title>Harness Engineering for Self-Improving Agents</title>
          <pubDate>Sun, 06 Sep 2026 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://reference-architecture.ai/posts/harness-engineering-agents/</link>
          <guid>https://reference-architecture.ai/posts/harness-engineering-agents/</guid>
          <description xml:base="https://reference-architecture.ai/posts/harness-engineering-agents/">&lt;p&gt;Many AI agent systems plateau after deployment. They execute tasks, but the surrounding system may not measure whether they are getting better, repeating old work, or normalizing stalled execution. This article proposes a reference pattern for &lt;strong&gt;agent harnesses&lt;/strong&gt;: supervised feedback loops that make agent behavior observable, measurable, and easier to improve.&lt;/p&gt;</description>
      </item>
      <item>
          <title>Turning Open Source project into Product with Redis Enterprise</title>
          <pubDate>Fri, 19 Aug 2022 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://reference-architecture.ai/posts/github-oauth2/</link>
          <guid>https://reference-architecture.ai/posts/github-oauth2/</guid>
          <description xml:base="https://reference-architecture.ai/posts/github-oauth2/">&lt;h1 id=&quot;turning-open-source-project-into-product-with-redis-enterprise&quot;&gt;Turning Open Source project into Product with Redis Enterprise&lt;/h1&gt;
&lt;h1 id=&quot;overview&quot;&gt;Overview&lt;/h1&gt;
&lt;h1 id=&quot;background&quot;&gt;Background&lt;/h1&gt;
&lt;h2 id=&quot;history&quot;&gt;History&lt;/h2&gt;
&lt;p&gt;Last year, my reference project, &quot;The Pattern&quot;, was the hackathon winner 2021 and got a bit of publicity and, in total, seven forks. But as with many open source projects, it is now stale. Time to revive &quot;The Pattern&quot; with new features and GitHub sponsors or Patreon patrons to help and inspire developers and creatives. In return, it&#39;s common to provide sponsor-only features and articles. Nevertheless, how can we do it with a large Redis-based machine learning pipeline?&lt;/p&gt;
&lt;h2 id=&quot;plan-sponsor-only-features&quot;&gt;Plan sponsor only features&lt;/h2&gt;
&lt;p&gt;This article will introduce a simple first step:
for GitHub sponsors, we start with offering persistent storage of preferences: I have a simple flask POST API which adds nodes into the user&#39;s preference storage - a simple Redis set per user. And it will be a foundation to build other sponsor-only features.
For now, let&#39;s cover the basics:&lt;/p&gt;
&lt;h1 id=&quot;overall-architecture-overview&quot;&gt;Overall architecture overview&lt;/h1&gt;
&lt;div class=&quot;mermaid-wrap&quot;&gt;&lt;pre class=&quot;mermaid&quot;&gt;
flowchart LR
    id1(User) --&gt; flask_login(Flask Login API)--&gt; github(GitHub OAuth2)
    github--&gt;flask_callback(Flask API callback)--&gt;GitHubGraphQL(GitHub GraphQL)
&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;add-github-oauth2-to-rest-api&quot;&gt;Add Github oauth2 to Rest API&lt;/h2&gt;
&lt;p&gt;There are a number of API&#39;s that GitHub offers to help developers, but the GitHub Authentication API is one of the most popular. This API allows you to log in to GitHub using your username and password, or OAuth token.&lt;/p&gt;
&lt;p&gt;A login button with a standard OIDC/OAuth2 dance is one of the most common ways for a user to authenticate to an API.
Below is code taken from this &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://gist.github.com/xros/aba970d1098d916200d0acce8feb0251&quot;&gt;gist&lt;/a&gt; and is very common for OAuth2 flows:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot; &gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;import&lt;/span&gt;&lt;span&gt; os &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;client_id&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; =&lt;/span&gt;&lt;span&gt; os&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;getenv&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;GITHUB_CLIENT_ID&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;client_secret&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; =&lt;/span&gt;&lt;span&gt; os&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;getenv&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;GITHUB_SECRET&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;app&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;route&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;,&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; methods&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=[&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;GET&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;, &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;POST&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;]&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; index&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;():&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    url&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; = &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;https://github.com/login/oauth/authorize&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    params&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; = {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;        &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;client_id&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;:&lt;/span&gt;&lt;span&gt; client_id&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;        &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;scope&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;: &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;read:user,read:email&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;        &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;state&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;:&lt;/span&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt; str&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;uuid4&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;hex&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;        &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;allow_signup&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;: &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    url&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; furl&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;url&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;params&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; redirect&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt;str&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;url&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 302&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;where GITHUB_CLIENT_ID and GITHUB_SECRET are client/secret GitHub Oauth2 apps. Register for following process on &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://github.com/settings/applications/new&quot;&gt;GitHub&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;On callback:
&lt;ul&gt;
&lt;li&gt;Fetch username, email, and other profile information- in case we need to contact them&lt;/li&gt;
&lt;li&gt;get the status of the user - if they are sponsor of the organisation
&lt;ul&gt;
&lt;li&gt;if they are sponsor&lt;/li&gt;
&lt;li&gt;add the username to the set of sponsors in Redis&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot; &gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;org_name&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;applied-knowledge-systems&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;app&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;route&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;/oauth2/callback&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; oauth2_callback&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;():&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    code&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; =&lt;/span&gt;&lt;span&gt; request&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span&gt;args&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;code&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    access_token_url&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; = &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;https://github.com/login/oauth/access_token&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    payload&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; = {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;        &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;client_id&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;:&lt;/span&gt;&lt;span&gt; client_id&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;        &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;client_secret&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;:&lt;/span&gt;&lt;span&gt; client_secret&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;        &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;code&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;:&lt;/span&gt;&lt;span&gt; code&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt;        # &amp;#39;redirect_uri&amp;#39;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;        &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;state&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;:&lt;/span&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt; str&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;uuid4&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;hex&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    r&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; =&lt;/span&gt;&lt;span&gt; requests&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;post&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;access_token_url&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; json&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;payload&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; headers&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;={&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;Accept&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;: &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;application/json&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;}&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    access_token&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; =&lt;/span&gt;&lt;span&gt; json&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;loads&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;r&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;text&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;access_token&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;access_token&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    access_user_url&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; = &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;https://api.github.com/user&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    response&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; =&lt;/span&gt;&lt;span&gt; requests&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;access_user_url&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; headers&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;={&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;Authorization&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;: &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;token &lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39; +&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; access_token&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    data&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&lt;/span&gt;&lt;span&gt;response&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;json&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    user_email&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;email&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    user_login&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;login&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    user_id&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt;    # response=redirect(url_for(&amp;#39;login&amp;#39;,next=redirect_url()))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt;    # response.set_cookie(&amp;#39;user_id&amp;#39;, str(user_id))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt;    # response.set_cookie(&amp;#39;user_login&amp;#39;, str(user_login))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt;    # return response&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    query&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; = &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;        viewer {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;            sponsorshipsAsSponsor(first: 100) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;            nodes {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;                sponsorable {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;                ... on User {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;                    id&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;                    email&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;                    url&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;                }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;                ... on Organization {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;                    id&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;                    email&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;                    name&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;                    url&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;                }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;                }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;                tier {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;                id&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;                name&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;                monthlyPriceInDollars&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;                monthlyPriceInCents&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;                }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;        &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    response_graphql&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; =&lt;/span&gt;&lt;span&gt; requests&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;post&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;https://api.github.com/graphql&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;,&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; json&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;={&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;query&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;:&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; query&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;},&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; headers&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;={&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;Authorization&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;: &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;token &lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39; +&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; access_token&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    response_graphql_data&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&lt;/span&gt;&lt;span&gt;response_graphql&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;json&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;[&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;data&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt; isinstance&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;response_graphql_data&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;viewer&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;[&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;sponsorshipsAsSponsor&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;][&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;nodes&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;],&lt;/span&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt; list&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;      if&lt;/span&gt;&lt;span&gt; response_graphql_data&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;viewer&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;[&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;sponsorshipsAsSponsor&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;][&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;nodes&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;][&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;][&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;sponsorable&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;][&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;]&lt;/span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;==&lt;/span&gt;&lt;span&gt;org_name&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt;          # if user is a sponsor of Applied Knowledge System add them to set of sponsors&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;         redis_client&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;sadd&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;&amp;#39;sponsors:&lt;/span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;org_name&lt;/span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;user_id&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt;    # if RedisJSON enabled:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt;    # redis_client.json().set(f&amp;quot;user_details:{user_id}&amp;quot;, &amp;#39;$&amp;#39;, {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt;    #     &amp;#39;email&amp;#39;: user_email,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt;    #     &amp;#39;id&amp;#39;: user_id,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt;    #     &amp;#39;user_login&amp;#39;: user_login,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt;    #     &amp;#39;graphql&amp;#39;: response_graphql_data,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt;    # }) &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt;    #if not&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    redis_client&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;hset&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;&amp;quot;user_details:&lt;/span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;user_id&lt;/span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; mapping&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;={&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;        &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;email&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;:&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; user_email&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;        &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;:&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; user_id&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;        &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;user_login&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;:&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; user_login&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;    }&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; jsonify&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;        &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;status&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;: &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;success&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;        &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;email&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;:&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; user_email&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;        &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;:&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; user_id&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;        &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;user_login&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;:&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; user_login&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;    }&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The API we are using for our sponsor-only feature is straightforward:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot; &gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;app&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;route&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;/exclude&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;,&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; methods&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=[&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;POST&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;,&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;GET&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;]&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; mark_node&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;():&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;    if&lt;/span&gt;&lt;span&gt; request&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span&gt;method&lt;/span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;POST&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; in&lt;/span&gt;&lt;span&gt; request&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span&gt;json&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            node_id&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&lt;/span&gt;&lt;span&gt;request&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span&gt;json&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;    else&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; in&lt;/span&gt;&lt;span&gt; request&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span&gt;args&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            node_id&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&lt;/span&gt;&lt;span&gt;request&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span&gt;args&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    user_id&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; =&lt;/span&gt;&lt;span&gt; session&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;user_id&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;    log&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;&amp;quot;Got user &lt;/span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;user_id&lt;/span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; from session&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;    if not&lt;/span&gt;&lt;span&gt; user_id&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        user_id&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; =&lt;/span&gt;&lt;span&gt; request&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span&gt;cookies&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;user_id&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;        log&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;&amp;quot;Got user &lt;/span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;user_id&lt;/span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; from cookie&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    redis_client&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;sadd&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;user:%s:mnodes&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot; %&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; user_id&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;node_id&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    response&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; jsonify&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;message&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;&amp;quot;Finished &lt;/span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;node_id&lt;/span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; and &lt;/span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;user_id&lt;/span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;    return&lt;/span&gt;&lt;span&gt; response&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And the only purpose of this API is to mark nodes as unimportant for the given user by adding nodes to RedisSet, and those nodes will be excluded from search API output. So far, everything was pretty standard: basic flask API and GitHub Social login flow. Now let&#39;s add Redis Enterprise and synchronise sponsors preferences.&lt;/p&gt;
&lt;h1 id=&quot;add-redis-enterprise&quot;&gt;Add Redis Enterprise&lt;/h1&gt;
&lt;p&gt;Why not use Redis Enterprise directly for everything?
The project is memory-heavy, with a lot of data and machine learning inside Redis. This allows to achieve state-of-the-art performance, but it also takes over 120 GB RAM (or as much RAM as you can give it), and 128 GB Redis Enterprise instance will exceed my budget for open-source project. Obviously if there will be enough sponsors we can move more functionality into Redis Enterprise, but for that we need to finish building basic blocks. Register on &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://redis.com/?utm_campaign=write_for_redis&quot;&gt;Redis.com&lt;/a&gt; cloud and create a database with the subscription.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://reference-architecture.ai/posts/github-oauth2/redis_enterprise_screen.png&quot; alt=&quot;Redis Enterprise&quot; /&gt;
Take a note host, port and password for Redis Enterprise and create docker enviroment file:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;cat&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; .env.gears&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;REDISENT_PWD&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;123&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;REDISENT_PORT&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;13444&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;REDISENT_HOST&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;hostname.cloud.redislabs.com&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and create a docker compose with section passing .env.gears. Mine looks like this:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  redisgraph:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    image: redislabs/redismod&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    container_name: redisgears&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    hostname: redisgears&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    env_file:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      - ./.env.gears&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ports:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      - 127.0.0.1:9001:6379&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h1 id=&quot;synchronize-redis-oss-to-redis-enterprise-using-redisgears&quot;&gt;Synchronize Redis OSS to Redis Enterprise using RedisGears&lt;/h1&gt;
&lt;h2 id=&quot;synchronize-all-user-preferences&quot;&gt;Synchronize all user preferences&lt;/h2&gt;
&lt;p&gt;First flow:
We will be using RedisGears to synchronize all preferences with Redis Enterprise&lt;/p&gt;
&lt;div class=&quot;mermaid-wrap&quot;&gt;&lt;pre class=&quot;mermaid&quot;&gt;
flowchart LR
    id1(User Preferences Redis OSS) --&gt; redis_gears1(Redis Gears)--&gt; redise(Redis Enterprise)
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you are new to RedisGears, there is a pattern &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://github.com/RedisGears/rgsync/tree/master/examples/redis&quot;&gt;rgsync&lt;/a&gt; that covers exacly this use case, but I already have RedisGears, so I am going to build it step by step:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot; &gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt;# gears_sync_preferences.py&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;rconn&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt;None&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; connecttoRedisEnterise&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;():&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;    import&lt;/span&gt;&lt;span&gt; redis &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;    import&lt;/span&gt;&lt;span&gt; os &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;    log&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt;str&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;os&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;environ&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt;    # Get environment variables&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt;    HOST&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; =&lt;/span&gt;&lt;span&gt; os&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;getenv&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;REDISENT_HOST&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt;    PASSWORD&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; =&lt;/span&gt;&lt;span&gt; os&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;getenv&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;REDISENT_PWD&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt;    PORT&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; =&lt;/span&gt;&lt;span&gt; os&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;getenv&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;REDISENT_PORT&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    redis_client&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&lt;/span&gt;&lt;span&gt;redis&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;Redis&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;host&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt;HOST&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;port&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt;PORT&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;charset&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;utf-8&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; password&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt;PASSWORD&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; decode_responses&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt;True&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;    return&lt;/span&gt;&lt;span&gt; redis_client&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; sync_users&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;record&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9D7CD8;font-style: italic;&quot;&gt;    global&lt;/span&gt;&lt;span&gt; rconn&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;    if not&lt;/span&gt;&lt;span&gt; rconn&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        rconn&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;connecttoRedisEnterise&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt;    # Uncomment logs to check &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt;    # log(str(record[&amp;#39;key&amp;#39;]))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt;    # log(str(record[&amp;#39;value&amp;#39;]))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    rconn&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;hset&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;record&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;key&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;mapping&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;record&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;gb&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; GB&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;gb&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;foreach&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;sync_users&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;gb&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;count&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;gb&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;user_details:*&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;this is a &quot;batch&quot; mode for RedisGears, which is easier to debug than streams. Install gears-cli](https://github.com/RedisGears/gears-cli) with &lt;code&gt;pip install gears-cli&lt;/code&gt; run above script:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;gears-cli&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; run&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; --host&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 127.0.0.1&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; --port&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 9001&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; gears_sync_preferences.py&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; --requirements&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; req_sync.txt&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;where req_sync.txt&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot; &gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;redis&lt;/span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt;3.5&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This RedisGears will copy all user&#39;s profiles into RedisEnterprise. Now let us add sponsors:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot; &gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt;# gears_sync_sponsors.py&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;rconn&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt;None&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; remove_prefix&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;text&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; prefix&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;    return&lt;/span&gt;&lt;span&gt; text&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;[&lt;/span&gt;&lt;span&gt;text&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;startswith&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;prefix&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; and&lt;/span&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt; len&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;prefix&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; connecttoRedisEnterise&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;():&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;    import&lt;/span&gt;&lt;span&gt; redis &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;    import&lt;/span&gt;&lt;span&gt; os &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;    log&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt;str&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;os&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;environ&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt;    # Get environment variables&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt;    HOST&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; =&lt;/span&gt;&lt;span&gt; os&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;getenv&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;REDISENT_HOST&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt;    PASSWORD&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; =&lt;/span&gt;&lt;span&gt; os&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;getenv&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;REDISENT_PWD&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt;    PORT&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; =&lt;/span&gt;&lt;span&gt; os&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;getenv&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;REDISENT_PORT&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;    log&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt;HOST&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;    log&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt;PORT&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;    log&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt;PASSWORD&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    redis_client&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&lt;/span&gt;&lt;span&gt;redis&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;Redis&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;host&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt;HOST&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;port&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt;PORT&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;charset&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;utf-8&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; password&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt;PASSWORD&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;    return&lt;/span&gt;&lt;span&gt; redis_client&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; sync_sponsors&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;record&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9D7CD8;font-style: italic;&quot;&gt;    global&lt;/span&gt;&lt;span&gt; rconn&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;    if not&lt;/span&gt;&lt;span&gt; rconn&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        rconn&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;connecttoRedisEnterise&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;    log&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt;str&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;record&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;key&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;]))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    values&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;execute&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;SMEMBERS&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;,&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;record&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;key&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;    log&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt;str&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;values&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;    for&lt;/span&gt;&lt;span&gt; each_value&lt;/span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; in&lt;/span&gt;&lt;span&gt; values&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;/span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        rconn&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;sadd&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;record&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;key&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;each_value&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;gb&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; GB&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;KeysReader&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;gb&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;foreach&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;sync_sponsors&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;gb&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;count&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;gb&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;user:*&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But this one will sync all user&#39;s preferences, but we only need sponsors - let us add another feature of RedisGears - filter:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot; &gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;rconn&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt;None&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; remove_prefix&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;text&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; prefix&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;    return&lt;/span&gt;&lt;span&gt; text&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;[&lt;/span&gt;&lt;span&gt;text&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;startswith&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;prefix&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; and&lt;/span&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt; len&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;prefix&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; connecttoRedisEnterise&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;():&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;    import&lt;/span&gt;&lt;span&gt; redis &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;    import&lt;/span&gt;&lt;span&gt; os &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;    log&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt;str&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;os&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;environ&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt;    # Get environment variables&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt;    HOST&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; =&lt;/span&gt;&lt;span&gt; os&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;getenv&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;REDISENT_HOST&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt;    PASSWORD&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; =&lt;/span&gt;&lt;span&gt; os&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;getenv&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;REDISENT_PWD&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt;    PORT&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; =&lt;/span&gt;&lt;span&gt; os&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;getenv&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;REDISENT_PORT&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    redis_client&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&lt;/span&gt;&lt;span&gt;redis&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;Redis&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;host&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt;HOST&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;port&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt;PORT&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;charset&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;utf-8&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; password&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt;PASSWORD&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; decode_responses&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt;True&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;    return&lt;/span&gt;&lt;span&gt; redis_client&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; filter_sponsors&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;record&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    org_name&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;applied-knowledge-systems&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    user_id&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; remove_prefix&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;record&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;key&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;user:&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    sponsor&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;execute&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;SISMEMBER&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;,&lt;/span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;&amp;#39;sponsors:&lt;/span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;org_name&lt;/span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;user_id&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt; bool&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;sponsor&lt;/span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt;True&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; sync_sponsors&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;record&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9D7CD8;font-style: italic;&quot;&gt;    global&lt;/span&gt;&lt;span&gt; rconn&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;    if not&lt;/span&gt;&lt;span&gt; rconn&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        rconn&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;connecttoRedisEnterise&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;    log&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt;str&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;record&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;key&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;]))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    values&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;execute&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;SMEMBERS&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;,&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;record&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;key&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;    log&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt;str&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;values&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;    for&lt;/span&gt;&lt;span&gt; each_value&lt;/span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; in&lt;/span&gt;&lt;span&gt; values&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;/span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        rconn&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;sadd&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;record&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;key&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;each_value&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;gb&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; GB&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;gb&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;filter&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;filter_sponsors&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;gb&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;foreach&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;sync_sponsors&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;gb&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;count&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;gb&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;user:*&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;fetch-sponsor-s-preferences-back-to-redis-oss-from-redis-enterprise&quot;&gt;Fetch sponsor&#39;s preferences back to Redis OSS from Redis Enterprise&lt;/h2&gt;
&lt;p&gt;Then we are going to use &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://web.archive.org/web/20221123154317/https://oss.redis.com/redisgears/1.2/miss_event.html#fetch-data-on-keymiss-event&quot;&gt;Key miss events&lt;/a&gt; from Redis Gears to fetch data for all users:&lt;/p&gt;
&lt;div class=&quot;mermaid-wrap&quot;&gt;&lt;pre class=&quot;mermaid&quot;&gt;
flowchart LR
    redise(Redis Enterprise)
    redis_gears2(Redis Gears)--key miss---&gt;redise
    redis_gears2--&gt;redisOSS[Redis OSS]
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;and it&#39;s very easy, right from key miss example:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot; &gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; fetch_data&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;r&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    key&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; =&lt;/span&gt;&lt;span&gt; r&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;key&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9D7CD8;font-style: italic;&quot;&gt;    global&lt;/span&gt;&lt;span&gt; rconn&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;    if not&lt;/span&gt;&lt;span&gt; rconn&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        rconn&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;connecttoRedisEnterise&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    values&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&lt;/span&gt;&lt;span&gt;rconn&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;smembers&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;record&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;key&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;    log&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt;str&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;values&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;    for&lt;/span&gt;&lt;span&gt; each_value&lt;/span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; in&lt;/span&gt;&lt;span&gt; values&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;/span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;        execute&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;SADD&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;,&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;record&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;key&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;each_value&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;GB&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;foreach&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;fetch_data&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;register&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;prefix&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;user:*&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;,&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; commands&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=[&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;smember&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;],&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;eventTypes&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=[&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;keymiss&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;],&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; mode&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;async_local&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There is one more option - to turn fetch_data into the async call, by wrapping it into async/await, but Redis Enterprise is fairly fast, and I don&#39;t think it&#39;s worth adding an async call in this case. For curiosity, see the example &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://github.com/applied-knowledge-systems/the-pattern-api/blob/54e96ff7ef9fddbb1ad7c34d1fd5a4333a4d4c41/qasearch/qa_redisai_gear_map_keymiss_np.py#L21&quot;&gt;code&lt;/a&gt; in The Pattern repository.&lt;/p&gt;
&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;In this article, we walked through steps on how to create sponsor-specific &quot;nanoservices&quot; using RedisOSS, RedisGears and Redis Enterprise. This allows us to leverage the best of all worlds open source Redis, high availability and persistence with Redis Enterprise and RedisGears as the glue which holds everything together.&lt;/p&gt;
&lt;p&gt;This post is in collaboration with Redis.&lt;/p&gt;
&lt;h1 id=&quot;references&quot;&gt;References&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://web.archive.org/web/20220808021840/https://creativewebspecialist.co.uk/2021/01/08/how-to-use-github-sponsors-to-help-monetize-your-software/&quot;&gt;How to use GitHub Sponsors to help monetize your software&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://github.com/community/community/discussions/3818&quot;&gt;Who sponsors this user?&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://gist.github.com/alexellis/6212c988189323dbb2806d1c7f7699ab&quot;&gt;Check sponsors.go - query whether a GitHub user is your sponsor at a given tier (dollar amount)&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://gist.github.com/xros/aba970d1098d916200d0acce8feb0251&quot;&gt;GitHub OAuth2 Gist&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://docs.github.com/en/graphql/overview/explorer&quot;&gt;GraphQL explorer&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</description>
      </item>
      <item>
          <title>Benchmarks for BERT Large Question Answering inference for RedisAI and RedisGears</title>
          <pubDate>Thu, 16 Jun 2022 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://reference-architecture.ai/docs/bert-qa-benchmarking/</link>
          <guid>https://reference-architecture.ai/docs/bert-qa-benchmarking/</guid>
          <description xml:base="https://reference-architecture.ai/docs/bert-qa-benchmarking/">&lt;h2 id=&quot;summary-of-the-article&quot;&gt;Summary of the article&lt;/h2&gt;
&lt;p&gt;This article will explore the challenges and opportunities of deploying a large BERT Question Answering Transformer model(bert-large-uncased-whole-word-masking-finetuned-squad) from inside Huggingface, where &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://developer.redis.com/howtos/redisgears?utm_campaign=write_for_redis&quot;&gt;RedisGears&lt;/a&gt; and &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://web.archive.org/web/20220724124905/https://developer.redis.com/howtos/redisai/getting-started&quot;&gt;RedisAI&lt;/a&gt; perform heavy lifting while leveraging in-memory datastore Redis.&lt;/p&gt;
&lt;h2 id=&quot;why-do-we-need-redisai&quot;&gt;Why do we need RedisAI?&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;In data science load, you want to load high-performance hardware as close to 100% as possible&lt;/li&gt;
&lt;li&gt;In user-facing load, you want to be able to distribute the load evenly, so it never reaches 100%, and client-facing servers can perform additional functions&lt;/li&gt;
&lt;li&gt;In data science, you prefer re-calculate results&lt;/li&gt;
&lt;li&gt;In a client-facing application, you prefer to cache results of calculation and fetch data from the cache as fast as possible to drive a seamless customer experience&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Some numbers for inspiration and why to read this article:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;python3 transformers_plain_bert_qa.py &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;airborne transmission of respiratory infections is the lack of established methods for the detection of airborne respiratory microorganisms&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;10.351818372 seconds&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;time curl -i -H &amp;quot;Content-Type: application/json&amp;quot; -X POST -d &amp;#39;{&amp;quot;search&amp;quot;:&amp;quot;Who performs viral transmission among adults&amp;quot;}&amp;#39; http://localhost:8080/qasearch&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;real	0m0.747s&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;user	0m0.004s&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sys	0m0.000s&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h1 id=&quot;background&quot;&gt;Background&lt;/h1&gt;
&lt;p&gt;BERT Question Answering inference works where the ML model selects an answer from the given text. In other words, BERT QA &quot;thinks&quot; through the following: &quot;What is the answer from the text, assuming the answer to the question exists within the paragraph selected.&quot;&lt;/p&gt;
&lt;p&gt;So it&#39;s important to select text potentially containing an answer. A typical pattern is to use Wikipedia data to build &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://lilianweng.github.io/posts/2020-10-29-odqa/&quot;&gt;Open Domain Question Answering&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Our QA system is a medical domain-specific question/answering pipeline, hence we need a first pipeline that turns data into a knowledge graph. This NLP pipeline is available at Redis LaunchPad, is fully &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://github.com/applied-knowledge-systems/the-pattern&quot;&gt;open source&lt;/a&gt;, and is described in &lt;a href=&quot;https://reference-architecture.ai/docs/nlp/&quot;&gt;a previous article&lt;/a&gt;. Here is a 5 minute &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://www.youtube.com/watch?v=VgJ8DTX5Mt4&quot;&gt;video&lt;/a&gt; describing it, and below you will find an architectural overview:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://reference-architecture.ai/docs/bert-qa-benchmarking/featured.png&quot; alt=&quot;featured&quot; /&gt;&lt;/p&gt;
&lt;h1 id=&quot;bert-question-answering-pipeline-and-api&quot;&gt;BERT Question Answering pipeline and API&lt;/h1&gt;
&lt;p&gt;In the BERT QA pipeline (or in any other modern NLP inference task), there are two steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Tokenize text - turn text into numbers&lt;/li&gt;
&lt;li&gt;Run the inference - large matrix multiplication&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;With Redis, we have the opportunity to pre-compute everything and store it in memory, but how do we do it? Unlike with the summarization ML learning task, the question is not known in advance, so we can&#39;t pre-compute all possible answers. However, we can pre-tokenize all potential answers (i.e. all paragraphs in the dataset) using RedisGears:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot; &gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; parse_sentence&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;record&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;    import&lt;/span&gt;&lt;span&gt; redisAI&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;    import&lt;/span&gt;&lt;span&gt; numpy&lt;/span&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt; as&lt;/span&gt;&lt;span&gt; np&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9D7CD8;font-style: italic;&quot;&gt;    global&lt;/span&gt;&lt;span&gt; tokenizer&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;    if not&lt;/span&gt;&lt;span&gt; tokenizer&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        tokenizer&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;loadTokeniser&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    hash_tag&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;{%s}&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot; %&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; hashtag&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;    for&lt;/span&gt;&lt;span&gt; idx&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;/span&gt;&lt;span&gt; value&lt;/span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt; sorted&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;record&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;items&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; key&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;lambda&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; item&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt; int&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;item&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;]))&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        tokens&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; =&lt;/span&gt;&lt;span&gt; tokenizer&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;encode&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; add_special_tokens&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt;False&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; max_length&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt;511&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; truncation&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt;True&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; return_tensors&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;np&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        tokens&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; =&lt;/span&gt;&lt;span&gt; np&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;append&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;tokens&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;tokenizer&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;sep_token_id&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;astype&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;np&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;int64&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        tensor&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&lt;/span&gt;&lt;span&gt;redisAI&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;createTensorFromBlob&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;INT64&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;,&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; tokens&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;shape&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; tokens&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;tobytes&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;())&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        key_prefix&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;sentence:&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        sentence_key&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;remove_prefix&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;record&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;key&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;key_prefix&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        token_key&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; f&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;&amp;quot;tokenized:bert:qa:&lt;/span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;sentence_key&lt;/span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;idx&lt;/span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        redisAI&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;setTensorInKey&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;token_key&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; tensor&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;        execute&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;SADD&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;,&lt;/span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;&amp;#39;processed_docs_stage3_tokenized&lt;/span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;hash_tag&lt;/span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; token_key&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;See the &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://github.com/applied-knowledge-systems/the-pattern-api/blob/156633b9934f1243775671ce6c18ff2bf471c0ce/qasearch/tokeniser_gears_redisai.py#L17&quot;&gt;full code on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Then for each Redis Cluster shard, we pre-load the BERT QA model by downloading, exporting it into torchscript, then loading it into each shard:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot; &gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; load_bert&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;():&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    model_file&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; = &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;traced_bert_qa.pt&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;    with&lt;/span&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt; open&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;model_file&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;, &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;rb&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; as&lt;/span&gt;&lt;span&gt; f&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        model&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; =&lt;/span&gt;&lt;span&gt; f&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;read&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    startup_nodes&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; = [{&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;host&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;127.0.0.1&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;port&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;30001&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;}, {&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;host&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;127.0.0.1&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;port&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;:&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;30002&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;}, {&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;host&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;:&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;127.0.0.1&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;port&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;:&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;30003&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;}]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    cc&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; ClusterClient&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;startup_nodes&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; startup_nodes&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    hash_tags&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; =&lt;/span&gt;&lt;span&gt; cc&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;execute_command&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;RG.PYEXECUTE&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;,  &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;gb = GB(&amp;#39;ShardsIDReader&amp;#39;).map(lambda x:hashtag()).run()&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;hash_tags&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;    for&lt;/span&gt;&lt;span&gt; hash_tag&lt;/span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; in&lt;/span&gt;&lt;span&gt; hash_tags&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt;        print&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;Loading model bert-qa{%s}&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot; %&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;hash_tag&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;decode&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;utf-8&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        cc&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;modelset&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;bert-qa{%s}&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39; %&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;hash_tag&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;decode&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;utf-8&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;, &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;TORCH&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;, &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;CPU&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;,&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; model&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt;        print&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;cc&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;infoget&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;bert-qa{%s}&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39; %&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;hash_tag&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;decode&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;utf-8&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://github.com/applied-knowledge-systems/the-pattern-api/blob/156633b9934f1243775671ce6c18ff2bf471c0ce/qasearch/export_load_bert.py&quot;&gt;full code is available on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;And when a question comes from the user, we tokenize and append the question to the list of potential answers before running the RedisAI model:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot; &gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    token_key&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; f&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;&amp;quot;tokenized:bert:qa:&lt;/span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;sentence_key&lt;/span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt;    # encode question&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    input_ids_question&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; =&lt;/span&gt;&lt;span&gt; tokenizer&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;encode&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;question&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; add_special_tokens&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt;True&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; truncation&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt;True&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; return_tensors&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;np&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    t&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&lt;/span&gt;&lt;span&gt;redisAI&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;getTensorFromKey&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;token_key&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    input_ids_context&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;to_np&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;t&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;np&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;int64&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt;    # merge (append) with potential answer, context - is pre-tokenized paragraph&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    input_ids&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; =&lt;/span&gt;&lt;span&gt; np&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;append&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;input_ids_question&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;input_ids_context&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    attention_mask&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; =&lt;/span&gt;&lt;span&gt; np&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;array&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;[[&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;]*&lt;/span&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt;len&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;input_ids&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    input_idss&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&lt;/span&gt;&lt;span&gt;np&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;array&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;input_ids&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    num_seg_a&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&lt;/span&gt;&lt;span&gt;input_ids_question&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span&gt;shape&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    num_seg_b&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&lt;/span&gt;&lt;span&gt;input_ids_context&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span&gt;shape&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    token_type_ids&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; =&lt;/span&gt;&lt;span&gt; np&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;array&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;]*&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;num_seg_a&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; + [&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;]*&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;num_seg_b&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt;    # create actual model runner for RedisAI&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    modelRunner&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; =&lt;/span&gt;&lt;span&gt; redisAI&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;createModelRunner&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;&amp;#39;bert-qa&lt;/span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;hash_tag&lt;/span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt;    # make sure all types are correct&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    input_idss_ts&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&lt;/span&gt;&lt;span&gt;redisAI&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;createTensorFromBlob&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;INT64&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;,&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; input_idss&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;shape&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; input_idss&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;tobytes&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;())&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    attention_mask_ts&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&lt;/span&gt;&lt;span&gt;redisAI&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;createTensorFromBlob&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;INT64&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;,&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; attention_mask&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;shape&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; attention_mask&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;tobytes&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;())&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    token_type_ids_ts&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&lt;/span&gt;&lt;span&gt;redisAI&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;createTensorFromBlob&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;INT64&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;,&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; token_type_ids&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;shape&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; token_type_ids&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;tobytes&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;())&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    redisAI&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;modelRunnerAddInput&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;modelRunner&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;, &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;input_ids&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;,&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; input_idss_ts&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    redisAI&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;modelRunnerAddInput&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;modelRunner&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;, &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;attention_mask&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;,&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; attention_mask_ts&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    redisAI&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;modelRunnerAddInput&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;modelRunner&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;, &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;token_type_ids&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;,&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; token_type_ids_ts&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    redisAI&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;modelRunnerAddOutput&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;modelRunner&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;, &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;answer_start_scores&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    redisAI&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;modelRunnerAddOutput&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;modelRunner&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;, &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;answer_end_scores&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt;    # run RedisAI model runner&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    res&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; await&lt;/span&gt;&lt;span&gt; redisAI&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;modelRunnerRunAsync&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;modelRunner&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    answer_start_scores&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;to_np&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;res&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;np&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;float32&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    answer_end_scores&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; to_np&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;res&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;np&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;float32&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    answer_start&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; =&lt;/span&gt;&lt;span&gt; np&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;argmax&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;answer_start_scores&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    answer_end&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; =&lt;/span&gt;&lt;span&gt; np&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;argmax&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;answer_end_scores&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    answer&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; =&lt;/span&gt;&lt;span&gt; tokenizer&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;convert_tokens_to_string&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;tokenizer&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;convert_ids_to_tokens&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;input_ids&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;answer_start&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;answer_end&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;skip_special_tokens&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; True&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;    log&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;Answer &lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;+&lt;/span&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt;str&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;answer&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;    return&lt;/span&gt;&lt;span&gt; answer&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Checkout the &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://github.com/applied-knowledge-systems/the-pattern-api/blob/156633b9934f1243775671ce6c18ff2bf471c0ce/qasearch/qa_redisai_keymiss_no_cache_np.py#L34&quot;&gt;full code, available on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The process for making a BERT QA API call looks like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://reference-architecture.ai/docs/bert-qa-benchmarking/diagrams_02.png&quot; alt=&quot;Architecture Diagram for BERT QA RedisGears and RedisAI&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Here I use two cool features of RedisGears: capturing events on key miss and using async/await to run RedisAI on each shard without locking the primary thread - so that Redis Cluster can continue to serve other customers. For benchmarks, caching responses from RedisAI is &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://github.com/applied-knowledge-systems/the-pattern-api/blob/156633b9934f1243775671ce6c18ff2bf471c0ce/qasearch/qa_redisai_keymiss_no_cache_np.py#L29&quot;&gt;disabled&lt;/a&gt;. If you are getting response times in nanoseconds on the second call rather then milliseconds, check to make sure the line linked above is commented out.&lt;/p&gt;
&lt;h1 id=&quot;running-the-benchmark&quot;&gt;Running the Benchmark&lt;/h1&gt;
&lt;p&gt;Pre-requisites for running the benchmark:&lt;/p&gt;
&lt;p&gt;Assuming you are running Debian or Ubuntu and have Docker and docker-compose installed (or can create a virtual environment via conda), run the following commands:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;git clone --recurse-submodules https://github.com/applied-knowledge-systems/the-pattern.git&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;cd the-pattern&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;./bootstrap_benchmark.sh&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above commands should end with a curl call to the qasearch API, since Redis caching is disabled for the benchmark.&lt;/p&gt;
&lt;p&gt;Next, invoke curl like this:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;time curl -i -H &amp;quot;Content-Type: application/json&amp;quot; -X POST -d &amp;#39;{&amp;quot;search&amp;quot;:&amp;quot;Who performs viral transmission among adults&amp;quot;}&amp;#39; http://localhost:8080/qasearch&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Expect the following output, or something similar based on your runtime environment:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;HTTP/1.1 200 OK&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Server: nginx/1.18.0 (Ubuntu)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Date: Sun, 29 May 2022 12:05:39 GMT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Content-Type: application/json&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Content-Length: 2120&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Connection: keep-alive&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&amp;quot;links&amp;quot;:[{&amp;quot;created_at&amp;quot;:&amp;quot;2002&amp;quot;,&amp;quot;rank&amp;quot;:13,&amp;quot;source&amp;quot;:&amp;quot;C0001486&amp;quot;,&amp;quot;target&amp;quot;:&amp;quot;C0152083&amp;quot;}],&amp;quot;results&amp;quot;:[{&amp;quot;answer&amp;quot;:&amp;quot;adenovirus&amp;quot;,&amp;quot;sentence&amp;quot;:&amp;quot;The medium of 40 T150 flasks of adenovirus transducer dec CAR CHO cells yielded 0 5 1 my of purified msCEACAM1a 1 4 protein&amp;quot;,&amp;quot;sentencekey&amp;quot;:&amp;quot;sentence:PMC125375.xml:{mG}:202&amp;quot;,&amp;quot;title&amp;quot;:&amp;quot;Crystal structure of murine sCEACAM1a[1,4]: a coronavirus receptor in the CEA family&amp;quot;}] OUTPUT_REDUCTED}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I modified the output of API for the benchmark to return results from all shards - even if the answer is empty, in the run above five shards return answers, overall API call response under second with all additional hops to search in RedisGraph.&lt;/p&gt;
&lt;p&gt;I modified the output of the API for the benchmark to return results from all shards - even if the answer is empty. In the run above five shards return answers. The overall API call response takes less than one second with all additional hops to search in RedisGraph!&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://reference-architecture.ai/docs/bert-qa-benchmarking/diagrams_01.png&quot; alt=&quot;Architecture Diagram for BERT QA API call&quot; /&gt;&lt;/p&gt;
&lt;h1 id=&quot;deep-dive-into-the-benchmark&quot;&gt;Deep Dive into the Benchmark&lt;/h1&gt;
&lt;p&gt;Let&#39;s dig deeper into what&#39;s happening under the hood:&lt;/p&gt;
&lt;p&gt;You should have a sentence key with shard id, which you get by looking at the &quot;Cache key&quot; from &lt;code&gt;docker logs -f rgcluster&lt;/code&gt;. In my setup the cache key is, &quot;bertqa{6fd}_PMC169038.xml:{6fd}:33_Who performs viral transmission among adults&quot;. If you think it looks like a function call it&#39;s because it is a function call. It is triggered if the key isn&#39;t present in the Redis Cluster, which for the benchmark will be every time since if you remember we disabled caching the output.&lt;/p&gt;
&lt;p&gt;One more thing to figure out from the logs is the port of the shard corresponding to the hashtag, also known as the &lt;code&gt;shard id&lt;/code&gt;. It is the text found in betweeen the curly brackets – looks like &lt;code&gt;{6fd}&lt;/code&gt; above. The same will be in the output for the &lt;code&gt;export_load&lt;/code&gt; script. In my case the cache key was found in &quot;30012.log&quot;, so my port is 30012.&lt;/p&gt;
&lt;p&gt;Next I run the following command:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;redis-cli -c -p 300012 -h 127.0.0.1 get &amp;quot;bertqa{6fd}_PMC169038.xml:{6fd}:33_Who performs viral transmission among adults&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and then run the benchmark:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;redis-benchmark -p 30012 -h 127.0.0.1 -n 10 get &amp;quot;bertqa{6fd}_PMC169038.xml:{6fd}:33_Who performs viral transmission among adults&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;====== get bertqa{6fd}_PMC169038.xml:{6fd}:33_Who performs viral transmission among adults ======&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  10 requests completed in 0.04 seconds&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  50 parallel clients&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  3 bytes payload&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  keep alive: 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;10.00% &amp;lt;= 41 milliseconds&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;100.00% &amp;lt;= 41 milliseconds&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;238.10 requests per second&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you are wondering, &lt;code&gt;-n&lt;/code&gt; = number of times. In this case we run the benchmark 10 times. You can also add:&lt;/p&gt;
&lt;p&gt;– &lt;code&gt;csv&lt;/code&gt; if you want to output in CSV format&lt;/p&gt;
&lt;p&gt;– &lt;code&gt;precision 3&lt;/code&gt; if you want more decimals in the ms&lt;/p&gt;
&lt;p&gt;More information about the benchmarking tool can be found on the &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://redis.io/topics/benchmarks&quot;&gt;redis.io Benchmarks page&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;if you don&#39;t have redis-utils installed locally, you can use Docker as follows:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; exec&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; -it&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; rgcluster /bin/bash&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;redis-benchmark&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 30012&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; -h&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 127.0.0.1&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; -n&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 10&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; get&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;bertqa{6fd}_PMC169038.xml:{6fd}:33_Who performs viral transmission among adults&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;====== get bertqa{6fd}_PMC169038.xml:{6fd}:33_Who performs viral transmission among adults ======&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;  10&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; requests completed in&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 1.75&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; seconds&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;  50&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; parallel clients&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;  99&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; bytes payload&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;  keep&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; alive:&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;  host&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; configuration&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;save&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;  host&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; configuration&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;appendonly&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;: no&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;  multi-thread:&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; no&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Latency&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; by percentile distribution:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;0.000%&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 243.711&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; milliseconds&lt;/span&gt;&lt;span&gt; (cumulative&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; count&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;50.000%&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 987.135&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; milliseconds&lt;/span&gt;&lt;span&gt; (cumulative&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; count&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 5&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;75.000%&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 1577.983&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; milliseconds&lt;/span&gt;&lt;span&gt; (cumulative&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; count&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 8&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;87.500%&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 1662.975&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; milliseconds&lt;/span&gt;&lt;span&gt; (cumulative&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; count&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 9&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;93.750%&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 1744.895&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; milliseconds&lt;/span&gt;&lt;span&gt; (cumulative&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; count&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 10&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;100.000%&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 1744.895&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; milliseconds&lt;/span&gt;&lt;span&gt; (cumulative&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; count&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 10&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Cumulative&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; distribution of latencies:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;0.000%&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 0.103&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; milliseconds&lt;/span&gt;&lt;span&gt; (cumulative&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; count&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 0&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;10.000%&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 244.223&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; milliseconds&lt;/span&gt;&lt;span&gt; (cumulative&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; count&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;20.000%&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 409.343&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; milliseconds&lt;/span&gt;&lt;span&gt; (cumulative&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; count&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 2&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;30.000%&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 575.487&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; milliseconds&lt;/span&gt;&lt;span&gt; (cumulative&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; count&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 3&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;40.000%&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 821.247&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; milliseconds&lt;/span&gt;&lt;span&gt; (cumulative&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; count&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 4&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;50.000%&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 987.135&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; milliseconds&lt;/span&gt;&lt;span&gt; (cumulative&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; count&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 5&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;60.000%&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 1157.119&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; milliseconds&lt;/span&gt;&lt;span&gt; (cumulative&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; count&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 6&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;70.000%&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 1497.087&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; milliseconds&lt;/span&gt;&lt;span&gt; (cumulative&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; count&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 7&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;80.000%&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 1577.983&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; milliseconds&lt;/span&gt;&lt;span&gt; (cumulative&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; count&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 8&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;90.000%&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 1662.975&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; milliseconds&lt;/span&gt;&lt;span&gt; (cumulative&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; count&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 9&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;100.000%&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 1744.895&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; milliseconds&lt;/span&gt;&lt;span&gt; (cumulative&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; count&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 10&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Summary:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;  throughput&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; summary:&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 5.73&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; requests per second&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;  latency&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; summary&lt;/span&gt;&lt;span&gt; (msec):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;          avg&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;       min       p50       p95       p99       max&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;     1067.296&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt;   243.584   987.135  1744.895  1744.895  1744.895&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The platform only has 20 articles and 8 Redis nodes (4 masters + 4 slaves), so relevance would be wrong and it doesn&#39;t need a lot of memory.&lt;/p&gt;
&lt;h2 id=&quot;ai-info&quot;&gt;AI.INFO&lt;/h2&gt;
&lt;p&gt;Now let&#39;s check how long our RedisAI model runs on the &lt;code&gt;{6fd}&lt;/code&gt; shard:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;127.0.0.1:30012&amp;gt; AI.INFO bert-qa{6fd}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 1) &amp;quot;key&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 2) &amp;quot;bert-qa{6fd}&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 3) &amp;quot;type&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 4) &amp;quot;MODEL&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 5) &amp;quot;backend&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 6) &amp;quot;TORCH&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 7) &amp;quot;device&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 8) &amp;quot;CPU&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 9) &amp;quot;tag&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;10) &amp;quot;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;11) &amp;quot;duration&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;12) (integer) 8928136&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;13) &amp;quot;samples&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;14) (integer) 58&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;15) &amp;quot;calls&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;16) (integer) 58&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;17) &amp;quot;errors&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;18) (integer) 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;bert-qa{6fd}&lt;/code&gt; is the key of the actual (very large) model saved. The &lt;code&gt;AI.INFO&lt;/code&gt; command gives us a cumulative duration of 8928136 microseconds and 58 calls, which is approximately 153 milliseconds per call.&lt;/p&gt;
&lt;p&gt;Let&#39;s double-check to make sure that&#39;s right by resetting the stats and then re-runnning the benchmark.&lt;/p&gt;
&lt;p&gt;First, reset the stats:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;127.0.0.1:30012&amp;gt; AI.INFO bert-qa{6fd} RESETSTAT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;OK&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;127.0.0.1:30012&amp;gt; AI.INFO bert-qa{6fd}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 1) &amp;quot;key&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 2) &amp;quot;bert-qa{6fd}&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 3) &amp;quot;type&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 4) &amp;quot;MODEL&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 5) &amp;quot;backend&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 6) &amp;quot;TORCH&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 7) &amp;quot;device&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 8) &amp;quot;CPU&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 9) &amp;quot;tag&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;10) &amp;quot;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;11) &amp;quot;duration&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;12) (integer) 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;13) &amp;quot;samples&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;14) (integer) 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;15) &amp;quot;calls&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;16) (integer) 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;17) &amp;quot;errors&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;18) (integer) 0&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, re-run the benchmark:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;redis-benchmark -p 30012 -h 127.0.0.1 -n 10 get &amp;quot;bertqa{6fd}_PMC169038.xml:{6fd}:33_Who performs viral transmission among adults&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;====== get bertqa{6fd}_PMC169038.xml:{6fd}:33_Who performs viral transmission among adults ======&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  10 requests completed in 1.78 seconds&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  50 parallel clients&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  99 bytes payload&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  keep alive: 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  host configuration &amp;quot;save&amp;quot;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  host configuration &amp;quot;appendonly&amp;quot;: no&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  multi-thread: no&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Latency by percentile distribution:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0.000% &amp;lt;= 188.927 milliseconds (cumulative count 1)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;50.000% &amp;lt;= 995.839 milliseconds (cumulative count 5)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;75.000% &amp;lt;= 1606.655 milliseconds (cumulative count 8)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;87.500% &amp;lt;= 1692.671 milliseconds (cumulative count 9)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;93.750% &amp;lt;= 1779.711 milliseconds (cumulative count 10)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;100.000% &amp;lt;= 1779.711 milliseconds (cumulative count 10)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Cumulative distribution of latencies:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0.000% &amp;lt;= 0.103 milliseconds (cumulative count 0)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;10.000% &amp;lt;= 189.183 milliseconds (cumulative count 1)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;20.000% &amp;lt;= 392.191 milliseconds (cumulative count 2)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;30.000% &amp;lt;= 540.159 milliseconds (cumulative count 3)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;40.000% &amp;lt;= 896.511 milliseconds (cumulative count 4)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;50.000% &amp;lt;= 996.351 milliseconds (cumulative count 5)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;60.000% &amp;lt;= 1260.543 milliseconds (cumulative count 6)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;70.000% &amp;lt;= 1456.127 milliseconds (cumulative count 7)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;80.000% &amp;lt;= 1606.655 milliseconds (cumulative count 8)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;90.000% &amp;lt;= 1692.671 milliseconds (cumulative count 9)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;100.000% &amp;lt;= 1779.711 milliseconds (cumulative count 10)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Summary:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  throughput summary: 5.62 requests per second&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  latency summary (msec):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          avg       min       p50       p95       p99       max&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     1080.454   188.800   995.839  1779.711  1779.711  1779.711&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now check the stats again:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;AI.INFO bert-qa{6fd}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 1) &amp;quot;key&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 2) &amp;quot;bert-qa{6fd}&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 3) &amp;quot;type&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 4) &amp;quot;MODEL&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 5) &amp;quot;backend&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 6) &amp;quot;TORCH&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 7) &amp;quot;device&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 8) &amp;quot;CPU&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 9) &amp;quot;tag&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;10) &amp;quot;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;11) &amp;quot;duration&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;12) (integer) 1767749&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;13) &amp;quot;samples&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;14) (integer) 20&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;15) &amp;quot;calls&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;16) (integer) 20&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;17) &amp;quot;errors&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;18) (integer) 0&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we get 88387.45 microseconds per call ~0.088387 seconds, which is pretty fast! Also, considering we started with 10 seconds per call, I think the benefits of using RedisAI in combination with RedisGears are pretty obvious. However, the trade-off is high memory usage.&lt;/p&gt;
&lt;p&gt;There are many ways to optimize this deployment. For example, you can add a FP16 quantization and ONNX runtime. If you would like to try that, &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://github.com/applied-knowledge-systems/the-pattern-api/blob/7bcf021e537dc8d453036730f0a993dd52e1781f/qasearch/export_load_bert.py&quot;&gt;this script&lt;/a&gt; will be a good starting point.&lt;/p&gt;
&lt;h1 id=&quot;using-grafana-to-monitor-redisgears-throughput-cpu-and-memory-usage&quot;&gt;Using Grafana to monitor RedisGears throughput, CPU, and Memory usage&lt;/h1&gt;
&lt;p&gt;Thanks to the contribution of &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://web.archive.org/web/20221231201518/https://volkovlabs.com/from-a-basic-redistimeseries-data-source-to-2-million-downloads-in-grafana-marketplace-9921ed9ac5a&quot;&gt;Mikhail Volkov&lt;/a&gt;, we can now observe RedisGears and RedisGraph throughput and memory consumption using Grafana. When you cloned repository it started Graphana Docker, which has pre-build templates to monitor RedisCluster, including RedisGears and RedisAI, and Graph - which is Redis with RedisGraph. &quot;The Pattern&quot; dashboard provides an overview, with all the key benchmark metrics you care about:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://reference-architecture.ai/docs/bert-qa-benchmarking/graphana_redis_graph.png&quot; alt=&quot;Grafana for RedisGraph&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://reference-architecture.ai/docs/bert-qa-benchmarking/graphana_cluster_overview.png&quot; alt=&quot;Grafana for RedisCluster&quot; /&gt;&lt;/p&gt;
&lt;p&gt;This post is in collaboration with Redis.&lt;/p&gt;
</description>
      </item>
      <item>
          <title>Capability Map (2020-2022)</title>
          <pubDate>Thu, 16 Jun 2022 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://reference-architecture.ai/docs/legacy-capability-map/</link>
          <guid>https://reference-architecture.ai/docs/legacy-capability-map/</guid>
          <description xml:base="https://reference-architecture.ai/docs/legacy-capability-map/">&lt;h1 id=&quot;introduction&quot;&gt;Introduction&lt;/h1&gt;
&lt;p&gt;There are tools for advanced analytics, including free ones from Google and Kaggle.&lt;/p&gt;
&lt;p&gt;There are well-known and validated deployment architectures for applications and the cloud.&lt;/p&gt;
&lt;p&gt;Yet the number of practical applications is still tiny, and they retained niche implementations.
While the benefits of AI are clear, there are still many gaps in AI architecture that need to be filled. For example, there is a gap between analytical tools and verified architectures for real-time deployments. This gap often stems from a lack of specific reference architectures and patterns, demonstrating the trade-offs between technologies, libraries, and tools.&lt;/p&gt;
&lt;p&gt;Let&#39;s bridge the gap in knowledge and drive a connection between science and engineering to make fast, efficient, and practical AI deployments.&lt;/p&gt;
&lt;p&gt;Three things need to be in place to build an AI product:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;AI Product itself&lt;/li&gt;
&lt;li&gt;Core Capabilities required to build AI/ML product&lt;/li&gt;
&lt;li&gt;Enabling capabilities&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I will use &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://thepattern.digital/&quot;&gt;The Pattern&lt;/a&gt;, my &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://redis.com/blog/build-on-redis-hackathon-winners/&quot;&gt;Build on Redis Hackathon&lt;/a&gt; prize-winning &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://github.com/applied-knowledge-systems/the-pattern&quot;&gt;open source&lt;/a&gt; project to illustrate how the capabilities below can be implemented and invite you to &lt;a href=&quot;https://reference-architecture.ai/docs/contribution/&quot;&gt;contribute&lt;/a&gt; or &lt;a href=&quot;https://reference-architecture.ai/docs/donate/&quot;&gt;donate&lt;/a&gt;.
The diagrams below are clickable.&lt;/p&gt;
&lt;h1 id=&quot;ai-product&quot;&gt;AI Product&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;/docs/ai-product/&quot;&gt;&lt;img src=&quot;/images/ai_product.drawio.svg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&quot;core-capabilities-for-ai-ml&quot;&gt;Core capabilities for AI/ML&lt;/h1&gt;
&lt;div class=&quot;mermaid-wrap&quot;&gt;&lt;pre class=&quot;mermaid&quot;&gt;
flowchart LR; 
subgraph &quot; &quot;
  data_intake(Data Acquisition);
  data_preprocessing(Data Preprocessing);
  data_validation(Data Validation);
  data_streaming(Data Streaming);
  ai_ml_pipe(AI ML Pipeline &lt;br/&gt; Model Training/Test/Validation);
  kg(Knowledge Graph);
  ML_inference(ML Inference);
  interaction(Interaction Layer&lt;br/&gt;Voice/VR/AR/Meta);
  click data_intake &quot;/docs/intake/&quot; &quot;Data Acquisition&quot;
  click ML_inference &quot;/docs/bert-qa-benchmarking/&quot; &quot;BERT Large Question Answering&quot;
  click kg &quot;/docs/nlp/#what-is-a-knowledge-graph&quot; &quot;Knowledge Graph&quot;
  click data_preprocessing &quot;/docs/nlp/#redisgears-for-nlp-pre-processing&quot; &quot;Data pre-processing&quot;
  click data_streaming &quot;/docs/nlp/#goal&quot; &quot;Data Streaming&quot;
  click ai_ml_pipe &quot;/docs/nlp/#overall-architecture-overview-components-diagram&quot; &quot;Overall ML pipeline&quot;
end
&lt;/pre&gt;&lt;/div&gt;
&lt;h1 id=&quot;enabling-capabilities&quot;&gt;Enabling Capabilities&lt;/h1&gt;
&lt;div class=&quot;mermaid-wrap&quot;&gt;&lt;pre class=&quot;mermaid&quot;&gt;
flowchart LR;
subgraph 2 [Enabling Capabilities]
  subgraph &quot; &quot;
D1[Data Governance]
D2[Data Quality Management]
D3[Metadata Management]
click D3 &quot;/docs/metadata/&quot; &quot;Metadata Management&quot;
end
subgraph &quot; &quot;
  id2[ML performance and bias monitoring];
  id3[Application Performance Monitoring];
  id4[Hardware Performance Monitoring];
  click id3 &quot;/docs/bert-qa-benchmarking/#running-the-benchmark&quot; &quot;Running Benchmarks&quot;
  click id4 &quot;/docs/bert-qa-benchmarking/#using-grafana-to-monitor-redisgears-throughput-cpu-and-memory-usage&quot; &quot;CPU and Memory Benchmarks&quot;
end
subgraph &quot; &quot;
  id5[DevOps: Continuous Integration/Continuous Deployment];
  c1[Configuration management]
  c2[Collaboration and knowledge management tooling]
  c3[Change Management]
end 
  subgraph 3 [Self Serving Infrastructure]
    s1[Computing Infrastructure]
    s2[Serving infrastructure]
  end
  end
  style 2 fill:#485fc754,stroke:#333,stroke-width:4px;
&lt;/pre&gt;&lt;/div&gt;
</description>
      </item>
      <item>
          <title>Announcing Reference Architecture for AI</title>
          <pubDate>Thu, 16 Jun 2022 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://reference-architecture.ai/posts/post-0/</link>
          <guid>https://reference-architecture.ai/posts/post-0/</guid>
          <description xml:base="https://reference-architecture.ai/posts/post-0/">&lt;p&gt;There are tools for advanced analytics, including free ones from Google and Kaggle.&lt;/p&gt;
&lt;p&gt;There are well-known and validated deployment architectures for applications and the cloud.&lt;/p&gt;
&lt;p&gt;Yet the number of practical applications is still tiny, and they retained niche implementations.
While the benefits of AI are clear, there are still many gaps in AI architecture that need to be filled. For example, there is a gap between analytical tools and verified architectures for real-time deployments. This gap often stems from a lack of specific reference architectures and patterns, demonstrating the trade-offs between technologies, libraries, and tools.&lt;/p&gt;
&lt;p&gt;Let&#39;s bridge the gap in knowledge and drive a connection between science and engineering to make fast, efficient, and practical AI deployments.
Three things need to be in place to build an AI product:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;AI Product itself&lt;/li&gt;
&lt;li&gt;Core Capabilities required to build AI/ML product&lt;/li&gt;
&lt;li&gt;Enabling capabilities&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I will use &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://thepattern.digital/&quot;&gt;The Pattern&lt;/a&gt;, my [“Build on Redis&lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://redis.com/blog/build-on-redis-hackathon-winners/&quot;&gt;” Hackathon &lt;/a&gt;prize-winning &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://github.com/applied-knowledge-systems/the-pattern&quot;&gt;open source&lt;/a&gt;](https://github.com/applied-knowledge-systems/the-pattern) project, to illustrate how the capabilities below can be implemented and invite you to &lt;a href=&quot;https://reference-architecture.ai/docs/contribution/&quot;&gt;contribute&lt;/a&gt; or &lt;a href=&quot;https://reference-architecture.ai/docs/donate/&quot;&gt;donate&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We launch in two full-featured articles - &lt;a href=&quot;https://reference-architecture.ai/docs/nlp/&quot;&gt;NLP ML pipeline for&lt;/a&gt; turning unstructured JSON text into a knowledge graph and fresh off the press &lt;a href=&quot;https://reference-architecture.ai/docs/bert-qa-benchmarking/&quot;&gt;Benchmarks for BERT Large Question Answering inference for RedisAI and RedisGears&lt;/a&gt; with Grafana Dashboards by &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://web.archive.org/web/20221231201518/https://volkovlabs.com/from-a-basic-redistimeseries-data-source-to-2-million-downloads-in-grafana-marketplace-9921ed9ac5a&quot;&gt;Mikhail Volkov&lt;/a&gt;&lt;/p&gt;
</description>
      </item>
      <item>
          <title>Building a Pipeline for Natural Language Processing using RedisGears</title>
          <pubDate>Sat, 28 May 2022 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://reference-architecture.ai/docs/nlp/</link>
          <guid>https://reference-architecture.ai/docs/nlp/</guid>
          <description xml:base="https://reference-architecture.ai/docs/nlp/">&lt;h2 id=&quot;goal&quot;&gt;Goal&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Disclaimer&lt;/em&gt; originally published in collaboration with &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://github.com/ajeetraina&quot;&gt;Ajeet Raina&lt;/a&gt; on &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://developer.redis.com/howtos/nlp/&quot;&gt;Developer.Redis.Com&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In this tutorial, you will learn how to build a pipeline for  Natural Language Processing(NLP) using &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://developer.redis.com/howtos/redisgears&quot;&gt;RedisGears&lt;/a&gt;. For this demonstration, we will be leveraging the Kaggle CORD19 datasets. The implementation is designed to avoid running out of memory, leveraging Redis Cluster and RedisGears, where the use of RedisGears allows for processing data on storage without the need to move data in and out of the Redis Cluster—using Redis Cluster as data fabric. Redis Cluster allows for horizontal scalability up to 1000 nodes, and together with RedisGears, provides a distributed system where data science/ML engineers can focus on processing steps, without the worry of writing tons of scaffoldings for distributed calculations.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://reference-architecture.ai/docs/nlp/nlparch.png&quot; alt=&quot;nlp&quot; /&gt;&lt;/p&gt;
&lt;p&gt;This project was built with the aim to make it easier for other people to contribute and build better information and knowledge management products.&lt;/p&gt;
&lt;h2 id=&quot;why-data-scientists-uses-redisgears&quot;&gt;Why data scientists uses RedisGears?&lt;/h2&gt;
&lt;p&gt;&lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://redis.com/modules/redis-gears/&quot;&gt;RedisGears&lt;/a&gt; have enormous potential, particularly for text processing—you can process your data “on data” without needing to move them in and out of memory. Summary of the important points:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In Memory storage (Horizontally scalable if it’s Redis cluster)&lt;/li&gt;
&lt;li&gt;Processing of data (on data) without need to move in and out&lt;/li&gt;
&lt;li&gt;Gears - like Spark on Hadoop, process data intelligently on storage(in-memory) without need to move data in and out&lt;/li&gt;
&lt;li&gt;Redis in cluster mode with RedisGears and python enabled takes 20 MB RAM. Think how much more data you can shuffle into your laptop or server.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;what-is-a-knowledge-graph&quot;&gt;What is a knowledge graph?&lt;/h2&gt;
&lt;p&gt;Today, we live in the world of new systems that operate not just files, folders, or web pages, but entities with their properties and relationships between them, organized into hierarchies of classes and categories. These systems are used everywhere from the military-industrial complex to our everyday lives. Palantir, Primer, and other data companies enable massive intelligence and counterintelligence projects in military and security forces, Quid and RecordedFuture enable competitive analytics, Bottlenose and similar enterprises enable online reputation analytics. Microsoft Graph enables new kinds of productivity apps for the enterprises, Google Knowledge Graph and Microsoft’s Satori enable everyday search queries, and together with Amazon Information Graph they power corresponding AI assistants by enabling them to answer questions about the world facts&lt;/p&gt;
&lt;p&gt;All these (and many other more specialized) systems are used in different domains, but all of them use Knowledge Graphs as their foundation.&lt;/p&gt;
&lt;p&gt;Knowledge graphs are one of the best ways to connect and make sense out of information from different data sources, following the motto of one of the vendors— &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://www.poolparty.biz/news-events/knowledge-graphs-connecting-dots-increasingly-complex-world/&quot;&gt;“It’s about things not strings”&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Knowledge Graph consists of thesaurus, taxonomy and ontology. In this pipeline I assume knowledge is captured in medical metathesaurus &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://www.nlm.nih.gov/research/umls/index.html&quot;&gt;UMLS&lt;/a&gt; and concepts in text are related if they are part of the same sentence, therefore concept become node, their relationship becomes edge:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://reference-architecture.ai/docs/nlp/concepts1.png&quot; alt=&quot;concepts1&quot; /&gt;
&lt;img src=&quot;https://reference-architecture.ai/docs/nlp/concepts2.png&quot; alt=&quot;concepts2&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Concepts have CUI (Concept Unique Identifiers) and those will be primary keys in nodes, linked to UMLS thesaurus. For example, if you search, “How does temperature and humidity affect the transmission of 2019-nCoV?” on the demo website  &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;http://thepattern.digital&quot;&gt;http://thepattern.digital/&lt;/a&gt; and move slider to 1996, there is an edge-connecting transmission (C5190195) and birth (C5195639) and the part of sentence matched, “the rate of transmission to an infant born to,” from the report titled, “Afebrile Pneumonia in infants.”&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://reference-architecture.ai/docs/nlp/concepts3.png&quot; alt=&quot;concepts3&quot; /&gt;&lt;/p&gt;
&lt;h2 id=&quot;redisgears-for-nlp-pre-processing&quot;&gt;RedisGears for NLP pre-processing&lt;/h2&gt;
&lt;h3 id=&quot;overall-architecture-overview-components-diagram&quot;&gt;Overall Architecture Overview (Components Diagram)&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://reference-architecture.ai/docs/nlp/component_diagram.png&quot; alt=&quot;component_diagram&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Intake step - is very simple put all JSON records into RedisCluster, then NLP pipeline starts processing all records, code is &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://github.com/applied-knowledge-systems/the-pattern-platform/blob/main/RedisIntakeRedisClusterSample.py&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;how-does-the-nlp-pipeline-steps-fit-into-redisgears&quot;&gt;How does the NLP pipeline steps fit into RedisGears?&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;For each record — detect language (discard non English), it’s &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://web.archive.org/web/20240318030547/https://oss.redis.com/redisgears/operations.html#filter&quot;&gt;filter&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Map paragraphs into a sentence — &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://web.archive.org/web/20240318030547/https://oss.redis.com/redisgears/operations.html#flatmap&quot;&gt;flatmap&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Sentences spellchecker — it’s &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://web.archive.org/web/20240318030547/https://oss.redis.com/redisgears/operations.html#map&quot;&gt;map&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Save sentences into hash — &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://web.archive.org/web/20240318030547/https://oss.redis.com/redisgears/operations.html#processor&quot;&gt;processor&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;step-1-pre-requisite&quot;&gt;Step 1. Pre-requisite&lt;/h3&gt;
&lt;p&gt;Ensure that you install virtualenv in your system&lt;/p&gt;
&lt;h3 id=&quot;step-2-clone-the-repository&quot;&gt;Step 2. Clone the repository&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; git&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; clone&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; --recurse-submodules&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; https://github.com/applied-knowledge-systems/the-pattern.git&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt; cd&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; the-pattern&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;step-3-bring-up-the-application&quot;&gt;Step 3. Bring up the application&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; docker-compose&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; docker-compose.dev.yml up&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; --build -d&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;step-4-apply-cluster-configuration-settings&quot;&gt;Step 4. Apply cluster configuration settings&lt;/h3&gt;
&lt;p&gt;You can deploy PyTorch and spacy to run on RedisGears.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; bash&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; post_start_dev.sh&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;For Data science-focused deployment, RedisCluster should be in HA mode with at least one slave for each master.
One need to change a few default parameters for rgcluster to accommodate the size of PyTorch and spacy libraries (each over 1GB zipped), gist with settings.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;step-5-create-or-activate-python-virtual-environment&quot;&gt;Step 5. Create or activate Python virtual environment&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt; cd&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; ./the-pattern-platform/&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;step-6-create-new-environment&quot;&gt;Step 6. Create new environment&lt;/h3&gt;
&lt;p&gt;You can create it via&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; conda&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; create&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; -n&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; pattern_env python=&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt;3.8&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;or&lt;/p&gt;
&lt;p&gt;Alternatively, you can activate by using the below CLI:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt; source&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; ~/venv_cord19/bin/activate&lt;/span&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt; #or create new venv&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; pip&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; -r&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; requirements.txt&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;step-7-run-pipeline&quot;&gt;Step 7. Run pipeline&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; bash cluster_pipeline.sh&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;step-8-validating-the-functionality-of-the-nlp-pipeline&quot;&gt;Step 8. Validating the functionality of the NLP pipeline&lt;/h3&gt;
&lt;p&gt;Wait for a bit and then check:&lt;/p&gt;
&lt;h3 id=&quot;verifying-redis-graph-populated&quot;&gt;Verifying Redis Graph populated:&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; redis-cli&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 9001&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; -h&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 127.0.0.1&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; GRAPH.QUERY cord19medical&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;MATCH (n:entity) RETURN count(n) as entity_count&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; redis-cli&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 9001&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; -h&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 127.0.0.1&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; GRAPH.QUERY cord19medical&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;MATCH (e:entity)-[r]-&amp;gt;(t:entity) RETURN count(r) as edge_count&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;checking-api-responds&quot;&gt;Checking API responds:&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; curl&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; -i -H&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;Content-Type: application/json&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; -X&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; POST&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; -d&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;{&amp;quot;search&amp;quot;:&amp;quot;How does temperature and humidity affect the transmission of 2019-nCoV&amp;quot;}&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; http://localhost:8080/gsearch&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;walkthrough&quot;&gt;Walkthrough&lt;/h2&gt;
&lt;p&gt;While RedisGears allows to deploy and run Machine Learning libraries like &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://github.com/AlexMikhalev/cord19redisknowledgegraph/blob/master/spacy_sentences_geared.py&quot;&gt;spacy&lt;/a&gt; and &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://github.com/AlexMikhalev/cord19redisknowledgegraph/blob/master/tokenizer_bert_geared.py&quot;&gt;BERT transformers&lt;/a&gt;, the solution above uses simpler approach:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot; &gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; gb&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; GB&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;KeysReader&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; gb&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;filter&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;filter_language&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; gb&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;flatmap&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;parse_paragraphs&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; gb&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;map&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;spellcheck_sentences&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; gb&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;foreach&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;save_sentences&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; gb&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;count&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; gb&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;register&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;paragraphs:*&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;,&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;keyTypes&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=[&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;,&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;hash&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;],&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; mode&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;async_local&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is the overall pipeline: those 7 lines allow you to run logic in a distributed cluster or on a single machine using all available CPUs - no changes required until you need to scale over more 1000 nodes. I use KeysReader registered for namespace paragraphs for all strings or hashes. My pipeline would need to run in async mode. For data scientists, I would recommend using gb.run to make sure gears function work and it will run in batch mode and then change it to register - to capture new data. By default, functions will return output, hence the need for count() - to prevent fetching the whole dataset back to the command issuing machine (90 GB for Cord19).&lt;/p&gt;
&lt;p&gt;Overall pre-processing is a straightforward - &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://github.com/applied-knowledge-systems/the-pattern-platform/blob/main/gears_pipeline_sentence_register.py&quot;&gt;full code&lt;/a&gt; is here.&lt;/p&gt;
&lt;p&gt;Things to keep in mind:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Node process can only save locally - we don&#39;t move data, anything you want to save should have hashtag, for example to add to the set of processed_docs:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot; &gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; execute&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;SADD&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;,&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;processed_docs_{%s}&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39; %&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; hashtag&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;article_id&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Loading external libraries into the computational threat, for example, symspell requires additional dictionaries and needs two steps to load:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot; &gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt; &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt; load symspell and relevant dictionaries&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt; &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; sym_spell&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt;None&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; def&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; load_symspell&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;():&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;  import&lt;/span&gt;&lt;span&gt; pkg_resources&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;  from&lt;/span&gt;&lt;span&gt; symspellpy&lt;/span&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt; import&lt;/span&gt;&lt;span&gt; SymSpell&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;/span&gt;&lt;span&gt; Verbosity&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  sym_spell&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; SymSpell&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;max_dictionary_edit_distance&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; prefix_length&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt;7&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  dictionary_path&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; =&lt;/span&gt;&lt;span&gt; pkg_resources&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;resource_filename&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;      &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;symspellpy&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;frequency_dictionary_en_82_765.txt&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  bigram_path&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; =&lt;/span&gt;&lt;span&gt; pkg_resources&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;resource_filename&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;      &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;symspellpy&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;frequency_bigramdictionary_en_243_342.txt&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt;  # term_index is the column of the term and count_index is the&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt;  # column of the term frequency&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  sym_spell&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;load_dictionary&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;dictionary_path&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; term_index&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; count_index&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  sym_spell&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;load_bigram_dictionary&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;bigram_path&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; term_index&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; count_index&lt;/span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;  return&lt;/span&gt;&lt;span&gt; sym_spell&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Scispacy is a great library and data science tool, but after a few iterations with deploying it I ended up reading data model documentation for UMLS Methathesaurus and decided to build Aho-Corasick automata directly from UMLS data. (MRXW_ENG.RRF contains all terms form for English mapped to CUI). Aho-Corasick allowed me to match incoming sentences into pairs of nodes (concepts from the medical dictionary) and present sentences as edges in a graph, Gears related code is simple:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; bg = GearsBuilder(&amp;#39;KeysReader&amp;#39;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; bg.foreach(process_item)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; bg.count()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; bg.register(&amp;#39;sentence:*&amp;#39;,  mode=&amp;quot;async_local&amp;quot;,onRegistered=OnRegisteredAutomata)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;OnRegisteredAutomata will perform similarly to symspell example above except it will download pre-build Aho-Corasick automata (30Mb).
Aho-Corasick is a very fast matcher and allows to perform &amp;gt;900 Mb text per second even on commodity laptop, RedisGears cluster makes a very smooth distribution of data and ML model and matching using available CPU and Memory. Full matcher &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://github.com/applied-knowledge-systems/the-pattern-platform/blob/main/sentences_matcher_register.py&quot;&gt;code&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Output of the matcher: nodes and edges are candidates to use another RedisGears pattern rgsync where you can write fast into Redis and RedisGears are going to replicate data into slower storage using RedisStreams.
But I decided to use streams and handcraft the population of the RedisGraph database, which will be focus of the next blog post.&lt;/p&gt;
&lt;p&gt;Output of the matcher: nodes and edges are candidates to use another RedisGears pattern &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://github.com/RedisGears/rgsync&quot;&gt;rgsync&lt;/a&gt; where you can write fast into Redis and RedisGears are going to replicate data into slower storage using RedisStreams, while this demo uses streams and populates RedisGraph database with nodes and edges calculating rank of each.&lt;/p&gt;
&lt;h2 id=&quot;call-to-action&quot;&gt;Call to action&lt;/h2&gt;
&lt;p&gt;We took OCR scans in JSON format and turned them into Knowledge Graph, demonstrating how you can traditional Semantic Network/OWL/Methathesaurus technique based on Unified Medical Language System. Redis Ecosystem offers a lot to the data science community, and can take place at the core of Kaggle notebooks, ML frameworks and make deployment and distribution of data more enjoyable. The success of our industry depends on how our tools work together — regardless of whether they are engineering, data science, machine learning and organisational or architectural.&lt;/p&gt;
&lt;p&gt;With the collaboration of RedisLabs and community, the full pipeline code is available via https://github.com/applied-knowledge-systems/the-pattern-platform. In case, you want to try it locally, then you can find a Docker Launch script in the root of the repository along with short quickstart guide. PR and suggestions are welcome. The overall goal of the project is to allow other to build their more interesting pipeline on top of it.&lt;/p&gt;
&lt;h3 id=&quot;references&quot;&gt;References&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;http://thepattern.digital/&quot;&gt;Covid19 - Redis Knowledge Graph in 3D&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://www.kaggle.com/allen-institute-for-ai/CORD-19-research-challenge&quot;&gt;COVID-19 Open Research Dataset Challenge (CORD-19)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://github.com/applied-knowledge-systems/the-pattern-platform&quot;&gt;Source Code for NLP pipeline based on RedisGears &lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
      </item>
      <item>
          <title>Metadata Management</title>
          <pubDate>Sat, 14 May 2022 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://reference-architecture.ai/docs/metadata/</link>
          <guid>https://reference-architecture.ai/docs/metadata/</guid>
          <description xml:base="https://reference-architecture.ai/docs/metadata/">&lt;p&gt;In CORD 19 dataset mentioned in &lt;a href=&quot;https://reference-architecture.ai/docs/intake/&quot;&gt;Data Acquisition&lt;/a&gt; Metadata stored in the separate csv file from the source data. &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://github.com/applied-knowledge-systems/the-pattern-platform/blob/2168aa194cc9d84457e3faac0299939e307900ae/parse_publish_dates_threaded.py&quot;&gt;Here&lt;/a&gt; simple script to parse date/times and attach it to JSON/XML files&lt;/p&gt;
</description>
      </item>
      <item>
          <title>Contribution Guidelines</title>
          <pubDate>Wed, 15 Dec 2021 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://reference-architecture.ai/docs/contribution/</link>
          <guid>https://reference-architecture.ai/docs/contribution/</guid>
          <description xml:base="https://reference-architecture.ai/docs/contribution/">&lt;p&gt;General guidelines for contributing to the project.&lt;/p&gt;</description>
      </item>
      <item>
          <title>The Pattern: Machine Learning Natural Language Processing meets VR/AR</title>
          <pubDate>Mon, 31 Aug 2020 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://reference-architecture.ai/docs/ai-product/</link>
          <guid>https://reference-architecture.ai/docs/ai-product/</guid>
          <description xml:base="https://reference-architecture.ai/docs/ai-product/">&lt;p&gt;To fight ever-increasing complexity, &quot;The Pattern&quot; projects help find relevant knowledge using Artificial Intelligence and novel UX elements, all powered by Redis - a new generation real-time data fabric turned into knowledge fabric&lt;/p&gt;
&lt;p&gt;Overall repository for CORD19 medical NLP pipeline, API and UI, design and architecture.&lt;/p&gt;
&lt;p&gt;Demo Video:&lt;/p&gt;
&lt;div class=&quot;video-embed&quot;&gt;
  &lt;iframe src=&quot;https://www.youtube-nocookie.com/embed/zCqzB0YVgA0&quot; title=&quot;Embedded video&quot;
    loading=&quot;lazy&quot; frameborder=&quot;0&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot;
    allow=&quot;accelerometer; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot;
    allowfullscreen&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;Demo Server (no persistance): &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://thepattern.digital/&quot;&gt;https://thepattern.digital/&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&quot;the-challenge&quot;&gt;The challenge&lt;/h1&gt;
&lt;p&gt;The medical profession put a lot of effort into collaboration, starting from Latin as a common language to industry-wide thesauruses like &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://www.nlm.nih.gov/research/umls/index.html&quot;&gt;UMLS&lt;/a&gt;. However, if full of scandals where publications in a prestigious journal would be retracted, and the World Health Organisation would change its policy advice based on the article. I think &quot;paper claiming that eating a bat-like Pokémon sparked the spread of COVID-19&quot; takes a prize. One would say that editors in those journals don&#39;t do their job, and while it may seem true, I would say they had no chance: with a number of publications about COVID (SARS-V) passing 300+ per day, we need better tools to navigate via such flow of information.
When exploring science or engineering topics, I look at the diversity of the opinion, not the variety of the same cluster of words or the same thought. I want to avoid confirmation bias. I want to find articles relevant to the same concept, not necessarily the ones which have similar words. My focus is to build a natural language processing pipeline capable of handling a large number of documents and concepts, incorporating System 1 AI (fast, intuitive reasoning) and System 2 (high-level reasoning) and then present knowledge in a modern VR/AR visualisation. Search or rather information exploration should be spatial, preferably in VR (memory palace, see Theatre of Giulio Camillo). A force-directed graph is a path towards it, where visuals are assisted by text — relevant text pops up on the connection and where people explore the concepts and then dig deeper into the text. The purpose of the pipeline is that knowledge should be reusable and shareable.&lt;/p&gt;
&lt;h1 id=&quot;community&quot;&gt;Community&lt;/h1&gt;
&lt;p&gt;Join our community on &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://discord.gg/rdgsCuJ4P4&quot;&gt;Discord&lt;/a&gt; or post on &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://github.com/applied-knowledge-systems/the-pattern/discussions&quot;&gt;GitHub Discussions&lt;/a&gt;](https://github.com/applied-knowledge-systems/the-pattern/discussions)&lt;/p&gt;
</description>
      </item>
      <item>
          <title>Data Acquisition</title>
          <pubDate>Mon, 31 Aug 2020 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://reference-architecture.ai/docs/intake/</link>
          <guid>https://reference-architecture.ai/docs/intake/</guid>
          <description xml:base="https://reference-architecture.ai/docs/intake/">&lt;p&gt;For the Reference Architecture for AI, we used Kaggle &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://www.kaggle.com/datasets/allen-institute-for-ai/CORD-19-research-challenge&quot;&gt;Cord19 dataset&lt;/a&gt;, &quot;COVID-19 Open Research Dataset (CORD-19). CORD-19 is a resource of over 1,000,000 scholarly articles, including over 400,000 with full text, about COVID-19, SARS-CoV-2, and related coronaviruses. This freely available dataset is provided to the global research community to apply recent advances in natural language processing and other AI techniques to generate new insights in support of the ongoing fight against this infectious disease.&quot;&lt;/p&gt;
&lt;h1 id=&quot;ingest-documents&quot;&gt;Ingest documents&lt;/h1&gt;
&lt;p&gt;&lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://github.com/applied-knowledge-systems/the-pattern-platform/blob/6fe80e7bf6c8c3baf2d1bd6aa300ff1ef336d523/RedisIntakeRedisClusterSample.py&quot;&gt;Example script&lt;/a&gt; parses documents taking out body_text and saves under paragraphs in Redis cluster.&lt;/p&gt;
</description>
      </item>
    </channel>
</rss>
