Skip to content

Commit 575d860

Browse files
demo (kNN): adds example for vector search
1 parent 7ca7fc3 commit 575d860

File tree

5 files changed

+351
-0
lines changed

5 files changed

+351
-0
lines changed
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# Vector Search Example
2+
3+
This example demonstrates how to use the vector search capabilities in ReactiveSearch. Vector search lets you perform semantic similarity searches using embeddings.
4+
5+
## Features
6+
7+
- Uses `vectorDataField` prop to specify the vector field in your index
8+
- Uses `candidates` prop to control the number of nearest neighbors to find
9+
- Combines vector search with traditional filters using `MultiList`
10+
- Shows how the `react` prop connects components for complex queries
11+
12+
## How it works
13+
14+
1. The SearchBox component captures user input
15+
2. The value from SearchBox is used as input for the vector search
16+
3. The ReactiveList component uses the `vectorDataField` to search by semantic similarity
17+
4. Facet filtering is applied with the MultiList component
18+
19+
## Requirements
20+
21+
- An Elasticsearch/OpenSearch cluster with vector search capabilities
22+
- An index with vector embeddings
23+
- The appropriate mappings for vector fields
24+
25+
## Running this example
26+
27+
```bash
28+
# Install dependencies
29+
npm install
30+
31+
# Start the development server
32+
npm start
33+
```
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
{
2+
"name": "vector-search",
3+
"version": "0.1.0",
4+
"private": true,
5+
"dependencies": {
6+
"@appbaseio/reactivesearch": "file:../../",
7+
"react": "^18.2.0",
8+
"react-dom": "^18.2.0",
9+
"react-scripts": "5.0.1"
10+
},
11+
"scripts": {
12+
"start": "react-scripts start",
13+
"build": "react-scripts build",
14+
"test": "react-scripts test",
15+
"eject": "react-scripts eject"
16+
},
17+
"eslintConfig": {
18+
"extends": [
19+
"react-app",
20+
"react-app/jest"
21+
]
22+
},
23+
"browserslist": {
24+
"production": [
25+
">0.2%",
26+
"not dead",
27+
"not op_mini all"
28+
],
29+
"development": [
30+
"last 1 chrome version",
31+
"last 1 firefox version",
32+
"last 1 safari version"
33+
]
34+
}
35+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1" />
6+
<meta name="theme-color" content="#000000" />
7+
<meta
8+
name="description"
9+
content="ReactiveSearch Vector Search Example"
10+
/>
11+
<title>Vector Search Example</title>
12+
</head>
13+
<body>
14+
<noscript>You need to enable JavaScript to run this app.</noscript>
15+
<div id="root"></div>
16+
</body>
17+
</html>
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
body {
2+
margin: 0;
3+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
4+
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
5+
sans-serif;
6+
-webkit-font-smoothing: antialiased;
7+
-moz-osx-font-smoothing: grayscale;
8+
}
9+
10+
.container {
11+
max-width: 1000px;
12+
margin: 0 auto;
13+
padding: 2rem;
14+
}
15+
16+
.layout {
17+
display: flex;
18+
gap: 2rem;
19+
}
20+
21+
.facet-container {
22+
width: 250px;
23+
}
24+
25+
.results-container {
26+
flex: 1;
27+
}
28+
29+
.result-item {
30+
display: flex;
31+
align-items: flex-start;
32+
padding: 1rem 0;
33+
border-bottom: 1px solid #ddd;
34+
}
35+
36+
.company-logo {
37+
width: 50px;
38+
height: 50px;
39+
object-fit: contain;
40+
margin-right: 1rem;
41+
}
42+
43+
.company-info {
44+
flex: 1;
45+
}
46+
47+
.company-name {
48+
margin: 0 0 0.5rem;
49+
font-size: 1.2rem;
50+
color: #333;
51+
}
52+
53+
.company-oneliner {
54+
margin: 0 0 0.75rem;
55+
color: #555;
56+
}
57+
58+
.company-meta {
59+
display: flex;
60+
gap: 1rem;
61+
margin-bottom: 0.75rem;
62+
}
63+
64+
.meta-item {
65+
font-size: 0.85rem;
66+
color: #666;
67+
}
68+
69+
.company-tags {
70+
display: flex;
71+
flex-wrap: wrap;
72+
gap: 0.5rem;
73+
margin-bottom: 0.75rem;
74+
}
75+
76+
.tag {
77+
font-size: 0.75rem;
78+
background-color: #f0f0f0;
79+
padding: 0.25rem 0.5rem;
80+
border-radius: 4px;
81+
color: #555;
82+
}
83+
84+
.company-link {
85+
font-size: 0.85rem;
86+
color: #1a73e8;
87+
text-decoration: none;
88+
}
89+
90+
.company-link:hover {
91+
text-decoration: underline;
92+
}
93+
94+
.debug-panel {
95+
margin-top: 2rem;
96+
padding: 1rem;
97+
background-color: #f5f5f5;
98+
border-radius: 4px;
99+
}
100+
101+
.debug-panel code {
102+
background-color: #e0e0e0;
103+
padding: 0.2rem 0.4rem;
104+
border-radius: 3px;
105+
font-family: monospace;
106+
}
107+
108+
ul.facet-list {
109+
max-height: 500px;
110+
}
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
import React from 'react';
2+
import ReactDOM from 'react-dom/client';
3+
import {
4+
ReactiveBase,
5+
SearchBox,
6+
MultiList,
7+
ReactiveList,
8+
SelectedFilters,
9+
} from '@appbaseio/reactivesearch';
10+
import './index.css';
11+
12+
const App = () => {
13+
return (
14+
<ReactiveBase
15+
app="yc-companies-dataset"
16+
url="https://appbase-demo-ansible-abxiydt-arc.searchbase.io"
17+
credentials="a03a1cb71321:75b6603d-9456-4a5a-af6b-a487b309eb61"
18+
enableAppbase
19+
>
20+
<div className="container">
21+
<h2>Vector Search with ReactiveSearch</h2>
22+
<SearchBox
23+
componentId="search"
24+
dataField={['name', 'one_liner']}
25+
placeholder="Vector search on a dataset of startup companies"
26+
autosuggest={false}
27+
style={{ marginBottom: '1rem' }}
28+
URLParams
29+
/>
30+
<SelectedFilters />
31+
32+
<div className="layout">
33+
<div className="facet-container">
34+
<MultiList
35+
componentId="industries"
36+
dataField="industries.keyword"
37+
title="Industries"
38+
placeholder="Filter by industries"
39+
showSearch
40+
style={{ marginBottom: '1rem' }}
41+
aggregationSize={96}
42+
innerClass={{"list": "facet-list"}}
43+
/>
44+
</div>
45+
46+
<div className="results-container">
47+
<ReactiveList
48+
componentId="results"
49+
vectorDataField="vector_data"
50+
size={20}
51+
candidates={20}
52+
pagination={true}
53+
react={{
54+
and: ['search', 'industries'],
55+
}}
56+
includeFields={[
57+
'name',
58+
'one_liner',
59+
'long_description',
60+
'team_size',
61+
'stage',
62+
'industries',
63+
'website',
64+
'small_logo_thumb_url',
65+
]}
66+
render={({ data }) => (
67+
<>
68+
{data.map((item) => {
69+
const company = item._source || item;
70+
return (
71+
<div className="result-item" key={company._id}>
72+
{company.small_logo_thumb_url && (
73+
<img
74+
src={company.small_logo_thumb_url}
75+
alt={`${company.name} logo`}
76+
className="company-logo"
77+
/>
78+
)}
79+
<div className="company-info">
80+
<h3 className="company-name">{company.name}</h3>
81+
<p className="company-oneliner">
82+
{company.one_liner ||
83+
company.long_description}
84+
</p>
85+
<div className="company-meta">
86+
{company.team_size && (
87+
<span className="meta-item">
88+
Team: {company.team_size}
89+
</span>
90+
)}
91+
{company.stage && (
92+
<span className="meta-item">
93+
Stage: {company.stage}
94+
</span>
95+
)}
96+
</div>
97+
{company.industries &&
98+
company.industries.length > 0 && (
99+
<div className="company-tags">
100+
{company.industries.map((ind) => (
101+
<span className="tag" key={ind}>
102+
{ind}
103+
</span>
104+
))}
105+
</div>
106+
)}
107+
{company.website && (
108+
<a
109+
href={company.website}
110+
target="_blank"
111+
rel="noopener noreferrer"
112+
className="company-link"
113+
>
114+
Visit website
115+
</a>
116+
)}
117+
</div>
118+
</div>
119+
);
120+
})}
121+
</>
122+
)}
123+
renderNoResults={() => <div>No results found</div>}
124+
/>
125+
126+
{/* Debug Panel - Shows the queries and responses */}
127+
<div className="debug-panel">
128+
<h3>Debug Information</h3>
129+
<p>
130+
This example demonstrates vector search using the{' '}
131+
<code>vectorDataField</code> and <code>candidates</code> props.
132+
</p>
133+
<ul>
134+
<li>
135+
When you search in the search box, the value is used for the
136+
vector search
137+
</li>
138+
<li>
139+
The <code>vectorDataField</code> prop points to the vector field
140+
in your index
141+
</li>
142+
<li>
143+
The <code>candidates</code> prop controls how many nearest
144+
neighbors to return
145+
</li>
146+
</ul>
147+
</div>
148+
</div>
149+
</div>
150+
</div>
151+
</ReactiveBase>
152+
);
153+
};
154+
155+
const root = ReactDOM.createRoot(document.getElementById('root'));
156+
root.render(<App />);

0 commit comments

Comments
 (0)