Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

super-search #13

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
node_modules
node_modules
.idea
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,11 @@ d. **Bonus** Step *a* wasn't enough - some tickets have long content. Add a show
a. Agents are complaining that our search functionality isn't working properly. They gave the example that when searching for "wix store", the ticket titled "Search bar for my wix store" (id `6860d043-f551-58c8-84d6-f9e6a8cb0cb2`) is not returned. Checking the data, that ticket does exist.. Find the issue and fix it.
Friendly reminder to commit and push after completing this step.

b. We're showing only 20 tickets but agents can swear there are more. Solve this problem.
**Keep in mind the number of tickets is planned to grow exponentially very soon so make sure to think of a proper solution.**
b. We're doing great, the system now has more than 10M tickets but with success comes challenges and search became unbearable.
We even had a complaint from an agent that told us he waited for a response more than 5 minutes, that's just CRAZY!
Let's create a search mechanism on steroids.
1.Add q query param `?superSearch=` to the `/tickets` API call and implement an *efficient* search solution, that gets a word as an input and return an array of matching tickets.
2. Connect your client side search bar to that API call
Friendly reminder to commit and push after completing this step.


Expand Down
51 changes: 48 additions & 3 deletions server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@ import express from 'express';
import bodyParser = require('body-parser');
import { tempData } from './temp-data';
import { serverAPIPort, APIPath } from '@fed-exam/config';
import { Ticket } from '../client/src/api';

type TicketId = string
type InvertedIndexData = Record<TicketId, number[]>

type SearchEfficientTickets = Record<string, InvertedIndexData>
type TicketsMap = Map<TicketId, Ticket>


console.log('starting server', { serverAPIPort, APIPath });

Expand All @@ -18,16 +26,53 @@ app.use((_, res, next) => {
next();
});

const buildTicketsMap = (tickets: Ticket[]): TicketsMap => tickets.reduce<TicketsMap>((acc, ticket) => acc.set(ticket.id, ticket), new Map());
const buildInvertedIndexData = (tickets: Ticket[]): SearchEfficientTickets => {
const unrelevantWords = ['i', 'the', 'we', 'is', 'an'];
return tickets.reduce<SearchEfficientTickets>((acc, ticket) => {
ticket.content
.toLowerCase()
.split(' ')
.map(word => word.replace(/[^a-z]/g, ''))
.filter(word => {
return !unrelevantWords.includes(word);
})
.forEach((word, ind) => {
if (acc[word]) {
if (Array.isArray(acc[word][ticket.id])) {
acc[word][ticket.id].push(ind);
} else {
acc[word][ticket.id] = [ind];
}
} else {
acc[word] = { [ticket.id]: [ind] };
}
});
return acc;
}, {});
};
const invertedIndexData: SearchEfficientTickets = buildInvertedIndexData(tempData);
const ticketsMap = buildTicketsMap(tempData);

app.get(APIPath, (req, res) => {


// @ts-ignore
const page: number = req.query.page || 1;
const word = req.query.superSearch as string;
if (word) {
const tickets = Object.keys(invertedIndexData[word] ?? {});
const paginatedData = tickets.map(id => ticketsMap.get(id)).slice((page - 1) * PAGE_SIZE, page * PAGE_SIZE);
res.send(paginatedData);
} else {
const paginatedData = tempData.slice((page - 1) * PAGE_SIZE, page * PAGE_SIZE);
res.send(paginatedData);
}

const paginatedData = tempData.slice((page - 1) * PAGE_SIZE, page * PAGE_SIZE);

res.send(paginatedData);
});


app.listen(serverAPIPort);
console.log('server running', serverAPIPort)
console.log('server running', serverAPIPort);

3 changes: 2 additions & 1 deletion server/temp-data.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {Ticket} from '../client/src/api';

const data = require('./data.json');
const data = require('./../tester/big-data.json');

console.log(data[0]);
export const tempData = data as Ticket[];
240,002 changes: 240,002 additions & 0 deletions tester/big-data.json

Large diffs are not rendered by default.

65 changes: 0 additions & 65 deletions tester/e2e.test.ts

This file was deleted.

Loading