diff --git a/server/.gitignore b/server/.gitignore
index 549e00a..c23b742 100644
--- a/server/.gitignore
+++ b/server/.gitignore
@@ -31,3 +31,5 @@ build/
### VS Code ###
.vscode/
+.mvn*
+mvnw*
diff --git a/server/pom.xml b/server/pom.xml
index 329f5fe..5a43217 100644
--- a/server/pom.xml
+++ b/server/pom.xml
@@ -11,7 +11,7 @@
com.github
awrb
0.0.1-SNAPSHOT
- awrb
+ solr
ISI 2021 Lab 4
1.8
diff --git a/server/src/main/java/com/github/awrb/AwrbApplication.java b/server/src/main/java/com/github/awrb/SolrApplication.java
similarity index 57%
rename from server/src/main/java/com/github/awrb/AwrbApplication.java
rename to server/src/main/java/com/github/awrb/SolrApplication.java
index fcbe5e6..3c7c804 100644
--- a/server/src/main/java/com/github/awrb/AwrbApplication.java
+++ b/server/src/main/java/com/github/awrb/SolrApplication.java
@@ -2,12 +2,11 @@ package com.github.awrb;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
-import org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration;
@SpringBootApplication
-public class AwrbApplication {
+public class SolrApplication {
public static void main(String[] args) {
- SpringApplication.run(AwrbApplication.class, args);
+ SpringApplication.run(SolrApplication.class, args);
}
}
diff --git a/server/src/main/java/com/github/awrb/solr/SolrFacade.java b/server/src/main/java/com/github/awrb/solr/SolrFacade.java
index 80b2ee6..b44411a 100644
--- a/server/src/main/java/com/github/awrb/solr/SolrFacade.java
+++ b/server/src/main/java/com/github/awrb/solr/SolrFacade.java
@@ -15,7 +15,7 @@ public class SolrFacade {
private SolrClient solrClient;
- public SolrFacade(@Value("${solr.address") String solrAddress) {
+ public SolrFacade(@Value("${solr.address}") String solrAddress) {
this.solrClient = new HttpSolrClient.Builder(solrAddress).build();
}
diff --git a/server/src/main/java/com/github/awrb/solr/services/SolrService.java b/server/src/main/java/com/github/awrb/solr/services/SolrService.java
index 33590fe..549c25f 100644
--- a/server/src/main/java/com/github/awrb/solr/services/SolrService.java
+++ b/server/src/main/java/com/github/awrb/solr/services/SolrService.java
@@ -1,11 +1,13 @@
package com.github.awrb.solr.services;
import com.github.awrb.solr.SolrFacade;
+import com.github.awrb.solr.services.data.SolrQueryParams;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.params.ModifiableSolrParams;
import org.apache.solr.common.params.SolrParams;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@@ -13,6 +15,7 @@ import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;
@RestController
+@CrossOrigin(origins = "http://localhost:3000")
public class SolrService {
private SolrFacade solrFacade;
@@ -23,14 +26,7 @@ public class SolrService {
}
@GetMapping("/search")
- public SolrDocumentList search(@RequestParam("q") String query) throws IOException, SolrServerException {
- SolrParams solrParams = solrParamsFromQuery(query);
- return solrFacade.query(solrParams).getResults();
- }
-
- private SolrParams solrParamsFromQuery(String query) {
- ModifiableSolrParams params = new ModifiableSolrParams();
- params.set("q", query);
- return params;
+ public SolrDocumentList search(SolrQueryParams params) throws IOException, SolrServerException {
+ return solrFacade.query(params.toSolrParams()).getResults();
}
}
diff --git a/server/src/main/java/com/github/awrb/solr/services/data/SolrQueryParams.java b/server/src/main/java/com/github/awrb/solr/services/data/SolrQueryParams.java
new file mode 100644
index 0000000..5cc47a1
--- /dev/null
+++ b/server/src/main/java/com/github/awrb/solr/services/data/SolrQueryParams.java
@@ -0,0 +1,86 @@
+package com.github.awrb.solr.services.data;
+
+import org.apache.solr.common.params.ModifiableSolrParams;
+import org.apache.solr.common.params.SolrParams;
+
+public class SolrQueryParams {
+
+ private static final String MATCH_ALL = "*";
+
+ private static final int DEFAULT_ROW_COUNT = 10;
+
+ private String query;
+
+ private String reviewText = MATCH_ALL;
+ private String reviewerName = MATCH_ALL;
+ private String summary = MATCH_ALL;
+ private String asin = MATCH_ALL;
+ private Sort sort = Sort.DESC;
+
+ private int rows = DEFAULT_ROW_COUNT;
+
+ public void setQuery(String query) {
+ this.query = query;
+ }
+
+ public void setReviewText(String reviewText) {
+ this.reviewText = reviewText;
+ }
+
+ public void setRows(int rows) {
+ this.rows = rows;
+ }
+
+ public void setReviewerName(String reviewerName) {
+ this.reviewerName = reviewerName;
+ }
+
+ public void setSummary(String summary) {
+ this.summary = summary;
+ }
+
+ public void setAsin(String asin) {
+ this.asin = asin;
+ }
+
+ public void setSort(Sort sort) {
+ this.sort = sort;
+ }
+
+ public SolrParams toSolrParams() {
+ ModifiableSolrParams params = new ModifiableSolrParams();
+ params.set("q", buildQ());
+ params.set("rows", rows);
+// params.set("sort", "overall " + sort.label);
+ System.out.println(params.toQueryString());
+ return params;
+ }
+
+ private String buildQ() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("(reviewText:")
+ .append(reviewText)
+ .append(" reviewerName:")
+ .append(reviewerName)
+ .append(" summary:")
+ .append(summary)
+ .append(" asin:")
+ .append(asin)
+ .append(")");
+ // The query string ends up looking like this: (reviewText:* reviewerName:* summary:*)
+ // OR between parameters
+ System.out.println(sb.toString());
+ return sb.toString();
+
+ }
+
+ public enum Sort {
+ ASC("asc"), DESC("desc");
+
+ private String label;
+
+ Sort(String label) {
+ this.label = label;
+ }
+ }
+}
diff --git a/server/src/main/resources/application.properties b/server/src/main/resources/application.properties
index a17e2a1..12565a4 100644
--- a/server/src/main/resources/application.properties
+++ b/server/src/main/resources/application.properties
@@ -1,2 +1,2 @@
server.servlet.context-path=/api
-solr.address=http://localhost:8983/solr/techproducts
+solr.address=http://localhost:8983/solr/reviews
diff --git a/server/src/test/java/com/github/awrb/AwrbApplicationTests.java b/server/src/test/java/com/github/awrb/SolrApplicationTests.java
similarity index 85%
rename from server/src/test/java/com/github/awrb/AwrbApplicationTests.java
rename to server/src/test/java/com/github/awrb/SolrApplicationTests.java
index 591caeb..797583d 100644
--- a/server/src/test/java/com/github/awrb/AwrbApplicationTests.java
+++ b/server/src/test/java/com/github/awrb/SolrApplicationTests.java
@@ -4,7 +4,7 @@ import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
-class AwrbApplicationTests {
+class SolrApplicationTests {
@Test
void contextLoads() {
diff --git a/ui/solr/.gitignore b/ui/solr/.gitignore
index 4d29575..9733a5e 100644
--- a/ui/solr/.gitignore
+++ b/ui/solr/.gitignore
@@ -21,3 +21,5 @@
npm-debug.log*
yarn-debug.log*
yarn-error.log*
+yarn.lock
+package-lock.json
diff --git a/ui/solr/package.json b/ui/solr/package.json
index af59670..68611fa 100644
--- a/ui/solr/package.json
+++ b/ui/solr/package.json
@@ -3,13 +3,16 @@
"version": "0.1.0",
"private": true,
"dependencies": {
- "@testing-library/jest-dom": "^5.11.4",
- "@testing-library/react": "^11.1.0",
- "@testing-library/user-event": "^12.1.10",
- "react": "^17.0.1",
- "react-dom": "^17.0.1",
+ "@material-ui/core": "4.11.3",
+ "@material-ui/icons": "4.11.2",
+ "@testing-library/jest-dom": "5.11.4",
+ "@testing-library/react": "11.1.0",
+ "@testing-library/user-event": "12.1.10",
+ "axios": "0.21.1",
+ "react": "17.0.1",
+ "react-dom": "17.0.1",
"react-scripts": "4.0.3",
- "web-vitals": "^1.0.1"
+ "web-vitals": "1.0.1"
},
"scripts": {
"start": "react-scripts start",
diff --git a/ui/solr/src/api/solr.js b/ui/solr/src/api/solr.js
new file mode 100644
index 0000000..15971e7
--- /dev/null
+++ b/ui/solr/src/api/solr.js
@@ -0,0 +1,11 @@
+import axios from "axios";
+
+const solr = axios.create({
+ baseURL: "http://localhost:8080/api/",
+ headers: {
+ "Content-Type": "application/json",
+ Accept: "application/json",
+ },
+});
+
+export default solr;
diff --git a/ui/solr/src/components/App.js b/ui/solr/src/components/App.js
new file mode 100644
index 0000000..96c0344
--- /dev/null
+++ b/ui/solr/src/components/App.js
@@ -0,0 +1,108 @@
+import React, { useState } from "react";
+import SearchBar from "./SearchBar";
+import SearchResult from "./SearchResult";
+import SortSelect from "./SortSelect";
+import solr from "../api/solr";
+import { List, CircularProgress, Grid } from "@material-ui/core";
+import { makeStyles } from "@material-ui/core/styles";
+import FilterSelect from "./FilterSelect";
+import Constants from "../constants";
+import PaginationSelect from "./PaginationSelect";
+
+const useStyles = makeStyles({
+ loader: { margin: 20 },
+ select: { marginLeft: "3vw" },
+});
+
+const App = () => {
+ const [results, setResults] = useState([]);
+ const [loading, setLoading] = useState(false);
+ const [filter, setFilter] = useState(Constants.REVIEW_TEXT);
+ const [term, setTerm] = useState("");
+ const [sort, setSort] = useState(Constants.DESC);
+ const [rows, setRows] = useState(10);
+
+ const classes = useStyles();
+
+ const getParams = () => {
+ const params = {
+ [Constants.REVIEWER_NAME]: "*",
+ [Constants.REVIEW_TEXT]: "*",
+ [Constants.SUMMARY]: "*",
+ [Constants.ASIN]: "*",
+ [Constants.ROWS]: rows,
+ [Constants.SORT]: sort,
+ };
+
+ if (filter === Constants.REVIEW_TEXT) {
+ params[Constants.REVIEW_TEXT] = term;
+ } else if (filter === Constants.REVIEWER_NAME) {
+ params[Constants.REVIEWER_NAME] = term;
+ } else if (filter === Constants.SUMMARY) {
+ params[Constants.SUMMARY] = term;
+ } else {
+ params[Constants.ASIN] = term;
+ }
+
+ return params;
+ };
+
+ const onSubmit = async () => {
+ setLoading(true);
+ const response = await solr.get("/search", { params: getParams() });
+ setResults(response.data);
+ setLoading(false);
+ };
+
+ const renderResults = () => {
+ return (
+
+ {results.map((result) => (
+
+ ))}
+
+ );
+ };
+
+ return (
+
+
+
+ setTerm(newTerm)}
+ onSubmit={onSubmit}
+ />
+
+
+ setFilter(filter)}
+ />
+
+
+ setSort(sort)}
+ value={sort}
+ className={classes.select}
+ />
+
+
+ setRows(rows)} />
+
+
+ {loading && }
+ {!loading && results.length > 0 && renderResults()}
+
+ );
+};
+
+export default App;
diff --git a/ui/solr/src/components/FilterSelect.js b/ui/solr/src/components/FilterSelect.js
new file mode 100644
index 0000000..5bc9e38
--- /dev/null
+++ b/ui/solr/src/components/FilterSelect.js
@@ -0,0 +1,28 @@
+import { InputLabel, MenuItem, Select } from "@material-ui/core";
+import React from "react";
+import Constants from "../constants";
+
+const FilterSelect = ({ onChange, value }) => {
+ const handleChange = (event) => {
+ onChange(event.target.value);
+ };
+
+ return (
+
+ Filter By
+
+
+ );
+};
+
+export default FilterSelect;
diff --git a/ui/solr/src/components/PaginationSelect.js b/ui/solr/src/components/PaginationSelect.js
new file mode 100644
index 0000000..5a932d2
--- /dev/null
+++ b/ui/solr/src/components/PaginationSelect.js
@@ -0,0 +1,27 @@
+import { InputLabel, MenuItem, Select } from "@material-ui/core";
+import React from "react";
+
+const PaginationSelect = ({ onChange, value }) => {
+ const handleChange = (event) => {
+ onChange(event.target.value);
+ };
+
+ return (
+
+
+
+
+ );
+};
+
+export default PaginationSelect;
diff --git a/ui/solr/src/components/SearchBar.js b/ui/solr/src/components/SearchBar.js
new file mode 100644
index 0000000..dd11c70
--- /dev/null
+++ b/ui/solr/src/components/SearchBar.js
@@ -0,0 +1,59 @@
+import React from "react";
+import { makeStyles } from "@material-ui/core/styles";
+import Paper from "@material-ui/core/Paper";
+import InputBase from "@material-ui/core/InputBase";
+import IconButton from "@material-ui/core/IconButton";
+import MenuIcon from "@material-ui/icons/Menu";
+import SearchIcon from "@material-ui/icons/Search";
+
+const useStyles = makeStyles((theme) => ({
+ root: {
+ padding: "2px 4px",
+ display: "flex",
+ alignItems: "center",
+ width: 400,
+ },
+ input: {
+ marginLeft: theme.spacing(1),
+ flex: 1,
+ },
+ iconButton: {
+ padding: 10,
+ },
+}));
+
+const SearchBar = ({ onSubmit, onChange, value }) => {
+ const classes = useStyles();
+
+ return (
+ {
+ e.preventDefault();
+ onSubmit();
+ }}
+ component="form"
+ className={classes.root}
+ >
+
+
+
+
+ onChange(e.target.value)}
+ className={classes.input}
+ placeholder="Search"
+ inputProps={{ "aria-label": "search" }}
+ />
+
+
+
+
+ );
+};
+
+export default SearchBar;
diff --git a/ui/solr/src/components/SearchResult.js b/ui/solr/src/components/SearchResult.js
new file mode 100644
index 0000000..655a240
--- /dev/null
+++ b/ui/solr/src/components/SearchResult.js
@@ -0,0 +1,33 @@
+import { Divider, ListItem, Paper, Typography } from "@material-ui/core";
+import React from "react";
+
+const SearchResult = ({
+ key,
+ summary,
+ reviewText,
+ author,
+ time,
+ asin,
+ rating,
+}) => {
+ return (
+
+
+ {summary}
+ {reviewText}
+
+
+
{author}
+
+
{time}
+
+
{`Rating ${rating}`}
+
+
{`ASIN ${asin}`}
+
+
+
+ );
+};
+
+export default SearchResult;
diff --git a/ui/solr/src/components/SortSelect.js b/ui/solr/src/components/SortSelect.js
new file mode 100644
index 0000000..7b57b55
--- /dev/null
+++ b/ui/solr/src/components/SortSelect.js
@@ -0,0 +1,26 @@
+import { InputLabel, MenuItem, Select } from "@material-ui/core";
+import React from "react";
+import Constants from "../constants";
+
+const SortSelect = ({ onChange, value }) => {
+ const handleChange = (event) => {
+ onChange(event.target.value);
+ };
+
+ return (
+
+ Sort by rating
+
+
+ );
+};
+
+export default SortSelect;
diff --git a/ui/solr/src/constants.js b/ui/solr/src/constants.js
new file mode 100644
index 0000000..8f09b0d
--- /dev/null
+++ b/ui/solr/src/constants.js
@@ -0,0 +1,21 @@
+export const REVIEWER_NAME = "reviewerName";
+export const REVIEW_TEXT = "reviewText";
+export const SUMMARY = "summary";
+export const ASIN = "asin";
+export const ROWS = "rows";
+export const ASC = "ASC";
+export const DESC = "DESC";
+export const SORT = "sort";
+
+export const CONSTANTS = {
+ REVIEWER_NAME,
+ REVIEW_TEXT,
+ SUMMARY,
+ ASIN,
+ ROWS,
+ DESC,
+ ASC,
+ SORT,
+};
+
+export default CONSTANTS;
diff --git a/ui/solr/src/index.js b/ui/solr/src/index.js
index ef2edf8..66bdb66 100644
--- a/ui/solr/src/index.js
+++ b/ui/solr/src/index.js
@@ -1,14 +1,13 @@
-import React from 'react';
-import ReactDOM from 'react-dom';
-import './index.css';
-import App from './App';
-import reportWebVitals from './reportWebVitals';
+import React from "react";
+import ReactDOM from "react-dom";
+import App from "./components/App";
+import reportWebVitals from "./reportWebVitals";
ReactDOM.render(
,
- document.getElementById('root')
+ document.getElementById("root")
);
// If you want to start measuring performance in your app, pass a function