Merge Frank's branch 'dev.frontend/opensearch' into feat/opensearch
This commit is contained in:
commit
cc62df68da
|
@ -1,4 +1,6 @@
|
|||
APP_URL=//tethys.at
|
||||
VUE_API=//www.tethys.at
|
||||
SOLR_HOST=tethys.at
|
||||
SOLR_CORE=rdr_data
|
||||
# SOLR_HOST=tethys.at
|
||||
# SOLR_CORE=rdr_data
|
||||
OPEN_HOST=192.168.21.18
|
||||
OPEN_CORE=tethys-records
|
9
OpenSearch queries.txt
Normal file
9
OpenSearch queries.txt
Normal file
|
@ -0,0 +1,9 @@
|
|||
Get all documents in the index ("core" in solr)
|
||||
----------------------------------------------------
|
||||
curl -XGET "http://192.168.21.18/tethys-records/_search?pretty" -H 'Content-Type: application/json' -d'
|
||||
{
|
||||
"query": {
|
||||
"match_all": {}
|
||||
}
|
||||
}'
|
||||
|
60
SOLR queries.txt
Normal file
60
SOLR queries.txt
Normal file
|
@ -0,0 +1,60 @@
|
|||
Search by a specific value for one of the fields
|
||||
https://tethys.at/solr/rdr_data/select?&q=year:2024
|
||||
|
||||
Search within a specific range of values for one of the fields
|
||||
https://tethys.at/solr/rdr_data/select?&q=year:2023%20TO%202024 years 2023 to 2024
|
||||
|
||||
Search for a term (search done in predefined field?)
|
||||
https://tethys.at/solr/rdr_data/select?&q=linz
|
||||
|
||||
Predefined Tethys Search
|
||||
https://tethys.at/solr/rdr_data/select?&0=fl%3Did%2Clicence%2Cserver_date_published%2Cabstract_output%2Cidentifier%2Ctitle_output%2Ctitle_additional%2Cauthor%2Csubject%2Cdoctype&q=%2A&q.op=or&defType=edismax&qf=title%5E3%20author%5E2%20subject%5E1&indent=on&wt=json&rows=10&start=0&sort=server_date_published%20desc&facet=on&json.facet.language=%7B%20type%3A%20%22terms%22%2C%20field%3A%20%22language%22%20%7D&json.facet.subject=%7B%20type%3A%20%22terms%22%2C%20field%3A%20%22subject%22%2C%20limit%3A%20-1%20%7D&json.facet.year=%7B%20type%3A%20%22terms%22%2C%20field%3A%20%22year%22%20%7D&json.facet.author=%7B%20type%3A%20%22terms%22%2C%20field%3A%20%22author_facet%22%2C%20limit%3A%20-1%20%7D
|
||||
|
||||
Predefined Tethys search changing the last facet to "doctype"
|
||||
https://tethys.at/solr/rdr_data/select?&0=fl%3Did%2Clicence%2Cserver_date_published%2Cabstract_output%2Cidentifier%2Ctitle_output%2Ctitle_additional%2Cauthor%2Csubject%2Cdoctype&q=*&q.op=or&defType=edismax&qf=title^3%20author^2%20subject^1&indent=on&wt=json&rows=10&start=0&sort=server_date_published%20desc&facet=on&json.facet.language={%20type%3A%20%22terms%22%2C%20field%3A%20%22language%22%20}&json.facet.subject={%20type%3A%20%22terms%22%2C%20field%3A%20%22subject%22%2C%20limit%3A%20-1%20}&json.facet.author={%20type%3A%20%22terms%22%2C%20field%3A%20%22author_facet%22%2C%20limit%3A%20-1%20}&json.facet.doctype={%20type%3A%20%22terms%22%2C%20field%3A%20%22doctype%22%2C%20limit%3A%20-1%20}
|
||||
|
||||
Giving a value for only one facet => Author: Coric, Stjepan (16)
|
||||
https://tethys.at/solr/rdr_data/select?&0=fl%3Did%2Clicence%2Cserver_date_published%2Cabstract_output%2Cidentifier%2Ctitle_output%2Ctitle_additional%2Cauthor%2Csubject%2Cdoctype&q=%2A&q.op=or&defType=edismax&qf=title%5E3%20author%5E2%20subject%5E1&indent=on&wt=json&rows=10&fq=author%3A%28%22Coric%2C%20Stjepan%22%29&start=0&sort=server_date_published%20desc&facet=on&json.facet.language=%7B%20type%3A%20%22terms%22%2C%20field%3A%20%22language%22%20%7D&json.facet.subject=%7B%20type%3A%20%22terms%22%2C%20field%3A%20%22subject%22%2C%20limit%3A%20-1%20%7D&json.facet.year=%7B%20type%3A%20%22terms%22%2C%20field%3A%20%22year%22%20%7D&json.facet.author=%7B%20type%3A%20%22terms%22%2C%20field%3A%20%22author_facet%22%2C%20limit%3A%20-1%20%7D
|
||||
|
||||
|
||||
|
||||
ASCII
|
||||
+----+-----+----+-----+----+-----+----+-----+
|
||||
| Hx | Chr | Hx | Chr | Hx | Chr | Hx | Chr |
|
||||
+----+-----+----+-----+----+-----+----+-----+
|
||||
| 00 | NUL | 20 | SPC | 40 | @ | 60 | ` |
|
||||
| 01 | SOH | 21 | ! | 41 | A | 61 | a |
|
||||
| 02 | STX | 22 | " | 42 | B | 62 | b |
|
||||
| 03 | ETX | 23 | # | 43 | C | 63 | c |
|
||||
| 04 | EOT | 24 | $ | 44 | D | 64 | d |
|
||||
| 05 | ENQ | 25 | % | 45 | E | 65 | e |
|
||||
| 06 | ACK | 26 | & | 46 | F | 66 | f |
|
||||
| 07 | BEL | 27 | ' | 47 | G | 67 | g |
|
||||
| 08 | BS | 28 | ( | 48 | H | 68 | h |
|
||||
| 09 | TAB | 29 | ) | 49 | I | 69 | i |
|
||||
| 0A | LF | 2A | * | 4A | J | 6A | j |
|
||||
| 0B | VT | 2B | + | 4B | K | 6B | k |
|
||||
| 0C | FF | 2C | , | 4C | L | 6C | l |
|
||||
| 0D | CR | 2D | - | 4D | M | 6D | m |
|
||||
| 0E | SO | 2E | . | 4E | N | 6E | n |
|
||||
| 0F | SI | 2F | / | 4F | O | 6F | o |
|
||||
| 10 | DLE | 30 | 0 | 50 | P | 70 | p |
|
||||
| 11 | DC1 | 31 | 1 | 51 | Q | 71 | q |
|
||||
| 12 | DC2 | 32 | 2 | 52 | R | 72 | r |
|
||||
| 13 | DC3 | 33 | 3 | 53 | S | 73 | s |
|
||||
| 14 | DC4 | 34 | 4 | 54 | T | 74 | t |
|
||||
| 15 | NAK | 35 | 5 | 55 | U | 75 | u |
|
||||
| 16 | SYN | 36 | 6 | 56 | V | 76 | v |
|
||||
| 17 | ETB | 37 | 7 | 57 | W | 77 | w |
|
||||
| 18 | CAN | 38 | 8 | 58 | X | 78 | x |
|
||||
| 19 | EM | 39 | 9 | 59 | Y | 79 | y |
|
||||
| 1A | SUB | 3A | : | 5A | Z | 7A | z |
|
||||
| 1B | ESC | 3B | ; | 5B | [ | 7B | { |
|
||||
| 1C | FS | 3C | < | 5C | \ | 7C | | |
|
||||
| 1D | GS | 3D | = | 5D | ] | 7D | } |
|
||||
| 1E | RS | 3E | > | 5E | ^ | 7E | ~ |
|
||||
| 1F | US | 3F | ? | 5F | _ | 7F | DEL |
|
||||
+----+-----+----+-----+----+-----+----+-----+
|
||||
https://www.asciitable.com/ see Hx
|
||||
|
||||
If you write encodeURIComponent(",") in your JavaScript console, then you will also get %2C. And with decodeURIComponent("%2C") you will get back the ","
|
22
package-lock.json
generated
22
package-lock.json
generated
|
@ -14,6 +14,7 @@
|
|||
"axios": "^1.2.2",
|
||||
"class-transformer": "^0.5.1",
|
||||
"dayjs": "^1.10.7",
|
||||
"dompurify": "^3.1.5",
|
||||
"leaflet": "^1.7.1",
|
||||
"qs": "^6.10.1",
|
||||
"rxjs": "^7.5.5",
|
||||
|
@ -29,6 +30,7 @@
|
|||
"@babel/plugin-proposal-decorators": "^7.22.5",
|
||||
"@babel/preset-env": "^7.22.5",
|
||||
"@tailwindcss/forms": "^0.5.7",
|
||||
"@types/dompurify": "^3.0.5",
|
||||
"@types/leaflet": "^1.7.9",
|
||||
"@typescript-eslint/eslint-plugin": "^7.2.0",
|
||||
"@typescript-eslint/parser": "^7.2.0",
|
||||
|
@ -2497,6 +2499,15 @@
|
|||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/dompurify": {
|
||||
"version": "3.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/dompurify/-/dompurify-3.0.5.tgz",
|
||||
"integrity": "sha512-1Wg0g3BtQF7sSb27fJQAKck1HECM6zV1EB66j8JH9i3LCjYabJa0FSdiSgsD5K/RbrsR0SiraKacLB+T8ZVYAg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/trusted-types": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/eslint": {
|
||||
"version": "8.56.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.7.tgz",
|
||||
|
@ -2694,6 +2705,12 @@
|
|||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/trusted-types": {
|
||||
"version": "2.0.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz",
|
||||
"integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/webpack-env": {
|
||||
"version": "1.18.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/webpack-env/-/webpack-env-1.18.4.tgz",
|
||||
|
@ -5626,6 +5643,11 @@
|
|||
"url": "https://github.com/fb55/domhandler?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/dompurify": {
|
||||
"version": "3.1.5",
|
||||
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.1.5.tgz",
|
||||
"integrity": "sha512-lwG+n5h8QNpxtyrJW/gJWckL+1/DQiYMX8f7t8Z2AZTPw1esVrqjI63i7Zc2Gz0aKzLVMYC1V1PL/ky+aY/NgA=="
|
||||
},
|
||||
"node_modules/domutils": {
|
||||
"version": "2.8.0",
|
||||
"resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz",
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
"axios": "^1.2.2",
|
||||
"class-transformer": "^0.5.1",
|
||||
"dayjs": "^1.10.7",
|
||||
"dompurify": "^3.1.5",
|
||||
"leaflet": "^1.7.1",
|
||||
"qs": "^6.10.1",
|
||||
"rxjs": "^7.5.5",
|
||||
|
@ -32,6 +33,7 @@
|
|||
"@babel/plugin-proposal-decorators": "^7.22.5",
|
||||
"@babel/preset-env": "^7.22.5",
|
||||
"@tailwindcss/forms": "^0.5.7",
|
||||
"@types/dompurify": "^3.0.5",
|
||||
"@types/leaflet": "^1.7.9",
|
||||
"@typescript-eslint/eslint-plugin": "^7.2.0",
|
||||
"@typescript-eslint/parser": "^7.2.0",
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
</li>
|
||||
<li class="navbar-item">
|
||||
<!-- <a class="navbar-link is-arrowless" href="#">SEARCH</a> -->
|
||||
<router-link class="navbar-link is-arrowless" to="/search">SEARCH</router-link>
|
||||
<router-link class="navbar-link is-arrowless" to="/search">OPENSEARCH</router-link>
|
||||
</li>
|
||||
<li class="navbar-item">
|
||||
<!-- <a class="navbar-link is-arrowless" href="#">SERVICES</a> -->
|
||||
|
|
|
@ -1,46 +1,37 @@
|
|||
import initializeAxios from "./axiosSetup";
|
||||
import { axiosRequestConfiguration } from "./config";
|
||||
import { map } from "rxjs/operators";
|
||||
// import { Observable } from "@reactivex/rxjs/compat";
|
||||
import { defer, Observable } from "rxjs";
|
||||
import { AxiosResponse } from "axios";
|
||||
// https://ichi.pro/de/so-wickeln-sie-axios-mit-typescript-und-react-in-rxjs-ein-118892823169891
|
||||
// Import the necessary modules and functions
|
||||
import initializeAxios from "./axiosSetup"; // Function to initialize the Axios instance
|
||||
import { axiosRequestConfiguration } from "./config"; // Axios configuration settings
|
||||
import { map } from "rxjs/operators"; // Operator to transform the items emitted by an Observable
|
||||
import { defer, Observable } from "rxjs"; // RxJS utilities for creating and working with Observables
|
||||
import { AxiosResponse } from "axios"; // Axios response type
|
||||
|
||||
// Initialize the Axios instance with the provided configuration
|
||||
const axiosInstance = initializeAxios(axiosRequestConfiguration);
|
||||
|
||||
// Function to make a GET request using Axios wrapped in an Observable
|
||||
// eslint-disable-next-line
|
||||
const get = <T>(url: string, queryParams?: any): Observable<T> => {
|
||||
return defer(() => axiosInstance.get<T>(url, { params: queryParams })).pipe(map((result: AxiosResponse) => result.data));
|
||||
// Use defer to create an Observable that makes the Axios GET request when subscribed to
|
||||
return defer(() => axiosInstance.get<T>(url, { params: queryParams }))
|
||||
// Use map to transform the Axios response to extract the data property
|
||||
.pipe(map((result: AxiosResponse) => result.data));
|
||||
};
|
||||
|
||||
// const post = <T>(url: string, body: object, queryParams?: any): Observable<T | void> => {
|
||||
// return defer(() => axiosInstance.post<T>(url, body, { params: queryParams })).pipe(map((result: AxiosResponse) => result.data));
|
||||
// };
|
||||
// Function to make a POST request using Axios wrapped in an Observable
|
||||
const post = <T>(url: string, body: any, queryParams?: any): Observable<T> => {
|
||||
// Use defer to create an Observable that makes the Axios POST request when subscribed to
|
||||
// console.log(body);
|
||||
// console.log(queryParams);
|
||||
|
||||
// const put = <T>(
|
||||
// url: string,
|
||||
// body: object,
|
||||
// queryParams?: object
|
||||
// ): Observable<T | void> => {
|
||||
// return defer(() =>
|
||||
// axiosInstance.put<T>(url, body, { params: queryParams })
|
||||
// ).pipe(map((result) => result.data));
|
||||
// };
|
||||
return defer(() => axiosInstance.post<T>(url, body, {
|
||||
params: queryParams,
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
}))
|
||||
.pipe(map((result: AxiosResponse) => result.data)); // Use map to transform the Axios response to extract the data property
|
||||
};
|
||||
|
||||
// const patch = <T>(
|
||||
// url: string,
|
||||
// body: object,
|
||||
// queryParams?: object
|
||||
// ): Observable<T | void> => {
|
||||
// return defer(() =>
|
||||
// axiosInstance.patch<T>(url, body, { params: queryParams })
|
||||
// ).pipe(map((result) => result.data));
|
||||
// };
|
||||
|
||||
// const deleteR = <T>(url: string, id: number): Observable<T | void> => {
|
||||
// return defer(() => axiosInstance.delete(`${url}/${id}`)).pipe(
|
||||
// map((result) => result.data)
|
||||
// );
|
||||
// };
|
||||
|
||||
export default { get };
|
||||
// Export the get and post functions as part of the default export
|
||||
export default { get, post };
|
|
@ -1,18 +1,10 @@
|
|||
import axios, { AxiosRequestConfig, AxiosInstance } from "axios";
|
||||
|
||||
const initialization = (config: AxiosRequestConfig): AxiosInstance => {
|
||||
//axios.defaults.headers.common["X-Requested-With"] = "XMLHttpRequest";
|
||||
delete axios.defaults.headers.common["X-Requested-With"];
|
||||
// axios.defaults.withCredentials = true;
|
||||
// const token = document.head.querySelector('meta[name="csrf-token"]');
|
||||
// if (token) {
|
||||
// axios.defaults.headers.common["X-CSRF-TOKEN"] = token.innerHTML;
|
||||
// }
|
||||
const axiosInstance = axios.create(config);
|
||||
|
||||
/*
|
||||
Add default headers, interceptors etc..
|
||||
*/
|
||||
delete axios.defaults.headers.common["X-Requested-With"];
|
||||
|
||||
const axiosInstance = axios.create(config);
|
||||
|
||||
return axiosInstance;
|
||||
};
|
||||
|
|
|
@ -1,31 +1,16 @@
|
|||
import { AxiosRequestConfig } from "axios";
|
||||
import { stringify } from "qs";
|
||||
|
||||
// let headers: AxiosRequestConfig['headers'] =
|
||||
// headers['Content-Type'] = 'multipart/form-data';
|
||||
|
||||
/* This file configures Axios to send requests with the specified headers and parameters serialization format for URL-encoded form data */
|
||||
export const axiosRequestConfiguration: AxiosRequestConfig = {
|
||||
// responseType: "text",
|
||||
// headers: {
|
||||
// // "Content-Type": "text/plain",
|
||||
// "Content-Type": "application/x-www-form-urlencoded",
|
||||
// // "Content-Type": "application/x-www-form-urlencoded",
|
||||
// // credentials: "same-origin",
|
||||
// // "Access-Control-Allow-Credentials": "true",
|
||||
// // "Access-Control-Allow-Origin": "*",
|
||||
// },
|
||||
|
||||
headers: {
|
||||
//: AxiosHeaders | Partial<RawAxiosHeaders & MethodsHeaders & CommonHeaders> | undefined
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
},
|
||||
// headers: {
|
||||
// "Content-type": "application/json; charset=UTF-8",
|
||||
// },
|
||||
// paramsSerializer: {
|
||||
// indexes: null, // by default: false
|
||||
// },
|
||||
|
||||
paramsSerializer: {
|
||||
/* The serialize function takes an object of key-value pairs as input and uses the qs.stringify method to convert it into a URL-encoded string.
|
||||
The arrayFormat: "repeat" option specifies how arrays should be serialized in the URL parameters. */
|
||||
serialize: (params: Record<string, number>) => {
|
||||
return stringify(params, { arrayFormat: "repeat" });
|
||||
},
|
||||
|
|
|
@ -20,6 +20,7 @@ export default class FacetCategory extends Vue {
|
|||
filterName!: string;
|
||||
|
||||
get alias(): string {
|
||||
// console.log("filterName:", this.filterName);
|
||||
return this.filterName == "datatype" ? "doctype" : this.filterName;
|
||||
}
|
||||
|
||||
|
@ -53,6 +54,7 @@ export default class FacetCategory extends Vue {
|
|||
|
||||
@Emit("filter")
|
||||
activateItem(filterItem: FacetItem): FacetItem {
|
||||
// console.log("ActivateItem");
|
||||
filterItem.category = this.alias;
|
||||
filterItem.active = true;
|
||||
// this.$emit("filter", filterItem);
|
||||
|
|
|
@ -2,12 +2,17 @@
|
|||
// import debounce from 'lodash/debounce';
|
||||
// import { DatasetService } from "../../services/dataset.service";
|
||||
import DatasetService from "../../services/dataset.service";
|
||||
import { SolrSettings } from "@/models/solr";
|
||||
// import { ref } from "vue";
|
||||
// import { SolrSettings } from "@/models/solr"; // PENDING USE
|
||||
|
||||
import { OpenSettings } from "@/models/solr";
|
||||
import { Component, Vue, Prop, Emit } from "vue-facing-decorator";
|
||||
// import { Prop, Emit } from "vue-property-decorator";
|
||||
import { Dataset, Suggestion, SearchType } from "@/models/dataset";
|
||||
import { SOLR_HOST, SOLR_CORE } from "@/constants";
|
||||
// import { SOLR_HOST, SOLR_CORE } from "@/constants";
|
||||
|
||||
import { OPEN_HOST, OPEN_CORE } from "@/constants"; // PENDING USE
|
||||
import { HitHighlight } from "@/models/headers";
|
||||
|
||||
import DOMPurify from 'dompurify'; // To sanitize the HTML content to prevent XSS attacks!
|
||||
|
||||
@Component({
|
||||
name: "VsInput",
|
||||
|
@ -16,30 +21,40 @@ export default class VsInput extends Vue {
|
|||
// @Prop()
|
||||
// private title!: string;
|
||||
|
||||
// Define the placeholder text for the input field
|
||||
@Prop({ default: "Search" })
|
||||
readonly placeholder!: string;
|
||||
|
||||
private display = "";
|
||||
private display = ""; // Input display value
|
||||
|
||||
@Prop()
|
||||
private propDisplay = "";
|
||||
|
||||
private value!: Suggestion | string;
|
||||
private error = "";
|
||||
private results: Array<Dataset> = [];
|
||||
private loading = false;
|
||||
private selectedIndex = -1;
|
||||
// private selectedDisplay = "";
|
||||
private solr: SolrSettings = {
|
||||
core: SOLR_CORE, //"rdr_data", // SOLR.core;
|
||||
host: SOLR_HOST, //"tethys.at",
|
||||
private results: Array<Dataset> = []; // Array to store search results
|
||||
private highlights: Array<HitHighlight> = [];
|
||||
|
||||
private loading = false; // Loading state indicator
|
||||
private selectedIndex = -1; // Index of the currently selected suggestion
|
||||
|
||||
// private solr: SolrSettings = {
|
||||
// core: SOLR_CORE, //"rdr_data", // SOLR.core;
|
||||
// host: SOLR_HOST, //"tethys.at",
|
||||
// };
|
||||
|
||||
private openSearch: OpenSettings = {
|
||||
core: OPEN_CORE, //"rdr_data", // SOLR.core;
|
||||
host: OPEN_HOST, //"tethys.at",
|
||||
// core: "test_data", // SOLR.core;
|
||||
// host: "repository.geologie.ac.at",
|
||||
};
|
||||
// private rdrAPI!: DatasetService;
|
||||
itemRefs!: Array<Element>;
|
||||
emits = ["filter"];
|
||||
|
||||
// private rdrAPI!: DatasetService;
|
||||
itemRefs!: Array<Element>; // Array to store references to suggestion items
|
||||
emits = ["filter"]; // Emits filter event
|
||||
|
||||
// Set reference for each item
|
||||
setItemRef(el: Element): void {
|
||||
this.itemRefs.push(el);
|
||||
}
|
||||
|
@ -68,53 +83,113 @@ export default class VsInput extends Vue {
|
|||
return this.error !== null;
|
||||
}
|
||||
|
||||
// Computed property to generate suggestions based on search results
|
||||
get suggestions(): Suggestion[] {
|
||||
// const suggestion = {
|
||||
// titles: new Array<string>(),
|
||||
// authors: new Array<string>(),
|
||||
// subjects: new Array<string>(),
|
||||
// };
|
||||
|
||||
const suggestions = new Array<Suggestion>();
|
||||
|
||||
this.results.forEach((dataset) => {
|
||||
// const del = dataset.title_output?.toLowerCase();
|
||||
if (dataset.title_output.toLowerCase().includes(this.display.toLowerCase())) {
|
||||
const title = dataset.title_output;
|
||||
// if (!suggestion["titles"].find((value) => value === title)) {
|
||||
// suggestion.titles.push(title);
|
||||
// }
|
||||
const hasTitleSuggestion = suggestions.some((suggestion) => suggestion.value === title && suggestion.type == SearchType.Title);
|
||||
if (!hasTitleSuggestion) {
|
||||
const suggestion = new Suggestion(title, SearchType.Title);
|
||||
suggestions.push(suggestion);
|
||||
}
|
||||
}
|
||||
if (this.find(dataset.author, this.display.toLowerCase()) !== "") {
|
||||
const author = this.find(dataset.author, this.display.toLowerCase());
|
||||
// console.log("getSuggestions > Display:", this.display);
|
||||
// console.log("results:", this.results );
|
||||
// console.log("highlights:", this.highlights);
|
||||
|
||||
const hasAuthorSuggestion = suggestions.some((suggestion) => suggestion.value === author && suggestion.type == SearchType.Author);
|
||||
//The method checks if there are any highlighted titles in the highlight object. If found, it joins the highlighted fragments into a single string
|
||||
// Generate suggestions based on search results
|
||||
this.results.forEach((dataset, index) => {
|
||||
|
||||
const highlight = this.highlights[index];
|
||||
|
||||
// console.log("get suggestions:id", dataset.id);
|
||||
// console.log("get suggestions:title_output", dataset.title_output);
|
||||
// console.log("get suggestions:author", dataset.author);
|
||||
// console.log("get suggestions:subjects", dataset.subjects);
|
||||
|
||||
// Checks if a suggestion with the same title and type already exists in the suggestions array. If not, it creates a new Suggestion object and adds it to the suggestions array.
|
||||
if (highlight.title && highlight.title.length > 0) {
|
||||
/** This line checks if the highlight object has a title property and if that property is an array with at least one element.
|
||||
* The highlight object contains highlighted fragments of the search term in various fields (e.g., title, author, subjects) as returned by the OpenSearch API.
|
||||
* This check ensures that we only process results that have highlighted titles. */
|
||||
const highlightedTitle = highlight.title.join(" ");
|
||||
/**
|
||||
* The highlight.title property is an array of strings, where each string is a highlighted fragment of the title. join(" ") combines these fragments into a single string with spaces between them.
|
||||
* This step constructs a full highlighted title from the individual fragments.
|
||||
* OpenSearch can return multiple fragments of a field (like the title) in its response, especially when the field contains multiple terms that match the search query.
|
||||
* This can happen because OpenSearch's highlighting feature is designed to provide context around each match within the field, which can result in multiple highlighted fragments.
|
||||
*/
|
||||
const hasTitleSuggestion = suggestions.some((suggestion) => suggestion.highlight.toLowerCase() === highlightedTitle.toLowerCase() && suggestion.type == SearchType.Title);
|
||||
if (!hasTitleSuggestion) {
|
||||
const suggestion = new Suggestion(dataset.title_output, highlightedTitle, SearchType.Title);
|
||||
suggestions.push(suggestion);
|
||||
}
|
||||
}
|
||||
if (highlight.author && highlight.author.length > 0) {
|
||||
const highlightedAuthor = highlight.author.join(" ");
|
||||
const datasetAuthor = this.find(dataset.author, this.display.toLowerCase());
|
||||
const hasAuthorSuggestion = suggestions.some((suggestion) => suggestion.highlight.toLowerCase() === highlightedAuthor.toLowerCase() && suggestion.type == SearchType.Author);
|
||||
if (!hasAuthorSuggestion) {
|
||||
const suggestion = new Suggestion(author, SearchType.Author);
|
||||
const suggestion = new Suggestion(datasetAuthor, highlightedAuthor, SearchType.Author);
|
||||
suggestions.push(suggestion);
|
||||
}
|
||||
}
|
||||
if (this.find(dataset.subject, this.display.toLowerCase()) != "") {
|
||||
const subject = this.find(dataset.subject, this.display.toLowerCase());
|
||||
const hasSubjectSuggestion = suggestions.some((suggestion) => suggestion.value === subject && suggestion.type == SearchType.Subject);
|
||||
if (highlight.subjects && highlight.subjects.length > 0) {
|
||||
const highlightedSubject = highlight.subjects.join(" ");
|
||||
const datasetSubject = this.find(dataset.subjects, this.display.toLowerCase());
|
||||
const hasSubjectSuggestion = suggestions.some((suggestion) => suggestion.highlight.toLowerCase() === highlightedSubject.toLowerCase() && suggestion.type == SearchType.Subject);
|
||||
if (!hasSubjectSuggestion) {
|
||||
const suggestion = new Suggestion(subject, SearchType.Subject);
|
||||
const suggestion = new Suggestion(datasetSubject, highlightedSubject, SearchType.Subject);
|
||||
suggestions.push(suggestion);
|
||||
}
|
||||
}
|
||||
|
||||
// ORIGINAL SOLR ===================================================================================================
|
||||
// if (dataset.title_output.toLowerCase().includes(this.display.toLowerCase())) {
|
||||
// const title = dataset.title_output;
|
||||
// // Check if there is already a suggestion with this title and type
|
||||
// const hasTitleSuggestion = suggestions.some((suggestion) => suggestion.value === title && suggestion.type == SearchType.Title);
|
||||
// if (!hasTitleSuggestion) {
|
||||
// // If there is no such suggestion, create a new one and add it to the suggestions array
|
||||
// const suggestion = new Suggestion(title, SearchType.Title);
|
||||
// suggestions.push(suggestion);
|
||||
// }
|
||||
// }
|
||||
// if (this.find(dataset.author, this.display.toLowerCase()) !== "") {
|
||||
// const author = this.find(dataset.author, this.display.toLowerCase());
|
||||
// // Check if there is already a suggestion with this author and type
|
||||
// const hasAuthorSuggestion = suggestions.some((suggestion) => suggestion.value === author && suggestion.type == SearchType.Author);
|
||||
// if (!hasAuthorSuggestion) {
|
||||
// const suggestion = new Suggestion(author, SearchType.Author);
|
||||
// suggestions.push(suggestion);
|
||||
// }
|
||||
// }
|
||||
// if (this.find(dataset.subjects, this.display.toLowerCase()) != "") {
|
||||
// const subject = this.find(dataset.subjects, this.display.toLowerCase());
|
||||
// const hasSubjectSuggestion = suggestions.some((suggestion) => suggestion.value === subject && suggestion.type == SearchType.Subject);
|
||||
// if (!hasSubjectSuggestion) {
|
||||
// const suggestion = new Suggestion(subject, SearchType.Subject);
|
||||
// suggestions.push(suggestion);
|
||||
// }
|
||||
// }
|
||||
|
||||
});
|
||||
|
||||
return suggestions;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method combines the suggestion value and type into a single HTML string. It also sanitizes the HTML content using DOMPurify to prevent XSS attacks.
|
||||
* The vue file uses the v-html directive to bind the combined HTML string to the label element. This ensures that the HTML content (e.g., <em>Wien</em>) is rendered correctly in the browser.
|
||||
*/
|
||||
formatSuggestion(result: Suggestion): string {
|
||||
const sanitizedValue = DOMPurify.sanitize(result.highlight);
|
||||
// Replacing the predefined format for highlights given by OpenSearch from <em> emphasys to <b> bold
|
||||
const replacedValue = sanitizedValue.replace(/<em>/g, '<b>').replace(/<\/em>/g, '</b>');
|
||||
return `${replacedValue} <em>| ${result.type}</em>`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all values, results and errors
|
||||
**/
|
||||
clear(): void {
|
||||
console.log("clear");
|
||||
this.display = "";
|
||||
// this.value = null;
|
||||
this.results = [];
|
||||
|
@ -122,15 +197,20 @@ export default class VsInput extends Vue {
|
|||
// this.$emit("clear");
|
||||
}
|
||||
|
||||
/* When the search button is clicked or the search input is changed, it updates the value property of the component with the current value of display,
|
||||
and emits a search-change event with the current value of display as the argument. */
|
||||
@Emit("search-change")
|
||||
search(): string {
|
||||
console.log("search");
|
||||
this.results = [];
|
||||
// this.$emit("search", this.display)
|
||||
this.value = this.display; //(obj["title_output"]) ? obj["title_output"] : obj.id
|
||||
return this.display;
|
||||
}
|
||||
|
||||
// Handler for search input change
|
||||
searchChanged(): void {
|
||||
// console.log("Search changed!");
|
||||
this.selectedIndex = -1;
|
||||
// Let's warn the parent that a change was made
|
||||
// this.$emit("input", this.display);
|
||||
|
@ -142,7 +222,9 @@ export default class VsInput extends Vue {
|
|||
}
|
||||
}
|
||||
|
||||
// Perform the search request
|
||||
private resourceSearch() {
|
||||
// console.log("resourceSearch");
|
||||
if (!this.display) {
|
||||
this.results = [];
|
||||
return;
|
||||
|
@ -152,23 +234,29 @@ export default class VsInput extends Vue {
|
|||
this.request();
|
||||
}
|
||||
|
||||
// Make the API request to search for datasets
|
||||
private request(): void {
|
||||
DatasetService.searchTerm(this.display, this.solr.core, this.solr.host).subscribe({
|
||||
next: (res: Dataset[]) => this.dataHandler(res),
|
||||
console.log("request()");
|
||||
// DatasetService.searchTerm(this.display, this.solr.core, this.solr.host).subscribe({
|
||||
DatasetService.searchTerm(this.display, this.openSearch.core, this.openSearch.host).subscribe({
|
||||
// next: (res: Dataset[]) => this.dataHandler(res),
|
||||
next: (res: { datasets: Dataset[], highlights: HitHighlight[] }) => this.dataHandler(res.datasets, res.highlights),
|
||||
error: (error: string) => this.errorHandler(error),
|
||||
complete: () => (this.loading = false),
|
||||
});
|
||||
}
|
||||
|
||||
private dataHandler(datasets: Dataset[]): void {
|
||||
// Handle the search results
|
||||
private dataHandler(datasets: Dataset[], highlights: HitHighlight[]): void {
|
||||
this.results = datasets;
|
||||
// this.$emit("search", this.display);
|
||||
// this.loading = false;
|
||||
this.highlights = highlights; // Store highlights
|
||||
// console.log(datasets);
|
||||
|
||||
}
|
||||
|
||||
// Handle errors from the search request
|
||||
private errorHandler(err: string): void {
|
||||
this.error = err;
|
||||
// this.loading = false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -180,7 +268,9 @@ export default class VsInput extends Vue {
|
|||
return key === this.selectedIndex;
|
||||
}
|
||||
|
||||
// Handle arrow down key press to navigate suggestions
|
||||
onArrowDown(ev: Event): void {
|
||||
console.log("onArrowDown");
|
||||
ev.preventDefault();
|
||||
if (this.selectedIndex === -1) {
|
||||
this.selectedIndex = 0;
|
||||
|
@ -190,6 +280,7 @@ export default class VsInput extends Vue {
|
|||
this.fixScrolling();
|
||||
}
|
||||
|
||||
// Scroll the selected suggestion into view
|
||||
private fixScrolling() {
|
||||
const currentElement = this.itemRefs[this.selectedIndex];
|
||||
currentElement.scrollIntoView({
|
||||
|
@ -199,7 +290,9 @@ export default class VsInput extends Vue {
|
|||
});
|
||||
}
|
||||
|
||||
// Handle arrow up key press to navigate suggestions
|
||||
onArrowUp(ev: Event): void {
|
||||
console.log("onArrowUp");
|
||||
ev.preventDefault();
|
||||
if (this.selectedIndex === -1) {
|
||||
this.selectedIndex = this.suggestions.length - 1;
|
||||
|
@ -209,7 +302,10 @@ export default class VsInput extends Vue {
|
|||
this.fixScrolling();
|
||||
}
|
||||
|
||||
// Handle enter key press to select a suggestion
|
||||
onEnter(): void {
|
||||
console.log("onEnter");
|
||||
|
||||
if (this.selectedIndex === -1) {
|
||||
// this.$emit("nothingSelected", this.display);
|
||||
this.display && this.search();
|
||||
|
@ -222,18 +318,18 @@ export default class VsInput extends Vue {
|
|||
|
||||
@Emit("search-change")
|
||||
private select(obj: Suggestion): Suggestion {
|
||||
// if (!obj) {
|
||||
// return;
|
||||
// }
|
||||
this.value = obj; //(obj["title_output"]) ? obj["title_output"] : obj.id
|
||||
this.display = obj.value; // this.formatDisplay(obj)
|
||||
// this.selectedDisplay = this.display;
|
||||
console.log("select:");
|
||||
this.value = obj;
|
||||
console.log(obj);
|
||||
|
||||
this.display = obj.value;
|
||||
|
||||
this.close();
|
||||
// this.$emit("update", this.value);
|
||||
|
||||
return this.value;
|
||||
}
|
||||
|
||||
// Find a search term in an array
|
||||
private find(myarray: Array<string>, searchterm: string): string {
|
||||
for (let i = 0, len = myarray.length; i < len; i += 1) {
|
||||
if (typeof myarray[i] === "string" && myarray[i].toLowerCase().indexOf(searchterm) !== -1) {
|
||||
|
@ -248,15 +344,11 @@ export default class VsInput extends Vue {
|
|||
* Close the results list. If nothing was selected clear the search
|
||||
*/
|
||||
close(): void {
|
||||
console.log("close");
|
||||
if (!this.value) {
|
||||
this.clear();
|
||||
}
|
||||
// if (this.selectedDisplay !== this.display && this.value) {
|
||||
// this.display = this.selectedDisplay;
|
||||
// }
|
||||
this.results = [];
|
||||
this.error = "";
|
||||
//this.removeEventListener()
|
||||
// this.$emit("close");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,15 @@
|
|||
<template>
|
||||
<!-- Parent container with multiple rows -->
|
||||
<div class="is-multiline">
|
||||
<!-- <div class="content column is-half is-offset-one-quarter" style="margin-top: 30px; padding-bottom: 0; margin-bottom: 0px"> -->
|
||||
<!-- Search input wrapper -->
|
||||
<div class="column is-two-thirds-tablet is-half-desktop is-one-third-widescreen mx-auto">
|
||||
|
||||
<!-- Search box -->
|
||||
<div class="search-box mx-auto">
|
||||
<!-- Search field -->
|
||||
<div class="field has-addons main-search-from-bg">
|
||||
<div class="control is-expanded">
|
||||
<!-- Input field for search query -->
|
||||
<input
|
||||
id="search_query"
|
||||
v-model="display"
|
||||
|
@ -20,24 +25,26 @@
|
|||
@keydown.tab="close"
|
||||
@focus="focus"
|
||||
/>
|
||||
<!-- <p>Display is: {{ display }}</p> -->
|
||||
<!-- v-on:input="searchChanged" -->
|
||||
</div>
|
||||
|
||||
<!-- Search button -->
|
||||
<div class="control">
|
||||
<button class="button input is-medium search-button-icon" @click="search()">
|
||||
<!-- <img src="../../assets/fa/search.svg" style="height: 22px; width: 22px" /> -->
|
||||
<!-- Search icon -->
|
||||
<i class="fas fa-search text-white"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="column is-half is-offset-one-quarter"> -->
|
||||
|
||||
<!-- Suggestions list -->
|
||||
<div class="column is-two-thirds-tablet is-half-desktop is-one-third-widescreen mx-auto">
|
||||
<ul v-show="showResults" class="autocomplete-results pure-u-23-24">
|
||||
<!-- Loading indicator -->
|
||||
<li v-if="isLoading" class="loading">Loading results...</li>
|
||||
|
||||
<!-- Iterating over suggestions -->
|
||||
<li
|
||||
v-for="(result, i) in suggestions"
|
||||
v-else
|
||||
|
@ -47,8 +54,10 @@
|
|||
v-bind:class="{ 'is-active': isSelected(i) }"
|
||||
@click.prevent="select(result)"
|
||||
>
|
||||
<!-- Displaying suggestion result -->
|
||||
<div class="small-label">
|
||||
<label>{{ result.value }} ({{ result.type }})</label>
|
||||
<!-- <label>{{ result.value }} ({{ result.type }})</label> -->
|
||||
<label v-html="formatSuggestion(result)"></label>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
@ -140,7 +149,7 @@ input {
|
|||
.autocomplete-result-item {
|
||||
list-style: none;
|
||||
text-align: left;
|
||||
/* padding: 7px 10px; */
|
||||
padding: 0px 0px 0px 5px; // top,right,bottom,left
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
|
|
|
@ -23,13 +23,15 @@ export default class VsResult extends Vue {
|
|||
.join(".");
|
||||
}
|
||||
|
||||
private convert(unixtimestamp: number): string {
|
||||
// private convert(unixtimestamp: number): string { // SOLR
|
||||
private convert(unixtimestamp: string): string { // OpenSearch
|
||||
// Unixtimestamp
|
||||
// var unixtimestamp = document.getElementById('timestamp').value;
|
||||
// Months array
|
||||
const months_arr = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
||||
// Convert timestamp to milliseconds
|
||||
const date = new Date(unixtimestamp * 1000);
|
||||
// const date = new Date(unixtimestamp * 1000); // SOLR
|
||||
const date = new Date(Number(unixtimestamp) * 1000); // OpenSearch
|
||||
// Year
|
||||
const year = date.getFullYear();
|
||||
// Month
|
||||
|
|
|
@ -3,49 +3,25 @@
|
|||
<div class="card result-list-container">
|
||||
<div class="card-content record-elem">
|
||||
<p v-if="document.identifier && document.identifier.length > 0">
|
||||
<!-- <span>Author: {{ document.identifier.join(', ') }}</span> -->
|
||||
<!-- <span v-for="(author,index) in document.author" :key="index">{{ author }}; </span> -->
|
||||
<!-- <span>'https://doi.org/' + {{ document.identifier[0] }}</span> -->
|
||||
<a target="_blank" v-bind:href="'https://doi.org/' + document.identifier[0]">
|
||||
{{ "https://doi.org/" + document.identifier[0] + " ➤" }} </a
|
||||
>
|
||||
<span v-if="document.author && document.author.length > 0" class="disabled">{{ document.author[0] }}</span>
|
||||
</p>
|
||||
|
||||
<!-- <span class="label label-info" data-container="div" data-title="Publication date">
|
||||
{{ convert(document.server_date_published) }}
|
||||
</span>
|
||||
<span class="label label-default ng-binding">{{ document.doctype }}</span>
|
||||
<span v-if="openAccessLicences.includes(document.licence)" class="label label-success titlecase">Open Access</span> -->
|
||||
|
||||
<h4>
|
||||
<!-- <a
|
||||
v-if="document.identifier && document.identifier.length > 0"
|
||||
target="_self"
|
||||
v-bind:href="'https://doi.' + getDomainWithoutSubdomain() + '/' + document.identifier[0]"
|
||||
class="ng-binding"
|
||||
>
|
||||
{{ document.title_output }}
|
||||
</a> -->
|
||||
<!-- <a target="_self" v-bind:href="'dataset/' + document.id" class="ng-binding">
|
||||
{{ document.title_output }}
|
||||
</a> -->
|
||||
<router-link class="ng-binding" v-bind:to="{ name: 'dataset', params: { datasetId: document.id } }">{{
|
||||
document.title_output
|
||||
}}</router-link>
|
||||
</h4>
|
||||
|
||||
<!-- <p v-if="document.author && document.author.length > 0">
|
||||
<span>Author: {{ document.author.join(', ') }}</span>
|
||||
<span v-for="(author, index) in document.author" :key="index">{{ author }}; </span>
|
||||
</p> -->
|
||||
|
||||
<p class="clamped clamped-2">
|
||||
<span class="disabled" data-container="div" data-title="Publication date">
|
||||
{{ convert(document.server_date_published) + ": " }}
|
||||
</span>
|
||||
<span class="text">
|
||||
{{ document.abstract_output }}
|
||||
<!-- {{ document.abstract_output }} -->
|
||||
{{ document.abstract[0] }}
|
||||
<span class="ellipsis">...</span>
|
||||
<span class="fill"></span>
|
||||
</span>
|
||||
|
@ -53,11 +29,9 @@
|
|||
|
||||
<p>
|
||||
<span class="label"><i class="fas fa-file"></i> {{ document.doctype }}</span>
|
||||
<!-- <span>Licence: {{ document.licence }}</span> -->
|
||||
<span v-if="openAccessLicences.includes(document.licence)" class="label titlecase"><i class="fas fa-lock-open"></i> Open Access</span>
|
||||
</p>
|
||||
|
||||
<!-- <span class="label label-keyword titlecase" v-for="(item, index) in document.subject" :key="index"> #{{ item }} </span> -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -2,19 +2,31 @@
|
|||
// declare const EDGE_URL: string;
|
||||
declare const APP_URL: string;
|
||||
declare const VUE_API: string;
|
||||
declare const SOLR_HOST: string;
|
||||
declare const SOLR_CORE: string;
|
||||
// declare const SOLR_HOST: string;
|
||||
// declare const SOLR_CORE: string;
|
||||
|
||||
// OPENSEARCH
|
||||
declare const OPEN_HOST: string;
|
||||
declare const OPEN_CORE: string;
|
||||
|
||||
// const _EDGE_URL = EDGE_URL;
|
||||
// const _POINT_URL = POINT_URL;
|
||||
const _APP_URL = APP_URL;
|
||||
const _VUE_API = VUE_API;
|
||||
const _SOLR_HOST = SOLR_HOST;
|
||||
const _SOLR_CORE = SOLR_CORE;
|
||||
// const _SOLR_HOST = SOLR_HOST;
|
||||
// const _SOLR_CORE = SOLR_CORE;
|
||||
|
||||
// OPENSEARCH
|
||||
const _OPEN_HOST = OPEN_HOST;
|
||||
const _OPEN_CORE = OPEN_CORE;
|
||||
|
||||
// export { _EDGE_URL as EDGE_URL };
|
||||
// export { _POINT_URL as POINT_URL };
|
||||
export { _APP_URL as APP_URL };
|
||||
export { _VUE_API as VUE_API };
|
||||
export { _SOLR_HOST as SOLR_HOST };
|
||||
export { _SOLR_CORE as SOLR_CORE };
|
||||
// export { _SOLR_HOST as SOLR_HOST };
|
||||
// export { _SOLR_CORE as SOLR_CORE };
|
||||
|
||||
// OPENSEARCH
|
||||
export { _OPEN_HOST as OPEN_HOST };
|
||||
export { _OPEN_CORE as OPEN_CORE };
|
||||
|
|
|
@ -1,72 +1,91 @@
|
|||
// import moment from "moment";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
// // SOLR Dataset original
|
||||
// export interface Dataset {
|
||||
// abstract_additional: Array<string>;// OpenSearch: abstract: Array<string>
|
||||
// abstract_output: string;// -----
|
||||
// author: Array<string>;// EQUAL
|
||||
// author_sort: Array<string>;// -----
|
||||
// belongs_to_bibliography: boolean;// EQUAL
|
||||
// creating_corporation: string;// EQUAL
|
||||
// doctype: string;// EQUAL
|
||||
// geo_location: string;// EQUAL
|
||||
// id: number;// EQUAL
|
||||
// identifier: Identifier;// OpenSearch: identifier: Array<string>
|
||||
// language: string;// EQUAL
|
||||
// licence: string;// EQUAL
|
||||
// publisher_name: string;// EQUAL
|
||||
// server_date_published: Array<number>;// OpenSearch not array!
|
||||
// subject: Array<string>;// OpenSearch: subjectS
|
||||
// title_output: string;// EQUAL
|
||||
// year: number;// EQUAL
|
||||
// year_inverted: number;// EQUAL
|
||||
// }
|
||||
|
||||
// OpenSearch Dataset
|
||||
export interface Dataset {
|
||||
abstract_additional: Array<string>;
|
||||
abstract_output: string;
|
||||
author: Array<string>;
|
||||
author_sort: Array<string>;
|
||||
belongs_to_bibliography: boolean;
|
||||
creating_corporation: string;
|
||||
doctype: string;
|
||||
geo_location: string;
|
||||
id: number;
|
||||
identifier: Identifier;
|
||||
language: string;
|
||||
licence: string;
|
||||
publisher_name: string;
|
||||
server_date_published: Array<number>;
|
||||
subject: Array<string>;
|
||||
title_output: string;
|
||||
year: number;
|
||||
year_inverted: number;
|
||||
abstract: Array<string>;// OpenSearch: abstract: Array<string>
|
||||
// abstract_output: string;// ----- NOT in OpenSearch
|
||||
author: Array<string>;// EQUAL
|
||||
// author_sort: Array<string>;// ----- NOT in OpenSearch
|
||||
belongs_to_bibliography: boolean;// EQUAL
|
||||
creating_corporation: string;// EQUAL
|
||||
doctype: string;// EQUAL
|
||||
geo_location: string;// EQUAL
|
||||
id: number;// EQUAL
|
||||
// identifier: Identifier;// OpenSearch: identifier: Array<string>
|
||||
identifier: Array<string>// DIFF DATATYPE
|
||||
language: string;// EQUAL
|
||||
licence: string;// EQUAL
|
||||
publisher_name: string;// EQUAL
|
||||
// server_date_published: Array<number>;// OpenSearch string!
|
||||
server_date_published: string;// DIFF DATATYPE
|
||||
// subject: Array<string>;// OpenSearch: subjectS
|
||||
subjects: Array<string>;// DIFF DATATYPE
|
||||
title_output: string;// EQUAL
|
||||
year: number;// EQUAL
|
||||
year_inverted: number;// EQUAL
|
||||
|
||||
title: string // Unique in OpenSearch
|
||||
title_additional: Array<string> // Unique in OpenSearch
|
||||
bbox_xmin: string // Unique in OpenSearch
|
||||
bbox_xmax: string // Unique in OpenSearch
|
||||
bbox_ymin: string // Unique in OpenSearch
|
||||
bbox_ymax: string // Unique in OpenSearch
|
||||
reference: Array<string> // Unique in OpenSearch
|
||||
abstract_additional: Array<string>;// Unique in OpenSearch
|
||||
}
|
||||
|
||||
|
||||
export class Suggestion {
|
||||
constructor(
|
||||
public value: string,
|
||||
public type: SearchType,
|
||||
public value: string, // Store the text value returned by OpenSearch
|
||||
// Store the highlight: i.e. the text value with the emphasised term that generated that results by OpenSearch.
|
||||
// In this way we can highlight the real term existing in the publication independently of how different was the inserted term used for the FUZZY search. e.g. "Vien" fuzzy matched with "Wien"
|
||||
public highlight: string,
|
||||
public type: SearchType, // Type of search element
|
||||
) {}
|
||||
// value!: string;
|
||||
// type!: SearchType;
|
||||
}
|
||||
|
||||
// export class Suggestion {
|
||||
// constructor(
|
||||
// public value: string,
|
||||
// public type: SearchType,
|
||||
// ) {}
|
||||
// // value!: string;
|
||||
// // type!: SearchType;
|
||||
// }
|
||||
|
||||
export enum SearchType {
|
||||
Title = "title",
|
||||
Author = "author",
|
||||
Subject = "subject",
|
||||
Subject = "subjects" // ** !! The field has this name in OpenSearch!!
|
||||
}
|
||||
|
||||
export class DbDataset {
|
||||
// public id!: number;
|
||||
// public url!: string;
|
||||
// public contributing_corporation!: string;
|
||||
// public creating_corporation!: string;
|
||||
// public publisher_name!: string;
|
||||
// public embargo_date!: string;
|
||||
// public publish_id!: number;
|
||||
// public project_id!: number;
|
||||
// public type!: string;
|
||||
// public language!: string;
|
||||
// public server_state!: string;
|
||||
// public belongs_to_bibliography!: boolean;
|
||||
// public created_at!: string;
|
||||
// public server_date_modified!: string;
|
||||
// public server_date_published!: string;
|
||||
// public account_id!: number;
|
||||
// public editor_id!: number;
|
||||
// public reviewer_id!: number;
|
||||
// public preferred_reviewer!: number;
|
||||
// public preferred_reviewer_email!: string;
|
||||
// public reject_editor_note!: string;
|
||||
// public reject_reviewer_note!: string;
|
||||
// public reviewer_note_visible!: string;
|
||||
// public titles!: Array<Title>;
|
||||
// public abstracts!: Array<Abstract>;
|
||||
// public authors!: Array<Author>;
|
||||
// public contributors!: Array<Author>;
|
||||
// public user!: Person;
|
||||
// public subjects!: Array<Subject>;
|
||||
|
||||
constructor(
|
||||
public id: string,
|
||||
|
|
|
@ -18,19 +18,6 @@ export interface ResponseHeaderParams {
|
|||
rows?: number;
|
||||
start?: number;
|
||||
wt?: string;
|
||||
|
||||
// 0:'fl=id,licence,server_date_published,abstract_output,identifier,title_output,title_additional,author,subject,doctype'
|
||||
|
||||
// df:'title'
|
||||
// facet:'on'
|
||||
// indent:'on'
|
||||
// json.facet.language:'{ type: "terms", field: "language" }'
|
||||
// json.facet.subject:'{ type: "terms", field: "subject" }'
|
||||
// q:'title:Geodaten - Blatt 49 Wels (1:50.000)'
|
||||
// q.op:'and'
|
||||
// rows:'10'
|
||||
// start:'0'
|
||||
// wt:'json'
|
||||
}
|
||||
|
||||
export interface ResponseContent {
|
||||
|
@ -39,36 +26,21 @@ export interface ResponseContent {
|
|||
docs: Array<Dataset>;
|
||||
}
|
||||
|
||||
// export interface FacetCount {
|
||||
// facet_fields: FacetCategory<any>;
|
||||
// }
|
||||
|
||||
// export class FacetCategory<T> {
|
||||
|
||||
// [key: string]: {
|
||||
// values: T[];
|
||||
// };
|
||||
// }
|
||||
|
||||
//Used
|
||||
export class FacetResults {
|
||||
// language!: Array<FacetItem>;
|
||||
// subject!: Array<FacetItem>;
|
||||
[key: string]: Array<FacetItem>;
|
||||
}
|
||||
|
||||
//#region solr response facets
|
||||
export class FacetFields {
|
||||
// count: number;
|
||||
language!: FacetInstance;
|
||||
subject!: FacetInstance;
|
||||
// [key: string]: FacetInstance;
|
||||
}
|
||||
|
||||
export interface FacetInstance {
|
||||
[key: string]: Array<FacetItem>;
|
||||
// buckets: Array<FacetItem>;
|
||||
}
|
||||
|
||||
//Used
|
||||
export class FacetItem {
|
||||
val: string;
|
||||
count: number;
|
||||
|
@ -83,3 +55,77 @@ export class FacetItem {
|
|||
}
|
||||
}
|
||||
//#endregion
|
||||
|
||||
// OPENSEARCH
|
||||
// ========================================================================
|
||||
export interface OpenSearchResponse {
|
||||
took: number;
|
||||
timed_out: boolean;
|
||||
_shards: Shards;
|
||||
hits: Hits; // Equivalent SOLR: response > docs
|
||||
aggregations?: Aggregations; // Equivalent SOLR: facets
|
||||
}
|
||||
|
||||
export interface Shards {
|
||||
total: number;
|
||||
successful: number;
|
||||
skipped: number;
|
||||
failed: number;
|
||||
}
|
||||
|
||||
export interface Hits {
|
||||
total: Total;
|
||||
max_score: number;
|
||||
hits: Array<Hit>;
|
||||
}
|
||||
|
||||
export interface Total {
|
||||
value: number; // Equivalent SOLR: response > numFound
|
||||
relation: string;
|
||||
}
|
||||
|
||||
export interface Hit {
|
||||
_index: string;
|
||||
_id: string;
|
||||
_score: number;
|
||||
_source: Dataset;
|
||||
highlight: HitHighlight; // !! This name is to avoid collision with Typescript "Highlight" class
|
||||
}
|
||||
|
||||
export interface HitHighlight {
|
||||
subjects?: Array<string>;
|
||||
title?: Array<string>;
|
||||
author?: Array<string>;
|
||||
}
|
||||
|
||||
export interface Aggregations { // Equivalent SOLR: FacetFields
|
||||
subjects: Subjects;
|
||||
language: Language;
|
||||
}
|
||||
|
||||
export interface Subjects {
|
||||
doc_count_error_upper_bound: number;
|
||||
sum_other_doc_count: number;
|
||||
buckets: Array<Bucket>;
|
||||
}
|
||||
|
||||
export interface Language {
|
||||
doc_count_error_upper_bound: number;
|
||||
sum_other_doc_count: number;
|
||||
buckets: Array<Bucket>;
|
||||
}
|
||||
|
||||
export interface Bucket {
|
||||
key: string;
|
||||
doc_count: number;
|
||||
}
|
||||
// // Needed?
|
||||
// export interface Aggregations {
|
||||
// [key: string]: Aggregation;
|
||||
// }
|
||||
|
||||
// export interface Aggregation {
|
||||
// buckets: Array<Bucket>;
|
||||
// }
|
||||
|
||||
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
export interface SolrSettings {
|
||||
// export interface SolrSettings {
|
||||
// core: string;
|
||||
// host: string;
|
||||
// }
|
||||
|
||||
export interface OpenSettings {
|
||||
core: string;
|
||||
host: string;
|
||||
}
|
||||
|
|
|
@ -1,361 +1,620 @@
|
|||
import api from "../api/api";
|
||||
// import { Observable, of } from "rxjs";
|
||||
import { Observable } from "rxjs";
|
||||
import { map } from "rxjs/operators";
|
||||
import { tap, map } from "rxjs/operators";
|
||||
import { Dataset, DbDataset, Suggestion } from "@/models/dataset";
|
||||
import { SolrResponse } from "@/models/headers";
|
||||
import { HitHighlight, OpenSearchResponse, SolrResponse } from "@/models/headers";
|
||||
import { ActiveFilterCategories } from "@/models/solr";
|
||||
import { VUE_API } from "@/constants";
|
||||
// import { deserialize, instanceToInstance } from "class-transformer";
|
||||
import { deserialize } from "class-transformer";
|
||||
// import { OAI_DATASETS } from "./mock-oai-datasets";
|
||||
// import { OaiDataset, OaiPerson } from "@/models/oai";
|
||||
// import xml2js from "xml2js";
|
||||
|
||||
class DatasetService {
|
||||
// for the autocomplete search
|
||||
public searchTerm(term: string, solrCore: string, solrHost: string): Observable<Dataset[]> {
|
||||
// solr endpoint
|
||||
// const host = 'http://voyagerdemo.com/';
|
||||
// const host = 'https://www.tethys.at/';''
|
||||
const host = "https://" + solrHost;
|
||||
const path = "/solr/" + solrCore + "/select?";
|
||||
// const base = "https://geomon.geologie.ac.at/52n-sos-webapp/api/features"; //host + path;
|
||||
/**
|
||||
* Fetch data from the OpenSearch endpoint with fuzzy search enabled.
|
||||
* This function allows for misspellings in the search term and boosts
|
||||
* the relevance of matches in the title, author, and subject fields.
|
||||
*
|
||||
* @param {string} searchTerm - The search term to query.
|
||||
*/
|
||||
|
||||
/* https://tethys.at/solr/rdr_data/select?&0=fl%3Did%2Clicence%2Cserver_date_published%2Cabstract_output%2Cidentifier%2Ctitle_output%2Ctitle_additional%2Cauthor%2Csubject%2Cdoctype&q=%2A
|
||||
&q.op=or&defType=edismax&qf=title%5E3%20author%5E2%20subject%5E1&indent=on&wt=json&rows=10&start=0&sort=server_date_published%20desc&facet=on&json.facet.language=%7B%20type%3A%20%22
|
||||
terms%22%2C%20field%3A%20%22language%22%20%7D&json.facet.subject=%7B%20type%3A%20%22terms%22%2C%20field%3A%20%22subject%22%2C%20limit%3A%20-1%20%7D&json.facet.year=%7B%20type%3A%20%22
|
||||
terms%22%2C%20field%3A%20%22year%22%20%7D&json.facet.author=%7B%20type%3A%20%22terms%22%2C%20field%3A%20%22author_facet%22%2C%20limit%3A%20-1%20%7D
|
||||
*/
|
||||
|
||||
// private openSearchUrl = "http://opensearch.geoinformation.dev/tethys-records/_search";
|
||||
// private openSearchUrl = "http://192.168.21.18/tethys-records/_search";
|
||||
|
||||
public searchTerm(term: string, openCore: string, openHost: string): Observable<{ datasets: Dataset[], highlights: HitHighlight[] }> {
|
||||
// OpenSearch endpoint
|
||||
const host = openHost; // When using local OpenSearch dev endpoint
|
||||
const path = "/" + openCore + "/_search";
|
||||
const base = host + path;
|
||||
|
||||
//const fields = 'id,server_date_published,abstract_output,title_output,title_additional,author,subject'; // fields we want returned
|
||||
const fields = [
|
||||
"id",
|
||||
"licence",
|
||||
"server_date_published",
|
||||
"abstract_output",
|
||||
"title_output",
|
||||
"title_additional",
|
||||
"author",
|
||||
"subject",
|
||||
"doctype",
|
||||
].toString();
|
||||
|
||||
//var dismaxFields = "title^3 abstract^2 subject^1";
|
||||
const qfFields = "title^3 author^2 subject^1";
|
||||
// let params = "fl=" + fields;
|
||||
// // if (term == "*%3A*") { // *:
|
||||
// // params += "&defType=edismax&wt=json&indent=on"; //edismax
|
||||
// // } else {
|
||||
// params += "&defType=edismax&qf=" + qfFields + "&wt=json&indent=on"; //dismax
|
||||
// // }
|
||||
|
||||
// const query = "&q=" + term + "*";
|
||||
// const apiU = base + params + query;
|
||||
|
||||
const q_params = {
|
||||
"0": "fl=" + fields,
|
||||
q: term + "*",
|
||||
defType: "edismax",
|
||||
qf: qfFields,
|
||||
indent: "on",
|
||||
wt: "json",
|
||||
/**
|
||||
* The match query used for title, author, and subjects fields is case-insensitive by default. The standard analyzer is typically used, which lowercases the terms.
|
||||
* The wildcard query is case-sensitive by default. To make it case-insensitive, it is needed to use a lowercase filter */
|
||||
const lowercaseTerm = term.toLowerCase(); // Lowercase the search term
|
||||
const body = {
|
||||
query: {
|
||||
bool: {
|
||||
should: [
|
||||
{ match: { title: { query: term, fuzziness: "AUTO", boost: 3 } } },
|
||||
{ match: { author: { query: term, fuzziness: "AUTO", boost: 2 } } },
|
||||
{ match: { subjects: { query: term, fuzziness: "AUTO", boost: 1 } } }, // In SOLR is "subject"!
|
||||
{ wildcard: { title: { value: `${lowercaseTerm}*`, boost: 3 } } },
|
||||
{ wildcard: { author: { value: `${lowercaseTerm}*`, boost: 2 } } },
|
||||
{ wildcard: { subjects: { value: `${lowercaseTerm}*`, boost: 1 } } } // In SOLR is "subject"!
|
||||
],
|
||||
minimum_should_match: 1
|
||||
}
|
||||
},
|
||||
size: 10,
|
||||
from: 0,
|
||||
// sort: [{ server_date_published: { order: "desc" } }],
|
||||
sort: [{ _score: { order: "desc" } }], // Sort by _score in descending order
|
||||
track_scores: true, // This ensures "_score" is included even when sorting by other criteria. Otherwise the relevance score is not calculated
|
||||
aggs: {
|
||||
subjects: { terms: { field: "subjects.keyword", size: 1000 } }, // In SOLR is "subject"!
|
||||
language: { terms: { field: "language" } }, // << ".keyword" HAS TO BE REMOVED. OTHERWISE BUCKETS ARE NOT OBTAINED FOR THIS
|
||||
author: { terms: { field: "author.keyword", size: 1000 } },
|
||||
year: { terms: { field: "year", size: 100 } } // << ".keyword" HAS TO BE REMOVED. OTHERWISE BUCKETS ARE NOT OBTAINED FOR THIS
|
||||
},
|
||||
// // CONTABO ================================================================================
|
||||
// aggs: {
|
||||
// subjects: { terms: { field: "subjects.keyword", size: 1000 } }, // In SOLR is "subject"!
|
||||
// language: { terms: { field: "language.keyword" } }, // << ".keyword" HAS TO BE REMOVED. OTHERWISE BUCKETS ARE NOT OBTAINED FOR THIS
|
||||
// author: { terms: { field: "author.keyword", size: 1000 } },
|
||||
// year: { terms: { field: "year.keyword", size: 100 } } // << ".keyword" HAS TO BE REMOVED. OTHERWISE BUCKETS ARE NOT OBTAINED FOR THIS
|
||||
// },
|
||||
// // ===========================================================================================
|
||||
highlight: {
|
||||
fields: {
|
||||
title: {},
|
||||
author: {},
|
||||
subjects: {}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const stations = api.get<SolrResponse>(base, q_params).pipe(map((res: SolrResponse) => res.response.docs));
|
||||
// Make API call to OpenSearch and return the result
|
||||
/**
|
||||
* When a POST request is made to the OpenSearch server using the api.post<OpenSearchResponse> method, the response received from OpenSearch is an object that includes various details about the search results.
|
||||
* One of the key properties of this response object is _source, which is an array of documents (datasets) that match the search criteria.
|
||||
* It is used the pipe method to chain RxJS operators to the Observable returned by api.get. The map operator is used to transform the emitted items of the Observable.
|
||||
*/
|
||||
return api.post<OpenSearchResponse>(base, body).pipe(
|
||||
// tap(response => console.log("OpenSearchResponse:", response)), // Log the complete response
|
||||
// tap(response => console.log("Aggre:", response.aggregations?.subjects.buckets[0])), // log the first subject of the array of subjects returned
|
||||
// tap(response => console.log("Hits:", response.hits)), // log the first subject of the array of subjects returned
|
||||
|
||||
return stations;
|
||||
// map(response => response.hits.hits.map(hit => hit._source))
|
||||
|
||||
map(response => ({
|
||||
datasets: response.hits.hits.map(hit => hit._source),
|
||||
highlights: response.hits.hits.map(hit => hit.highlight)
|
||||
}))
|
||||
);
|
||||
}
|
||||
|
||||
public facetedSearch(
|
||||
// // For the autocomplete search. Method to perform a search based on a term
|
||||
// public searchTerm_SOLR(term: string, solrCore: string, solrHost: string): Observable<Dataset[]> {
|
||||
// // SOLR endpoint
|
||||
// const host = "https://" + solrHost;
|
||||
// const path = "/solr/" + solrCore + "/select?";
|
||||
// const base = host + path;
|
||||
|
||||
// //const fields = 'id,server_date_published,abstract_output,title_output,title_additional,author,subject'; // fields we want returned
|
||||
// const fields = [
|
||||
// "id",
|
||||
// "licence",
|
||||
// "server_date_published",
|
||||
// "abstract_output",
|
||||
// "title_output",
|
||||
// "title_additional",
|
||||
// "author",
|
||||
// "subject",
|
||||
// "doctype",
|
||||
// ].toString();
|
||||
|
||||
|
||||
// const qfFields = "title^3 author^2 subject^1";
|
||||
|
||||
// const q_params = {
|
||||
// "0": "fl=" + fields,
|
||||
// q: term + "*",
|
||||
// defType: "edismax",
|
||||
// qf: qfFields,
|
||||
// indent: "on",
|
||||
// wt: "json",
|
||||
// };
|
||||
|
||||
// // Make API call to Solr and return the result
|
||||
// /**
|
||||
// * When a GET request is made to the Solr server using the api.get<SolrResponse> method, the response received from Solr is an object that includes various details about the search results.
|
||||
// * One of the key properties of this response object is docs, which is an array of documents (datasets) that match the search criteria.
|
||||
// * It is used the pipe method to chain RxJS operators to the Observable returned by api.get. The map operator is used to transform the emitted items of the Observable.
|
||||
// */
|
||||
// const stations = api.get<SolrResponse>(base, q_params).pipe(map((res: SolrResponse) => res.response.docs));
|
||||
|
||||
// return stations;
|
||||
// }
|
||||
|
||||
// public facetedSearchOPEN(
|
||||
// suggestion: Suggestion | string,
|
||||
// activeFilterCategories: ActiveFilterCategories,
|
||||
// openCore: string,
|
||||
// openHost: string,
|
||||
// start?: string, // Starting page
|
||||
// ): Observable<OpenSearchResponse> {
|
||||
// // OpenSearch endpoint
|
||||
// const host = openHost;
|
||||
// const path = "/" + openCore + "/_search";
|
||||
// const base = host + path;
|
||||
|
||||
// // Constructing Filters Based on Active Filter Categories
|
||||
// const filters = Object.entries(activeFilterCategories).map(([category, values]) => {
|
||||
// if (category === "language" || category === "year") {
|
||||
// return { terms: { [category]: values } };
|
||||
// } else {
|
||||
// return { terms: { [`${category}.keyword`]: values } };
|
||||
// }
|
||||
// });
|
||||
// console.log("filters:", filters);
|
||||
|
||||
// // Determine search term and query fields based on the suggestion type
|
||||
// let query;
|
||||
// if (typeof suggestion === "string") { // If suggestion is a string, append a wildcard (*) for partial matches
|
||||
// const lowercaseTerm = suggestion.toLowerCase()
|
||||
// query = {
|
||||
// bool: {
|
||||
// should: [
|
||||
// { match: { title: { query: suggestion, fuzziness: "AUTO", boost: 3 } } },
|
||||
// { match: { author: { query: suggestion, fuzziness: "AUTO", boost: 2 } } },
|
||||
// { match: { subjects: { query: suggestion, fuzziness: "AUTO", boost: 1 } } },
|
||||
// { wildcard: { title: { value: `${lowercaseTerm}*`, boost: 3 } } },
|
||||
// { wildcard: { author: { value: `${lowercaseTerm}*`, boost: 2 } } },
|
||||
// { wildcard: { subjects: { value: `${lowercaseTerm}*`, boost: 1 } } }
|
||||
// ],
|
||||
// minimum_should_match: 1
|
||||
// }
|
||||
// };
|
||||
// } else if (suggestion instanceof Suggestion) { // If suggestion is a Suggestion object, form a specific query
|
||||
// query = {
|
||||
// match: {
|
||||
// [suggestion.type]: {
|
||||
// query: suggestion.value,
|
||||
// operator: 'and' // all the terms in the query must be present in the field e.g. if is a title, the complete title
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
// }
|
||||
|
||||
// // Set default value for start if not provided
|
||||
// const startValue = start ? parseInt(start) : 0;
|
||||
|
||||
// // console.log(activeFilterCategories);
|
||||
// // console.log("mainQuery:", mainQuery);
|
||||
|
||||
// // Construct the body of the OpenSearch query
|
||||
// const body = {
|
||||
|
||||
// query: {
|
||||
// bool: {
|
||||
// must: [
|
||||
// mainQuery, // Ensure the main query must be satisfied
|
||||
// ...filters // Ensure all filters must be satisfied
|
||||
// ]
|
||||
// }
|
||||
// },
|
||||
|
||||
// // // WORKS // Expected: 12 results
|
||||
// // query: {
|
||||
// // bool: {
|
||||
// // "must": [
|
||||
// // { "term": { "language": "en" } },
|
||||
// // { "term": { "subjects.keyword": "Lower Austria" } },
|
||||
// // { "term": { "subjects.keyword": "counting data" } }
|
||||
// // ],
|
||||
// // }
|
||||
// // },
|
||||
|
||||
// // // THIS WORKS: // Expected: 19 results
|
||||
// // query: {
|
||||
// // bool: {
|
||||
// // must: [
|
||||
// // { "match": { "title": "Blatt" } },
|
||||
// // { "term": { "subjects": "bayern" } }
|
||||
// // ],
|
||||
// // }
|
||||
// // },
|
||||
|
||||
// // // WORKS // Expected: 4 results
|
||||
// // query: {
|
||||
// // bool: {
|
||||
// // "must": [
|
||||
// // { "match": { "title": "blatt" } },
|
||||
// // { "term": { "subjects": "bayern" } },
|
||||
// // { "term": { "subjects": "salzburg" } }
|
||||
// // ],
|
||||
// // }
|
||||
// // },
|
||||
|
||||
// // // WORKS // Expected: 2 results
|
||||
// // query: {
|
||||
// // bool: {
|
||||
// // "must": [
|
||||
// // { "match": { "title": "blatt" } },
|
||||
// // { "term": { "subjects": "ungarn" } },
|
||||
// // { "term": { "subjects": "steiermark" } }
|
||||
// // ],
|
||||
// // }
|
||||
// // },
|
||||
|
||||
// // WORKS // Expected: 12 results
|
||||
// query: {
|
||||
// bool: {
|
||||
// "must": [
|
||||
// { "term": { "language": "en" } },
|
||||
// { "term": { "subjects.keyword": "Lower Austria" } },
|
||||
// { "term": { "subjects.keyword": "counting data" } }
|
||||
// ],
|
||||
// "should": [
|
||||
// { match: { title: { query: "halger", fuzziness: "AUTO", boost: 3 } } },
|
||||
// { match: { author: { query: "halger", fuzziness: "AUTO", boost: 2 } } },
|
||||
// { match: { subjects: { query: "halger", fuzziness: "AUTO", boost: 1 } } },
|
||||
// { wildcard: { title: { value: "halger", boost: 3 } } },
|
||||
// { wildcard: { author: { value: "halger", boost: 2 } } },
|
||||
// { wildcard: { subjects: { value: "halger", boost: 1 } } }
|
||||
// ],
|
||||
// minimum_should_match: 1
|
||||
// }
|
||||
// },
|
||||
|
||||
// size: 10,
|
||||
// from: startValue,
|
||||
// sort: [{ _score: { order: "desc" } }],
|
||||
// track_scores: true,
|
||||
|
||||
// aggs: {
|
||||
// subjects: { terms: { field: "subjects.keyword", size: 1000 } },
|
||||
// language: { terms: { field: "language" } },
|
||||
// author: { terms: { field: "author.keyword", size: 1000 } },
|
||||
// year: { terms: { field: "year", size: 100 } }
|
||||
// },
|
||||
|
||||
// highlight: {
|
||||
// fields: {
|
||||
// title: {},
|
||||
// author: {},
|
||||
// subjects: {}
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
|
||||
// console.log("mainQuery:", mainQuery);
|
||||
// console.log("filters:", filters);
|
||||
// console.log("body:", body);
|
||||
|
||||
// // Make API call to OpenSearch and return the result
|
||||
// const stations = api.post<OpenSearchResponse>(base, body);
|
||||
|
||||
// return stations;
|
||||
// }
|
||||
|
||||
|
||||
|
||||
public facetedSearchOPEN(
|
||||
suggestion: Suggestion | string,
|
||||
activeFilterCategories: ActiveFilterCategories,
|
||||
solrCore: string,
|
||||
solrHost: string,
|
||||
start?: string,
|
||||
): Observable<SolrResponse> {
|
||||
// solr endpoint
|
||||
// const host = 'http://voyagerdemo.com/';
|
||||
//const host = 'https://www.tethys.at/';
|
||||
//const host = 'https://' + solrHost;
|
||||
const host = "https://" + solrHost;
|
||||
const path = "/solr/" + solrCore + "/select?";
|
||||
openCore: string,
|
||||
openHost: string,
|
||||
start?: string, // Starting page
|
||||
): Observable<OpenSearchResponse> {
|
||||
// OpenSearch endpoint
|
||||
const host = openHost;
|
||||
const path = "/" + openCore + "/_search";
|
||||
const base = host + path;
|
||||
|
||||
//const fields = 'id,server_date_published,abstract_output,title_output,title_additional,author,subject'; // fields we want returned
|
||||
const fields = [
|
||||
"id",
|
||||
"licence",
|
||||
"server_date_published",
|
||||
"abstract_output",
|
||||
"identifier",
|
||||
"title_output",
|
||||
"title_additional",
|
||||
"author",
|
||||
"subject",
|
||||
"doctype",
|
||||
].toString();
|
||||
const lowercaseTerm = typeof suggestion === 'string' ? suggestion.toLowerCase() : suggestion.value;
|
||||
|
||||
// const qfFields = "title^3 author^2 subject^1";
|
||||
// let params = "fl=" + fields;
|
||||
// if (term == "*%3A*") {
|
||||
// params += "&defType=edismax&wt=json&indent=on"; //edismax
|
||||
// } else {
|
||||
// params += "&defType=dismax&qf=" + qfFields + "&wt=json&indent=on"; //dismax
|
||||
// }
|
||||
// console.log("facetedsearchOPEN > suggestion entered:");
|
||||
// console.log(suggestion);
|
||||
// console.log("typeof:", typeof suggestion);
|
||||
|
||||
let term, queryOperator, qfFields;
|
||||
if (typeof suggestion === "string") {
|
||||
term = suggestion + "*";
|
||||
queryOperator = "or";
|
||||
qfFields = "title^3 author^2 subject^1";
|
||||
} else if (suggestion instanceof Suggestion) {
|
||||
term = suggestion.type + ':"' + suggestion.value + '"';
|
||||
queryOperator = "and";
|
||||
qfFields = undefined;
|
||||
}
|
||||
|
||||
if (start === undefined) start = "0";
|
||||
// start = "&start=" + start;
|
||||
|
||||
// const facetFields =
|
||||
// "&facet=on&facet.field=language&facet.field={!key=datatype}doctype&facet.field=subject"; //&fq=year:(2019)";//&facet.query=year:2018";
|
||||
|
||||
const filterFields = new Array<string>();
|
||||
if (Object.keys(activeFilterCategories).length > 0) {
|
||||
// filterFields = '["';
|
||||
// const filterFields: string[] = [];
|
||||
// const facet_fields: FacetFields = res.facets;
|
||||
let prop: keyof typeof activeFilterCategories;
|
||||
for (prop in activeFilterCategories) {
|
||||
const filterItems = activeFilterCategories[prop];
|
||||
// const filterItems = facetCategory.values;
|
||||
// filterItems.forEach((filterItem) => {
|
||||
// console.log(`${key} ${valueArray}`);
|
||||
filterItems.forEach(function (value: string) {
|
||||
// filterFields += "&fq=" + key + ':("' + value + '")';
|
||||
filterFields.push(prop + ':("' + value + '")');
|
||||
// filterFields += prop + ":" + value;
|
||||
});
|
||||
/**
|
||||
* The query construction depends on whether the suggestion is a string or a Suggestion object. */
|
||||
// When suggestion is a string:
|
||||
const mainQuery = typeof suggestion === 'string'
|
||||
? {
|
||||
bool: {
|
||||
should: [
|
||||
{ match: { title: { query: suggestion, fuzziness: "AUTO", boost: 3 } } },
|
||||
{ match: { author: { query: suggestion, fuzziness: "AUTO", boost: 2 } } },
|
||||
{ match: { subjects: { query: suggestion, fuzziness: "AUTO", boost: 1 } } },
|
||||
{ wildcard: { title: { value: `${lowercaseTerm}*`, boost: 3 } } },
|
||||
{ wildcard: { author: { value: `${lowercaseTerm}*`, boost: 2 } } },
|
||||
{ wildcard: { subjects: { value: `${lowercaseTerm}*`, boost: 1 } } }
|
||||
],
|
||||
minimum_should_match: 1
|
||||
}
|
||||
}
|
||||
// filterFields += '"]';
|
||||
}
|
||||
// const query = "&sort=server_date_published desc" + "&q=" + term;
|
||||
// When suggestion is a suggestion object
|
||||
: {
|
||||
match: {
|
||||
[suggestion.type]: {
|
||||
query: suggestion.value,
|
||||
operator: 'and' // all the terms in the query must be present in the field
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// const api =
|
||||
// base + params + limit + start + query + filterFields + facetFields;
|
||||
// CONTABO ====================================================
|
||||
// // Constructing Filters Based on Active Filter Categories
|
||||
// const filters = Object.entries(activeFilterCategories).map(([category, values]) => ({
|
||||
// terms: { [`${category}.keyword`]: values }
|
||||
// }));
|
||||
// ================================================================
|
||||
|
||||
// https://solr.apache.org/guide/8_4/json-request-api.html
|
||||
const q_params = {
|
||||
"0": "fl=" + fields,
|
||||
q: term,
|
||||
"q.op": queryOperator,
|
||||
defType: "edismax",
|
||||
qf: qfFields,
|
||||
// df: "title",
|
||||
indent: "on",
|
||||
wt: "json",
|
||||
rows: 10,
|
||||
// fq: ["subject:Steiermark", "language:de"],
|
||||
fq: filterFields,
|
||||
start: start,
|
||||
sort: "server_date_published desc",
|
||||
facet: "on",
|
||||
// "facet.field": "language",
|
||||
"json.facet.language": '{ type: "terms", field: "language" }',
|
||||
"json.facet.subject": '{ type: "terms", field: "subject", limit: -1 }',
|
||||
"json.facet.year": '{ type: "terms", field: "year" }',
|
||||
"json.facet.author": '{ type: "terms", field: "author_facet", limit: -1 }',
|
||||
// // Constructing Filters Based on Active Filter Categories
|
||||
// const filters = Object.entries(activeFilterCategories).map(([category, values]) => {
|
||||
// if (category === "language" || category === "year") {
|
||||
// return { terms: { [category]: values } };
|
||||
// } else {
|
||||
// return { terms: { [`${category}.keyword`]: values } };
|
||||
// }
|
||||
// });
|
||||
|
||||
|
||||
// const filters = Object.entries(activeFilterCategories).map(([category, values]) =>
|
||||
// values.map(value => ({ term: { [`${category}.keyword`]: value } }))
|
||||
// ).flat();
|
||||
|
||||
|
||||
const filters = Object.entries(activeFilterCategories).map(([category, values]) => {
|
||||
if (category === "language" || category === "year") {
|
||||
return values.map(value => ({ term: { [category]: value } }));
|
||||
} else {
|
||||
return values.map(value => ({ term: { [`${category}.keyword`]: value } }));
|
||||
}
|
||||
}).flat();
|
||||
|
||||
// console.log(activeFilterCategories);
|
||||
console.log("mainQuery:", mainQuery);
|
||||
console.log("filters:", filters);
|
||||
|
||||
const body = {
|
||||
// query: {
|
||||
// bool: {
|
||||
// must: query, // Contains the main query constructed earlier.
|
||||
// filter: filters // Contains the filters constructed from activeFilterCategories.
|
||||
// // filter: [
|
||||
// // { "terms": { "subjects.keyword": ["Lower Austria", "counting data"] } },
|
||||
// // { "term": { "language": "en" } }
|
||||
// // ] // Contains the filters constructed from activeFilterCategories.
|
||||
// }
|
||||
// },
|
||||
|
||||
query: {
|
||||
bool: {
|
||||
must: [
|
||||
mainQuery, // Ensure the main query must be satisfied
|
||||
...filters // Ensure all filters must be satisfied
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
// // THIS DOESNT WORK // Expected: 12 results, Ouput: 16
|
||||
// query: {
|
||||
// bool: {
|
||||
// "must": [
|
||||
// { "term": { "language": "en" } },
|
||||
// { "terms": { "subjects.keyword": ["Lower Austria", "counting data"] } }
|
||||
// ],
|
||||
// "should": [
|
||||
// { match: { title: { query: "halger", fuzziness: "AUTO", boost: 3 } } },
|
||||
// { match: { author: { query: "halger", fuzziness: "AUTO", boost: 2 } } },
|
||||
// { match: { subjects: { query: "halger", fuzziness: "AUTO", boost: 1 } } },
|
||||
// { wildcard: { title: { value: "halger", boost: 3 } } },
|
||||
// { wildcard: { author: { value: "halger", boost: 2 } } },
|
||||
// { wildcard: { subjects: { value: "halger", boost: 1 } } }
|
||||
// ],
|
||||
// minimum_should_match: 1
|
||||
// }
|
||||
// },
|
||||
|
||||
size: 10,
|
||||
from: start ? parseInt(start) : 0,
|
||||
sort: [{ _score: { order: "desc" } }],
|
||||
track_scores: true,
|
||||
aggs: { // Defines aggregations for facets
|
||||
// terms: Aggregation type that returns the most common terms in a field.
|
||||
// !For a large number of terms setting an extremely large size might not be efficient
|
||||
// If you genuinely need all unique terms and expect a large number of them, consider using a composite aggregation for more efficient pagination of terms.
|
||||
subjects: { terms: { field: "subjects.keyword", size: 1000 } }, // In SOLR is "subject"!
|
||||
language: { terms: { field: "language" } }, // ".keyword" HAS TO BE REMOVED. OTHERWISE BUCKETS ARE NOT OBTAINED FOR THIS
|
||||
author: { terms: { field: "author.keyword", size: 1000 } },
|
||||
year: { terms: { field: "year", size: 100 } } // ".keyword" HAS TO BE REMOVED. OTHERWISE BUCKETS ARE NOT OBTAINED FOR THIS
|
||||
},
|
||||
// CONTABO ================================================================================
|
||||
// aggs: {
|
||||
// subjects: { terms: { field: "subjects.keyword", size: 1000 } }, // In SOLR is "subject"!
|
||||
// language: { terms: { field: "language.keyword" } }, // << ".keyword" HAS TO BE REMOVED. OTHERWISE BUCKETS ARE NOT OBTAINED FOR THIS
|
||||
// author: { terms: { field: "author.keyword", size: 1000 } },
|
||||
// year: { terms: { field: "year.keyword", size: 100 } } // << ".keyword" HAS TO BE REMOVED. OTHERWISE BUCKETS ARE NOT OBTAINED FOR THIS
|
||||
// },
|
||||
// ===========================================================================================
|
||||
highlight: {
|
||||
fields: {
|
||||
title: {},
|
||||
author: {},
|
||||
subjects: {}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const stations = api.get<SolrResponse>(base, q_params);
|
||||
// .pipe(map((res) => res.response.docs));
|
||||
console.log("body:", body);
|
||||
|
||||
const stations = api.post<OpenSearchResponse>(base, body);
|
||||
|
||||
return stations;
|
||||
}
|
||||
|
||||
// /**
|
||||
// * This method performs a faceted search on a Solr core. Faceted search allows the user to filter search results based on various categories (facets)
|
||||
// */
|
||||
// public facetedSearch_SOLR(
|
||||
// suggestion: Suggestion | string,
|
||||
// activeFilterCategories: ActiveFilterCategories,
|
||||
// solrCore: string,
|
||||
// solrHost: string,
|
||||
// start?: string, // Starting page
|
||||
// ): Observable<SolrResponse> {
|
||||
// // console.log("face:", suggestion);
|
||||
// // console.log(activeFilterCategories);
|
||||
// // console.log(solrCore);
|
||||
// // console.log(solrHost);
|
||||
// // console.log(start);
|
||||
|
||||
// console.log("facetedsearchSOLR > suggestion entered:");
|
||||
// console.log(suggestion);
|
||||
|
||||
// // Construct Solr query parameters
|
||||
// const host = "https://" + solrHost;
|
||||
// const path = "/solr/" + solrCore + "/select?";
|
||||
// const base = host + path;
|
||||
|
||||
// const fields = [
|
||||
// "id",
|
||||
// "licence",
|
||||
// "server_date_published",
|
||||
// "abstract_output",
|
||||
// "identifier",
|
||||
// "title_output",
|
||||
// "title_additional",
|
||||
// "author",
|
||||
// "subject",
|
||||
// "doctype",
|
||||
// ].toString();
|
||||
|
||||
// // Determine search term, query operator, and query fields based on the suggestion type. Depending on whether suggestion is a string or a Suggestion object, it constructs the search term and query fields differently.
|
||||
// let term, queryOperator, qfFields;
|
||||
// if (typeof suggestion === "string") { // f suggestion is a string, it appends a wildcard (*) for partial matches.
|
||||
// term = suggestion + "*";
|
||||
// queryOperator = "or";
|
||||
// qfFields = "title^3 author^2 subject^1";
|
||||
// } else if (suggestion instanceof Suggestion) { // If suggestion is a Suggestion object, it forms a more specific query based on the type and value of the suggestion.
|
||||
// term = suggestion.type + ':"' + suggestion.value + '"';
|
||||
// queryOperator = "and";
|
||||
// qfFields = undefined;
|
||||
// }
|
||||
|
||||
// // Set default value for start if not provided
|
||||
// if (start === undefined) start = "0";
|
||||
|
||||
// // Construct filter fields based on active filter categories
|
||||
// const filterFields = new Array<string>();
|
||||
// if (Object.keys(activeFilterCategories).length > 0) {
|
||||
// /* Declare variable prop with a type that is a key of the activeFilterCategories. The 'keyof typeof' activeFilterCategories type represents all possible keys
|
||||
// that can exist on the activeFilterCategories --> prop can only be assigned a value that is a key of the activeFilterCategories object */
|
||||
// let prop: keyof typeof activeFilterCategories;
|
||||
// for (prop in activeFilterCategories) {
|
||||
// const filterItems = activeFilterCategories[prop];
|
||||
// filterItems.forEach(function (value: string) {
|
||||
// filterFields.push(prop + ':("' + value + '")');
|
||||
// // e.g. Array [ 'subject:("Vektordaten")', 'author:("GeoSphere Austria, ")' ]
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
|
||||
// // https://solr.apache.org/guide/8_4/json-request-api.html
|
||||
// // Construct Solr query parameters
|
||||
// const q_params = {
|
||||
// "0": "fl=" + fields,
|
||||
// q: term,
|
||||
// "q.op": queryOperator,
|
||||
// defType: "edismax",
|
||||
// qf: qfFields,
|
||||
// // df: "title",
|
||||
// indent: "on",
|
||||
// wt: "json",
|
||||
// rows: 10,
|
||||
// // fq: ["subject:Steiermark", "language:de"],
|
||||
// fq: filterFields,
|
||||
// start: start,
|
||||
// sort: "server_date_published desc",
|
||||
// facet: "on",
|
||||
// // "facet.field": "language",
|
||||
// "json.facet.language": '{ type: "terms", field: "language" }',
|
||||
// "json.facet.subject": '{ type: "terms", field: "subject", limit: -1 }',
|
||||
// "json.facet.year": '{ type: "terms", field: "year" }',
|
||||
// "json.facet.author": '{ type: "terms", field: "author_facet", limit: -1 }',
|
||||
// };
|
||||
// /* E.g.
|
||||
// {"0":"fl=id,licence,server_date_published,abstract_output,identifier,title_output,title_additional,author,subject,doctype","q":"*","q.op":"or","defType":"edismax",
|
||||
// "qf":"title^3 author^2 subject^1",
|
||||
// "indent":"on","wt":"json","rows":10,
|
||||
// "fq":["subject:(\"Vektordaten\")","author:(\"GeoSphere Austria, \")"],
|
||||
// "start":"0","sort":"server_date_published desc","facet":"on",
|
||||
// "json.facet.language":"{ type: \"terms\", field: \"language\" }",
|
||||
// "json.facet.subject":"{ type: \"terms\", field: \"subject\", limit: -1 }",
|
||||
// "json.facet.year":"{ type: \"terms\", field: \"year\" }",
|
||||
// "json.facet.author":"{ type: \"terms\", field: \"author_facet\", limit: -1 }"}
|
||||
// */
|
||||
// // console.log(JSON.stringify(q_params));
|
||||
|
||||
// // Make API call to Solr and return the result
|
||||
// const stations = api.get<SolrResponse>(base, q_params);
|
||||
|
||||
// return stations;
|
||||
// }
|
||||
|
||||
// Method to fetch years
|
||||
public getYears(): Observable<string[]> {
|
||||
// const heroes = of(HEROES);
|
||||
// const host = "https:" + VUE_API;
|
||||
const host = VUE_API;
|
||||
const path = "/api/years";
|
||||
const base = host + path;
|
||||
|
||||
const years = api.get<string[]>(base);
|
||||
// this.messageService.add('HeroService: fetched heroes');
|
||||
return years;
|
||||
}
|
||||
|
||||
// Method to fetch documents for a specific year
|
||||
public getDocuments(year: string): Observable<Array<DbDataset>> {
|
||||
// const host = "https:" + VUE_API;
|
||||
const host = VUE_API;
|
||||
const path = "/api/sitelinks/" + year;
|
||||
const base = host + path;
|
||||
|
||||
const documents: Observable<DbDataset[]> = api.get<Array<DbDataset>>(base);
|
||||
// this.messageService.add('HeroService: fetched heroes');
|
||||
return documents;
|
||||
}
|
||||
|
||||
// Method to fetch a dataset by its ID
|
||||
public getDataset(id: number): Observable<DbDataset> {
|
||||
// const host = "https:" + VUE_API;
|
||||
const host = VUE_API;
|
||||
const path = "/api/dataset/" + id;
|
||||
const apiUrl = host + path;
|
||||
const dataset = api.get<DbDataset>(apiUrl).pipe(map((res) => this.prepareDataset(res)));
|
||||
// const dataset = api.get<DbDataset>(apiUrl).pipe(map((res) => this.prepareDataset(res, apiUrl)));
|
||||
|
||||
// this.messageService.add('HeroService: fetched heroes');
|
||||
return dataset;
|
||||
}
|
||||
|
||||
// Method to fetch a dataset by its DOI
|
||||
public getDatasetByDoi(doi: string): Observable<DbDataset> {
|
||||
// const host = "https:" + VUE_API;
|
||||
const host = VUE_API;
|
||||
const path = "/api/dataset/10.24341/tethys." + doi;
|
||||
const apiUrl = host + path;
|
||||
const dataset = api.get<DbDataset>(apiUrl).pipe(map((res) => this.prepareDataset(res)));
|
||||
// const dataset = api.get<DbDataset>(apiUrl).pipe(map((res) => this.prepareDataset(res, apiUrl)));
|
||||
|
||||
// this.messageService.add('HeroService: fetched heroes');
|
||||
return dataset;
|
||||
}
|
||||
|
||||
// public getOaiDatasets(): Observable<OaiDataset[]> {
|
||||
// const apiUrl = "https://data.tethys.at/oai?verb=ListRecords&metadataPrefix=oai_datacite";
|
||||
// const oaiDatasets = api.get<string>(apiUrl).pipe(
|
||||
// map(
|
||||
// (response: string) => {
|
||||
// // const parser = new DOMParser();
|
||||
// // const xmlDoc: XMLDocument = parser.parseFromString(response, "application/xml");
|
||||
|
||||
// // const xslDoc = parser.parseFromString(this.xsl, "application/xml");
|
||||
// // const xsltProcessor = new XSLTProcessor();
|
||||
// // xsltProcessor.importStylesheet(xslDoc);
|
||||
// // console.log(xmlDoc);
|
||||
// // const xmlDom = xsltProcessor.transformToDocument(xmlDoc);
|
||||
|
||||
// // const serializer = new XMLSerializer();
|
||||
// // const html = serializer.serializeToString(xmlDom.documentElement);
|
||||
// // console.log(html);
|
||||
|
||||
// // const arrOai = new Array<OaiDataset>();
|
||||
// // return arrOai;
|
||||
// const arrOai = this.parseXML(response);
|
||||
// return arrOai;
|
||||
// // .then((data) => {
|
||||
// // return data;
|
||||
// // });
|
||||
// },
|
||||
// // (error: string) => this.errorHandler(error),
|
||||
// ),
|
||||
// );
|
||||
// // const oaiDatasets = of(OAI_DATASETS);
|
||||
|
||||
// // this.messageService.add('HeroService: fetched heroes');
|
||||
// return oaiDatasets;
|
||||
// }
|
||||
|
||||
// private parseXML(xmlStr: string): Array<OaiDataset> {
|
||||
// // let k = "";
|
||||
// const arr: OaiDataset[] = [];
|
||||
// const domParser = new DOMParser();
|
||||
// const doc = domParser.parseFromString(xmlStr, "application/xml");
|
||||
// const records = doc.getElementsByTagName("ListRecords")[0];
|
||||
// // // const rt = xmlNode.resumptionToken;
|
||||
// // for (let i = 0; i < records.length; i++) {
|
||||
// // console.log(records[i].getAttribute("name"));
|
||||
// // }
|
||||
|
||||
// const parser: xml2js.Parser = new xml2js.Parser({
|
||||
// trim: true,
|
||||
// explicitArray: false,
|
||||
// ignoreAttrs: false,
|
||||
// // mergeAttrs: true,
|
||||
// });
|
||||
// parser.parseString(records.outerHTML, function (err: Error | null, result: any) {
|
||||
// const xmlNode = result.ListRecords;
|
||||
// // const rt = xmlNode.resumptionToken;
|
||||
// for (const rNode in xmlNode.record) {
|
||||
// const item = xmlNode.record[rNode];
|
||||
|
||||
// const dc = item.metadata.resource;
|
||||
// const t = dc.titles.title;
|
||||
// const id = dc.identifier._;
|
||||
|
||||
// const lang = "en"; //dc.titles.title.attributes("xml",True)->lang;
|
||||
// let title: string;
|
||||
// if (lang == "en" && t.length > 1) {
|
||||
// title = t[1]._;
|
||||
// } else {
|
||||
// title = t[0]._;
|
||||
// }
|
||||
|
||||
// let creator = "";
|
||||
// if (dc.creators.creator instanceof Array) {
|
||||
// dc.creators.creator.forEach((person: OaiPerson) => {
|
||||
// creator += person.creatorName + "; ";
|
||||
// });
|
||||
// } else {
|
||||
// creator += dc.creators.creator.creatorName._;
|
||||
// }
|
||||
|
||||
// let contributor = "";
|
||||
// if (dc.contributors) {
|
||||
// if (dc.contributors.contributor instanceof Array) {
|
||||
// dc.contributors.contributor.forEach((person: OaiPerson) => {
|
||||
// contributor += person.contributorName + "; ";
|
||||
// });
|
||||
// } else {
|
||||
// contributor += dc.contributors.contributor.contributorName;
|
||||
// }
|
||||
// }
|
||||
|
||||
// // ?.map((u: any) => u.creatorName._).join("; ");
|
||||
// // foreach ($dc->creators->creator as $c) {
|
||||
// // foreach ($c->creatorName as $d) {
|
||||
// // if (count(explode(',',$d)) > 1) {
|
||||
// // $creator .= explode(',',$d)[0] . ', ' . substr(explode(',',$d)[1],1,1) . '; ';
|
||||
// // } else {
|
||||
// // $creator .= explode(',',$d)[0];
|
||||
// // }
|
||||
|
||||
// // }
|
||||
// // }
|
||||
|
||||
// const north = dc.geoLocations.geoLocation.geoLocationBox.northBoundLatitude;
|
||||
// const east = dc.geoLocations.geoLocation.geoLocationBox.eastBoundLongitude;
|
||||
// const south = dc.geoLocations.geoLocation.geoLocationBox.southBoundLatitude;
|
||||
// const west = dc.geoLocations.geoLocation.geoLocationBox.westBoundLongitude;
|
||||
|
||||
// const subject = dc.subjects.subject.map((u: any) => u._).join(", ");
|
||||
|
||||
// const oaiDataset = {
|
||||
// doi: id,
|
||||
// title: title,
|
||||
// creator: creator,
|
||||
// contributor: contributor,
|
||||
// subject: subject,
|
||||
// north: north,
|
||||
// south: south,
|
||||
// east: east,
|
||||
// west: west,
|
||||
// } as OaiDataset;
|
||||
// arr.push(oaiDataset);
|
||||
// }
|
||||
// // resolve(arr);
|
||||
// });
|
||||
// return arr;
|
||||
// }
|
||||
|
||||
// private prepareOAI(xml: any) : Array<OaiDataset> {
|
||||
// //
|
||||
// }
|
||||
|
||||
// private prepareDataset(datasetObj: DbDataset, apiUrl: string): DbDataset {
|
||||
// Method to prepare dataset object
|
||||
private prepareDataset(datasetObj: DbDataset): DbDataset {
|
||||
const dataset = deserialize<DbDataset>(DbDataset, JSON.stringify(datasetObj));
|
||||
dataset.url = document.documentURI;
|
||||
// this.internalDatasetId.generateInternalId(dataset);
|
||||
// if (dataset.seriesParameters) {
|
||||
// dataset.parameters = dataset.seriesParameters;
|
||||
// delete dataset.seriesParameters;
|
||||
// }
|
||||
|
||||
return dataset;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,6 +59,8 @@ export default class DatasetDetailComponent extends Vue {
|
|||
}
|
||||
|
||||
onSearch(suggestion: Suggestion | string): void {
|
||||
console.log("onSearch (dataset-detail.component)");
|
||||
|
||||
const host = window.location.host;
|
||||
const parts = host.split(".");
|
||||
if (parts[0] === "doi") {
|
||||
|
|
|
@ -11,6 +11,9 @@ import { Suggestion } from "@/models/dataset";
|
|||
export default class HomeViewComponent extends Vue {
|
||||
public display = "";
|
||||
|
||||
/* This method is called when a search suggestion is selected. It takes a parameter suggestion which can be either a Suggestion object or a string.
|
||||
If it's a string, the method extracts the term and navigates to the "Search" route with the term as a parameter. If it's a Suggestion object, it extracts
|
||||
the value and type from the suggestion and navigates to the "Search" route with both parameters.*/
|
||||
onSearch(suggestion: Suggestion | string): void {
|
||||
let term;
|
||||
if (typeof suggestion === "string") {
|
||||
|
@ -22,6 +25,7 @@ export default class HomeViewComponent extends Vue {
|
|||
}
|
||||
}
|
||||
|
||||
/* This method is called when the user initiates a search. It navigates to the "Search" route with the display property as a parameter. */
|
||||
search(): void {
|
||||
this.$router.push({ name: "Search", params: { display: this.display } });
|
||||
}
|
||||
|
|
|
@ -18,13 +18,6 @@
|
|||
</a>
|
||||
</div> -->
|
||||
|
||||
<!-- <div class="column">
|
||||
<div class="col text-center py-3">
|
||||
<h1>Tethys Research Data Repository</h1>
|
||||
<p class="lead">Data Publisher for Geoscience Austria</p>
|
||||
<hr class="center-line" />
|
||||
</div>
|
||||
</div> -->
|
||||
<div class="column">
|
||||
<div class="col text-center py-3">
|
||||
<h1>Tethys Research Data Repository</h1>
|
||||
|
|
|
@ -3,16 +3,23 @@ import VsInput from "@/components/vs-input/vs-input.vue";
|
|||
import VsResult from "@/components/vs-result/vs-result.vue";
|
||||
import FacetCategory from "@/components/face-category/facet-category.vue";
|
||||
import ActiveFacetCategory from "@/components/active-facet-category/active-facet-category.vue";
|
||||
import { SolrSettings } from "@/models/solr";
|
||||
// import { SolrSettings } from "@/models/solr";
|
||||
|
||||
import { OpenSettings } from "@/models/solr";
|
||||
// import { DatasetService } from "@/services/dataset.service";
|
||||
import DatasetService from "../../services/dataset.service";
|
||||
import { Suggestion, Dataset, SearchType } from "@/models/dataset";
|
||||
import { SolrResponse, FacetFields, FacetItem, FacetResults, FacetInstance } from "@/models/headers";
|
||||
// import { SolrResponse, FacetFields, FacetItem, FacetResults, FacetInstance } from "@/models/headers";
|
||||
// import { SolrResponse, FacetFields, FacetItem, FacetResults, FacetInstance, OpenSearchResponse, HitHighlight } from "@/models/headers";
|
||||
import { FacetFields, FacetItem, FacetResults, FacetInstance, OpenSearchResponse, HitHighlight } from "@/models/headers";
|
||||
import { ActiveFilterCategories } from "@/models/solr";
|
||||
import { SOLR_HOST, SOLR_CORE } from "@/constants";
|
||||
// import { SOLR_HOST, SOLR_CORE } from "@/constants";
|
||||
import { IPagination } from "@/models/pagination";
|
||||
import PaginationComponent from "@/components/PaginationComponent.vue";
|
||||
|
||||
import { OPEN_HOST, OPEN_CORE } from "@/constants";
|
||||
|
||||
// Decorate the component and define its name and components
|
||||
@Component({
|
||||
name: "SearchViewComponent",
|
||||
components: {
|
||||
|
@ -23,6 +30,8 @@ import PaginationComponent from "@/components/PaginationComponent.vue";
|
|||
PaginationComponent,
|
||||
},
|
||||
})
|
||||
|
||||
// Define the SearchViewComponent class
|
||||
export default class SearchViewComponent extends Vue {
|
||||
@Prop()
|
||||
display!: string;
|
||||
|
@ -46,16 +55,22 @@ export default class SearchViewComponent extends Vue {
|
|||
};
|
||||
loaded = false;
|
||||
numFound!: number;
|
||||
private solr: SolrSettings = {
|
||||
core: SOLR_CORE, //"rdr_data", // SOLR.core;
|
||||
host: SOLR_HOST, //"tethys.at",
|
||||
// core: "test_data", // SOLR.core;
|
||||
// host: "repository.geologie.ac.at",
|
||||
// private solr: SolrSettings = {
|
||||
// core: SOLR_CORE, //"rdr_data", // SOLR.core;
|
||||
// host: SOLR_HOST, //"tethys.at",
|
||||
// };
|
||||
|
||||
private open: OpenSettings = {
|
||||
core: OPEN_CORE, //"rdr_data", // SOLR.core;
|
||||
host: OPEN_HOST, //"tethys.at",
|
||||
};
|
||||
// private rdrAPI!: DatasetService;
|
||||
|
||||
private error = "";
|
||||
|
||||
// Computed property to get search term as string
|
||||
get stringSearchTerm(): string {
|
||||
// console.log("stringSearchTerm:", this.searchTerm);
|
||||
|
||||
if (typeof this.searchTerm === "string") {
|
||||
return this.searchTerm;
|
||||
} else if (this.searchTerm instanceof Suggestion) {
|
||||
|
@ -65,6 +80,7 @@ export default class SearchViewComponent extends Vue {
|
|||
}
|
||||
}
|
||||
|
||||
// Method to check if a search term is present
|
||||
hasSearchTerm(): boolean {
|
||||
if (typeof this.searchTerm === "string" && this.searchTerm !== "") {
|
||||
return true;
|
||||
|
@ -77,18 +93,25 @@ export default class SearchViewComponent extends Vue {
|
|||
// getKeyName(value: string) {
|
||||
// return Object.entries(Suggestion).find(([key, val]) => val === value)?.[0];
|
||||
// }
|
||||
|
||||
// Method to get enum key by enum value
|
||||
getEnumKeyByEnumValue<T extends { [index: string]: string }>(myEnum: T, enumValue: string): keyof T | null {
|
||||
const keys = Object.keys(myEnum).filter((x) => myEnum[x] == enumValue);
|
||||
return keys.length > 0 ? keys[0] : null;
|
||||
// return keys[0];
|
||||
}
|
||||
|
||||
// Lifecycle hook: executed before the component is mounted
|
||||
beforeMount(): void {
|
||||
// console.log("beforeMount!");
|
||||
|
||||
// this.rdrAPI = new DatasetService();
|
||||
// Trigger search based on provided display and type props
|
||||
if (this.display != "" && this.type != undefined) {
|
||||
const enumKey: "Title" | "Author" | "Subject" | null = this.getEnumKeyByEnumValue(SearchType, this.type);
|
||||
if (enumKey) {
|
||||
const suggestion = new Suggestion(this.display, SearchType[enumKey]);
|
||||
const suggestion = new Suggestion(this.display, "NO-IDEA", SearchType[enumKey]);
|
||||
// const suggestion = new Suggestion(this.display, "" , SearchType[enumKey]);
|
||||
this.onSearch(suggestion);
|
||||
} else {
|
||||
this.onSearch(this.display);
|
||||
|
@ -100,209 +123,327 @@ export default class SearchViewComponent extends Vue {
|
|||
}
|
||||
}
|
||||
|
||||
// onSearch(term: string): void {
|
||||
// Method to trigger a search
|
||||
onSearch(suggestion: Suggestion | string): void {
|
||||
// let queryOperator;
|
||||
// if (typeof suggestion === "string") {
|
||||
// suggestion = suggestion + "*";
|
||||
// queryOperator = "or";
|
||||
// } else if (suggestion instanceof Suggestion) {
|
||||
// // term = suggestion.value;
|
||||
// queryOperator = "and";
|
||||
// }
|
||||
|
||||
// if (term) {
|
||||
// term = term.trim();
|
||||
// } else {
|
||||
// term = "*%3A*";
|
||||
// }
|
||||
// console.log("ONSEARCH");
|
||||
|
||||
// Reset active filter categories and facet results
|
||||
this.activeFilterCategories = new ActiveFilterCategories();
|
||||
this.facets = new FacetResults();
|
||||
|
||||
// this.facets = {};
|
||||
this.searchTerm = suggestion;
|
||||
DatasetService.facetedSearch(suggestion, this.activeFilterCategories, this.solr.core, this.solr.host, undefined).subscribe({
|
||||
next: (res: SolrResponse) => this.dataHandler(res),
|
||||
// console.log("ONSEARCH > suggestion: ", suggestion);
|
||||
|
||||
// /* Perform faceted search. The method returns an Observable, and the code subscribes to this Observable to handle the response. If the response is successful, it calls the dataHandler method
|
||||
// with the Solr response as a parameter. If there is an error, it calls the errorHandler method with the error message as a parameter */
|
||||
// DatasetService.facetedSearch(suggestion, this.activeFilterCategories, this.solr.core, this.solr.host, undefined).subscribe({
|
||||
// next: (res: SolrResponse) => this.dataHandler(res),
|
||||
// error: (error: string) => this.errorHandler(error),
|
||||
// });
|
||||
|
||||
DatasetService.facetedSearchOPEN(suggestion, this.activeFilterCategories, this.open.core, this.open.host, undefined).subscribe({
|
||||
// next: (res: { datasets: Dataset[], highlights: HitHighlight[] }) => this.dataHandlerOpen(res.datasets, res.highlights),
|
||||
next: (res: OpenSearchResponse) => this.dataHandlerOPEN(res),
|
||||
error: (error: string) => this.errorHandler(error),
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private dataHandler(res: SolrResponse, filterItem?: FacetItem): void {
|
||||
// this.results = datasets;
|
||||
this.results = res.response.docs;
|
||||
this.numFound = res.response.numFound;
|
||||
// Handle the search results
|
||||
private dataHandlerOPEN(res: OpenSearchResponse, filterItem?: FacetItem): void {
|
||||
this.results = res.hits.hits.map(hit => hit._source);
|
||||
this.numFound = res.hits.total.value;
|
||||
|
||||
// pagination
|
||||
this.pagination["total"] = res.response.numFound;
|
||||
this.pagination["perPage"] = res.responseHeader.params.rows as number;
|
||||
// this.pagination["currentPage"] = 1;
|
||||
this.pagination["data"] = res.response.docs;
|
||||
this.pagination.lastPage = Math.ceil(this.pagination.total / this.pagination.perPage);
|
||||
// console.log("dataHandlerOPEN (results, numFound):");
|
||||
// console.log(this.results);
|
||||
// console.log(this.numFound);
|
||||
// console.log(res.hits.hits);
|
||||
// console.log(res.hits.total.value); console.log(res);
|
||||
// console.log("results:");
|
||||
console.log(res);
|
||||
|
||||
// facets
|
||||
// const facet_fields = res.facet_counts.facet_fields;
|
||||
// for (const prop in facet_fields) {
|
||||
// const facetCategory: FacetCategory<any> = facet_fields[prop];
|
||||
// const facetValues = facetCategory.key.values.map((facet_value: any, i: number) => {
|
||||
// if (i % 2 === 0 && typeof facet_value == "string") {
|
||||
// //var rObj = { value: facet, count: facet_fields[prop][i + 1] };
|
||||
// // FiletrItem with value and count
|
||||
// const rObj = new FilterItem(facet_value, facetCategory.key.values[i + 1]);
|
||||
// return rObj;
|
||||
// }
|
||||
// });
|
||||
// .filter(function (el: FilterItem) {
|
||||
// return el != null && el.count > 0;
|
||||
// });
|
||||
// //this.facets.push({ filterName: prop, values: facetValues });
|
||||
// this.facets[prop] = facetValues;
|
||||
// for (const key in this.results) {
|
||||
// if (Object.prototype.hasOwnProperty.call(this.results, key)) {
|
||||
// const element = this.results[key];
|
||||
// // console.log(element.abstract[0]);
|
||||
// // console.log(element.language);
|
||||
// console.log(element.server_date_published);
|
||||
// }
|
||||
// }
|
||||
|
||||
const facet_fields: FacetFields = res.facets;
|
||||
let prop: keyof typeof facet_fields;
|
||||
for (prop in facet_fields) {
|
||||
const facetCategory = facet_fields[prop];
|
||||
if (facetCategory.buckets) {
|
||||
const facetItems: Array<FacetItem> = facetCategory.buckets;
|
||||
this.pagination.total = res.hits.total.value;
|
||||
this.pagination.perPage = 10;
|
||||
this.pagination.data = this.results;
|
||||
this.pagination.lastPage = Math.ceil(this.pagination.total / this.pagination.perPage);
|
||||
|
||||
let facetValues = facetItems.map((facetItem) => {
|
||||
let rObj: FacetItem;
|
||||
if (filterItem?.val == facetItem.val) {
|
||||
rObj = filterItem;
|
||||
} else if (this.facets[prop]?.some((e) => e.val === facetItem.val)) {
|
||||
// console.log(facetValue + " is included")
|
||||
const indexOfFacetValue = this.facets[prop].findIndex((i) => i.val === facetItem.val);
|
||||
// console.log(indexOfFacetValue);
|
||||
rObj = this.facets[prop][indexOfFacetValue];
|
||||
rObj.count = facetItem.count;
|
||||
// rObj = new FacetItem(val, count);
|
||||
} else {
|
||||
rObj = new FacetItem(facetItem.val, facetItem.count);
|
||||
}
|
||||
return rObj;
|
||||
});
|
||||
// if (res.aggregations) {
|
||||
// const facet_fields = res.aggregations;
|
||||
|
||||
facetValues = facetValues.filter(function (el) {
|
||||
return el != null && el.count > 0;
|
||||
});
|
||||
// this.facets[prop] = facetCategory;
|
||||
this.facets[prop] = facetValues;
|
||||
// let prop: keyof typeof facet_fields;
|
||||
|
||||
// for (prop in facet_fields) {
|
||||
// const facetCategory = facet_fields[prop];
|
||||
// if (facetCategory.buckets) {
|
||||
// const facetItems = facetCategory.buckets.map(bucket => new FacetItem(bucket.key, bucket.doc_count));
|
||||
// this.facets[prop] = facetItems.filter(el => el.count > 0);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
if (res.aggregations) {
|
||||
const facet_fields = res.aggregations;
|
||||
|
||||
let prop: keyof typeof facet_fields;
|
||||
|
||||
// Iterate through facet fields
|
||||
for (prop in facet_fields) {
|
||||
const facetCategory = facet_fields[prop];
|
||||
if (facetCategory.buckets) {
|
||||
const facetItems = facetCategory.buckets.map(bucket => new FacetItem(bucket.key, bucket.doc_count));
|
||||
|
||||
let facetValues = facetItems.map((facetItem) => {
|
||||
let rObj: FacetItem;
|
||||
// Check if current facet item matches filter item
|
||||
if (filterItem?.val == facetItem.val) {
|
||||
rObj = filterItem;
|
||||
} else if (this.facets[prop]?.some((e) => e.val === facetItem.val)) {
|
||||
const indexOfFacetValue = this.facets[prop].findIndex((i) => i.val === facetItem.val);
|
||||
rObj = this.facets[prop][indexOfFacetValue];
|
||||
rObj.count = facetItem.count;
|
||||
} else {
|
||||
// Create new facet item
|
||||
rObj = new FacetItem(facetItem.val, facetItem.count);
|
||||
}
|
||||
return rObj;
|
||||
});
|
||||
|
||||
// Filter out null values and values with count <= 0
|
||||
facetValues = facetValues.filter(el => el.count > 0);
|
||||
this.facets[prop] = facetValues;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// // Method to handle search response
|
||||
// private dataHandler(res: SolrResponse, filterItem?: FacetItem): void {
|
||||
// // console.log("dataHandlerSOLR (docs, numFound):");
|
||||
// // console.log(res.response.docs);
|
||||
// // console.log(res.response.numFound);
|
||||
|
||||
// // Update results
|
||||
// this.results = res.response.docs;
|
||||
// this.numFound = res.response.numFound;
|
||||
|
||||
// // Update pagination
|
||||
// this.pagination["total"] = res.response.numFound;
|
||||
// this.pagination["perPage"] = res.responseHeader.params.rows as number;
|
||||
// this.pagination["data"] = res.response.docs;
|
||||
// this.pagination.lastPage = Math.ceil(this.pagination.total / this.pagination.perPage);
|
||||
|
||||
// const facet_fields: FacetFields = res.facets;
|
||||
|
||||
// /* This code declares a variable prop with a type of keys of the facet_fields object. The keyof typeof facet_fields type represents the keys of the facet_fields object.
|
||||
// This means that prop can only hold values that are keys of the facet_fields object. */
|
||||
// let prop: keyof typeof facet_fields;
|
||||
|
||||
// // Iterate through facet fields
|
||||
// for (prop in facet_fields) {
|
||||
// const facetCategory = facet_fields[prop];
|
||||
// if (facetCategory.buckets) {
|
||||
// const facetItems: Array<FacetItem> = facetCategory.buckets;
|
||||
|
||||
// let facetValues = facetItems.map((facetItem) => {
|
||||
// let rObj: FacetItem;
|
||||
// // Check if current facet item matches filter item
|
||||
// if (filterItem?.val == facetItem.val) {
|
||||
// rObj = filterItem;
|
||||
// } else if (this.facets[prop]?.some((e) => e.val === facetItem.val)) {
|
||||
// // console.log(facetValue + " is included")
|
||||
// // Update existing facet item with new count
|
||||
// const indexOfFacetValue = this.facets[prop].findIndex((i) => i.val === facetItem.val);
|
||||
// // console.log(indexOfFacetValue);
|
||||
// rObj = this.facets[prop][indexOfFacetValue];
|
||||
// rObj.count = facetItem.count;
|
||||
// // rObj = new FacetItem(val, count);
|
||||
// } else {
|
||||
// // Create new facet item
|
||||
// rObj = new FacetItem(facetItem.val, facetItem.count);
|
||||
// }
|
||||
// return rObj;
|
||||
// });
|
||||
|
||||
// // Filter out null values and values with count <= 0
|
||||
// facetValues = facetValues.filter(function (el) {
|
||||
// return el != null && el.count > 0;
|
||||
// });
|
||||
// // this.facets[prop] = facetCategory;
|
||||
// // Update facet values
|
||||
// this.facets[prop] = facetValues;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// Method to handle search errors
|
||||
private errorHandler(err: string): void {
|
||||
this.error = err;
|
||||
// this.loading = false;
|
||||
}
|
||||
|
||||
// Method to handle pagination
|
||||
onMenuClick(page: number) {
|
||||
// const test = page;
|
||||
// console.log(test);
|
||||
console.log("onMenuClick");
|
||||
|
||||
this.pagination.currentPage = page;
|
||||
const start = page * this.pagination.perPage - this.pagination.perPage;
|
||||
|
||||
DatasetService.facetedSearch(this.searchTerm, this.activeFilterCategories, this.solr.core, this.solr.host, start.toString()).subscribe(
|
||||
(res: SolrResponse) => this.dataHandler(res),
|
||||
(error: string) => this.errorHandler(error),
|
||||
);
|
||||
// // Trigger new search with updated pagination parameters
|
||||
// DatasetService.facetedSearch(this.searchTerm, this.activeFilterCategories, this.solr.core, this.solr.host, start.toString()).subscribe(
|
||||
// (res: SolrResponse) => this.dataHandler(res),
|
||||
// (error: string) => this.errorHandler(error),
|
||||
// );
|
||||
|
||||
DatasetService.facetedSearchOPEN(this.searchTerm, this.activeFilterCategories, this.open.core, this.open.host, start.toString()).subscribe({
|
||||
next: (res: OpenSearchResponse) => this.dataHandlerOPEN(res),
|
||||
error: (error: string) => this.errorHandler(error),
|
||||
});
|
||||
}
|
||||
|
||||
// Method to handle facet filtering
|
||||
onFilter(facetItem: FacetItem): void {
|
||||
console.log("onFilter");
|
||||
|
||||
// Reset current page
|
||||
this.pagination.currentPage = 1;
|
||||
// console.log(facetItem.val);
|
||||
// console.log(facetItem.category);
|
||||
|
||||
// if (!this.activeFilterCategories.hasOwnProperty(facetItem.category)) {
|
||||
|
||||
// Check if filter item already exists
|
||||
if (!Object.prototype.hasOwnProperty.call(this.activeFilterCategories, facetItem.category)) {
|
||||
this.activeFilterCategories[facetItem.category] = new Array<string>();
|
||||
// console.log(this.activeFilterCategories);
|
||||
}
|
||||
// if (!this.activeFilterCategories[facetItem.category].some((e) => e === facetItem.val)) {
|
||||
|
||||
// Check if filter item is not already applied
|
||||
if (!this.activeFilterCategories[facetItem.category].some((e) => e === facetItem.val)) {
|
||||
// Add filter item to active filter categories
|
||||
this.activeFilterCategories[facetItem.category].push(facetItem.val);
|
||||
|
||||
DatasetService.facetedSearch(this.searchTerm, this.activeFilterCategories, this.solr.core, this.solr.host, undefined).subscribe(
|
||||
(res: SolrResponse) => this.dataHandler(res, facetItem),
|
||||
(error: string) => this.errorHandler(error),
|
||||
);
|
||||
// alert(this.activeFilterCategories[filter.Category]);
|
||||
// var res = await rdrApi.search(this.searchTerm, this.activeFilterCategories, this.solrCore, this.solrHost);
|
||||
// this.results = res.response.docs;
|
||||
// this.numFound = res.response.numFound;
|
||||
|
||||
// // pagination
|
||||
// this.pagination['total'] = res.response.numFound;
|
||||
// this.pagination['per_page'] = res.responseHeader.params.rows;
|
||||
// this.pagination['current_page'] = 1;
|
||||
// this.pagination['data'] = res.response.docs;
|
||||
|
||||
// var facet_fields = res.facet_counts.facet_fields;
|
||||
// for (var prop in facet_fields) {
|
||||
// var facetValues = facet_fields[prop].map((facetValue, i) => {
|
||||
// if (i % 2 === 0) {
|
||||
// // var rObj = { value: facetValue, count: facet_fields[prop][i + 1] };
|
||||
// var rObj;
|
||||
// if (filter.value == facetValue) {
|
||||
// rObj = filter;
|
||||
// } else if (this.facets[prop].some(e => e.value === facetValue)) {
|
||||
// // console.log(facetValue + " is included")
|
||||
// var indexOfFacetValue = this.facets[prop].findIndex(i => i.value === facetValue);
|
||||
// // console.log(indexOfFacetValue);
|
||||
// rObj = this.facets[prop][indexOfFacetValue];
|
||||
// rObj.count = facet_fields[prop][i + 1];
|
||||
// } else {
|
||||
// rObj = new FilterItem(facetValue, facet_fields[prop][i + 1]);
|
||||
// }
|
||||
// return rObj;
|
||||
// }
|
||||
// }).filter(function (el) {
|
||||
// return el != null && el.count > 0;
|
||||
// });
|
||||
// // this.facets.push({ filterName: prop, values: facetValues });
|
||||
// this.facets[prop] = facetValues;
|
||||
// Trigger new search with updated filter
|
||||
// DatasetService.facetedSearch(this.searchTerm, this.activeFilterCategories, this.solr.core, this.solr.host, undefined).subscribe(
|
||||
// (res: SolrResponse) => this.dataHandler(res, facetItem),
|
||||
// (error: string) => this.errorHandler(error),
|
||||
// );
|
||||
// console.log(this.activeFilterCategories);
|
||||
DatasetService.facetedSearchOPEN(this.searchTerm, this.activeFilterCategories, this.open.core, this.open.host, undefined).subscribe({
|
||||
next: (res: OpenSearchResponse) => this.dataHandlerOPEN(res, facetItem),
|
||||
error: (error: string) => this.errorHandler(error),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
onClearFacetCategory(categoryName: string): void {
|
||||
// alert(categoryName);
|
||||
// // // Method to clear facet category filter
|
||||
// onClearFacetCategory(categoryName: string): void {
|
||||
// console.log("onClearFacetCategory");
|
||||
|
||||
// delete this.activeFilterCategories[categoryName];
|
||||
|
||||
// // Trigger new search with updated filter
|
||||
// DatasetService.facetedSearch(this.searchTerm, this.activeFilterCategories, this.solr.core, this.solr.host, undefined).subscribe({
|
||||
// next: (res: SolrResponse) => {
|
||||
// this.results = res.response.docs;
|
||||
// this.numFound = res.response.numFound;
|
||||
|
||||
// // pagination
|
||||
// this.pagination["total"] = res.response.numFound;
|
||||
// this.pagination["perPage"] = res.responseHeader.params.rows as number;
|
||||
// this.pagination["currentPage"] = 1;
|
||||
// this.pagination["data"] = res.response.docs;
|
||||
|
||||
// const facet_fields: FacetFields = res.facets;
|
||||
// let prop: keyof typeof facet_fields;
|
||||
// for (prop in facet_fields) {
|
||||
// const facetCategory: FacetInstance = facet_fields[prop];
|
||||
// if (facetCategory.buckets) {
|
||||
// const facetItems: Array<FacetItem> = facetCategory.buckets;
|
||||
|
||||
// const facetValues = facetItems.map((facetItem) => {
|
||||
// let rObj: FacetItem;
|
||||
// if (this.facets[prop]?.some((e) => e.val === facetItem.val)) {
|
||||
// // console.log(facetValue + " is included")
|
||||
// // Update existing facet item with new count
|
||||
// const indexOfFacetValue = this.facets[prop].findIndex((i) => i.val === facetItem.val);
|
||||
// // console.log(indexOfFacetValue);
|
||||
// rObj = this.facets[prop][indexOfFacetValue];
|
||||
// rObj.count = facetItem.count;
|
||||
// // rObj = new FacetItem(val, count);
|
||||
// // if facet ccategory is reactivated category, deactivate all filter items
|
||||
// if (prop == categoryName) {
|
||||
// rObj.active = false;
|
||||
// }
|
||||
// } else {
|
||||
// // Create new facet item
|
||||
// rObj = new FacetItem(facetItem.val, facetItem.count);
|
||||
// }
|
||||
// return rObj;
|
||||
// });
|
||||
// this.facets[prop] = facetValues;
|
||||
// }
|
||||
// }
|
||||
// },
|
||||
// error: (error: string) => this.errorHandler(error),
|
||||
// complete: () => console.log("clear facet category completed"),
|
||||
// });
|
||||
// }
|
||||
|
||||
// Method to clear facet category filter
|
||||
onClearFacetCategoryOPEN(categoryName: string): void {
|
||||
// console.log("onClearFacetCategory");
|
||||
delete this.activeFilterCategories[categoryName];
|
||||
|
||||
DatasetService.facetedSearch(this.searchTerm, this.activeFilterCategories, this.solr.core, this.solr.host, undefined).subscribe({
|
||||
next: (res: SolrResponse) => {
|
||||
this.results = res.response.docs;
|
||||
this.numFound = res.response.numFound;
|
||||
// Trigger new search with updated filter
|
||||
DatasetService.facetedSearchOPEN(this.searchTerm, this.activeFilterCategories, this.open.core, this.open.host, undefined).subscribe({
|
||||
next: (res: OpenSearchResponse) => {
|
||||
this.results = res.hits.hits.map(hit => hit._source);
|
||||
this.numFound = res.hits.total.value;
|
||||
|
||||
// pagination
|
||||
this.pagination["total"] = res.response.numFound;
|
||||
this.pagination["perPage"] = res.responseHeader.params.rows as number;
|
||||
this.pagination["currentPage"] = 1;
|
||||
this.pagination["data"] = res.response.docs;
|
||||
// Update pagination
|
||||
this.pagination.total = res.hits.total.value;
|
||||
this.pagination.perPage = 10;
|
||||
this.pagination.currentPage = 1;
|
||||
this.pagination.data = this.results;
|
||||
this.pagination.lastPage = Math.ceil(this.pagination.total / this.pagination.perPage);
|
||||
|
||||
const facet_fields: FacetFields = res.facets;
|
||||
let prop: keyof typeof facet_fields;
|
||||
for (prop in facet_fields) {
|
||||
const facetCategory: FacetInstance = facet_fields[prop];
|
||||
if (facetCategory.buckets) {
|
||||
const facetItems: Array<FacetItem> = facetCategory.buckets;
|
||||
if (res.aggregations) {
|
||||
const facet_fields = res.aggregations;
|
||||
|
||||
const facetValues = facetItems.map((facetItem) => {
|
||||
let rObj: FacetItem;
|
||||
if (this.facets[prop]?.some((e) => e.val === facetItem.val)) {
|
||||
// console.log(facetValue + " is included")
|
||||
const indexOfFacetValue = this.facets[prop].findIndex((i) => i.val === facetItem.val);
|
||||
// console.log(indexOfFacetValue);
|
||||
rObj = this.facets[prop][indexOfFacetValue];
|
||||
rObj.count = facetItem.count;
|
||||
// rObj = new FacetItem(val, count);
|
||||
//if facet ccategory is reactivated category, deactivate all filter items
|
||||
if (prop == categoryName) {
|
||||
rObj.active = false;
|
||||
let prop: keyof typeof facet_fields;
|
||||
|
||||
for (prop in facet_fields) {
|
||||
const facetCategory = facet_fields[prop];
|
||||
if (facetCategory.buckets) {
|
||||
const facetItems = facetCategory.buckets.map(bucket => new FacetItem(bucket.key, bucket.doc_count));
|
||||
|
||||
const facetValues = facetItems.map((facetItem) => {
|
||||
let rObj: FacetItem;
|
||||
if (this.facets[prop]?.some((e) => e.val === facetItem.val)) {
|
||||
// Update existing facet item with new count
|
||||
const indexOfFacetValue = this.facets[prop].findIndex((i) => i.val === facetItem.val);
|
||||
rObj = this.facets[prop][indexOfFacetValue];
|
||||
rObj.count = facetItem.count;
|
||||
// if facet category is reactivated category, deactivate all filter items
|
||||
if (prop === categoryName) {
|
||||
rObj.active = false;
|
||||
}
|
||||
} else {
|
||||
// Create new facet item
|
||||
rObj = new FacetItem(facetItem.val, facetItem.count);
|
||||
}
|
||||
} else {
|
||||
rObj = new FacetItem(facetItem.val, facetItem.count);
|
||||
}
|
||||
return rObj;
|
||||
});
|
||||
this.facets[prop] = facetValues;
|
||||
return rObj;
|
||||
}).filter(el => el.count > 0); // Filter out items with count <= 0
|
||||
|
||||
this.facets[prop] = facetValues;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -311,5 +452,4 @@ export default class SearchViewComponent extends Vue {
|
|||
});
|
||||
}
|
||||
|
||||
// onPaging(page: number): void {}
|
||||
}
|
||||
|
|
|
@ -1,31 +1,11 @@
|
|||
<template>
|
||||
<div id="page_style" class="rows site-content page__style page__description" autocomplete="off">
|
||||
|
||||
<div class="container-fluid banner mz-5">
|
||||
<vs-input v-bind:propDisplay="searchTerm" v-bind:placeholder="'Enter your search term...'" @search-change="onSearch"></vs-input>
|
||||
</div>
|
||||
|
||||
<div class="column is-half is-offset-one-quarter" style="padding-top: 0; margin-top: 0">
|
||||
<!-- <div class="tabs is-centered">
|
||||
<ul id="id-results-tabs">
|
||||
<li class="search_tab is-active">
|
||||
<a target="_self">Web</a>
|
||||
</li>
|
||||
<li class="search_tab">
|
||||
<a target="_self">Images</a>
|
||||
</li>
|
||||
<li class="search_tab">
|
||||
<a target="_self">Videos</a>
|
||||
</li>
|
||||
<li class="search_tab">
|
||||
<a target="_self">Homepages</a>
|
||||
</li>
|
||||
<li class="search_tab">
|
||||
<a target="_self">Food</a>
|
||||
</li>
|
||||
<li class="search_tab">
|
||||
<a target="_self">Books</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div> -->
|
||||
<div v-if="results.length > 0" class="result-list-info">
|
||||
<div v-if="hasSearchTerm()" class="resultheader">
|
||||
Your search term {{ "'" + stringSearchTerm + "'" }} yielded <strong>{{ numFound }}</strong> results:
|
||||
|
@ -54,7 +34,7 @@
|
|||
<active-facet-category
|
||||
v-bind:filterItems="values"
|
||||
v-bind:categoryName="key"
|
||||
@clear-facet-category="onClearFacetCategory"
|
||||
@clear-facet-category="onClearFacetCategoryOPEN"
|
||||
></active-facet-category>
|
||||
</span>
|
||||
</div>
|
||||
|
|
|
@ -89,8 +89,11 @@ module.exports = {
|
|||
__VUE_PROD_HYDRATION_MISMATCH_DETAILS__: "false",
|
||||
APP_URL: JSON.stringify(process.env.APP_URL),
|
||||
VUE_API: JSON.stringify(process.env.VUE_API),
|
||||
SOLR_HOST: JSON.stringify(process.env.SOLR_HOST),
|
||||
SOLR_CORE: JSON.stringify(process.env.SOLR_CORE),
|
||||
// SOLR_HOST: JSON.stringify(process.env.SOLR_HOST),
|
||||
// SOLR_CORE: JSON.stringify(process.env.SOLR_CORE),
|
||||
// OPENSEARCH
|
||||
OPEN_HOST: JSON.stringify(process.env.OPEN_HOST),
|
||||
OPEN_CORE: JSON.stringify(process.env.OPEN_CORE),
|
||||
}),
|
||||
// new NodePolyfillPlugin(),
|
||||
],
|
||||
|
|
Loading…
Reference in New Issue
Block a user