- Code cleaning for OpenSearch

- Added comments
- Facets menu small change
This commit is contained in:
Porras-Bernardez 2024-09-12 15:54:59 +02:00
parent 50ab318854
commit 6f1b9f4c5f
5 changed files with 264 additions and 389 deletions

View File

@ -76,7 +76,10 @@ export default FacetCategory;
flex-grow: 1;
flex-shrink: 0;
/* padding: 0.75rem; */
padding: 0.75em 2em;
padding-top: 0em;
padding-right: 2em;
padding-bottom: 0.75em;
padding-left: 2em;
justify-content: left;
}
@ -89,6 +92,7 @@ export default FacetCategory;
}
.panel-body {
padding: 0 2em;
padding-bottom: 0.75em; /* Increase padding at the bottom */
}
.disabled {

View File

@ -0,0 +1,161 @@
// 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;
// }

View File

@ -1,5 +1,4 @@
import api from "../api/api";
// import { Observable, of } from "rxjs";
import { Observable } from "rxjs";
import { tap, map } from "rxjs/operators";
import { Dataset, DbDataset, Suggestion } from "@/models/dataset";
@ -10,33 +9,23 @@ import { deserialize } from "class-transformer";
class DatasetService {
/**
* 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.
* Search datasets with OpenSearch API, allowing for fuzzy search and boosting relevance in title, author, and subject fields.
* @param {string} searchTerm - Search query term
* @param {string} openCore - The OpenSearch core to search in
* @param {string} openHost - The OpenSearch host URL
* @returns {Observable} - Observable emitting datasets and their highlights
*/
/* 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[] }> {
// console.log("SEARCHTERM");
// OpenSearch endpoint
const host = openHost; // When using local OpenSearch dev endpoint
const path = "/" + openCore + "/_search";
const base = host + path;
const host = openHost; // OpenSearch host URL
const path = "/" + openCore + "/_search"; // API endpoint for searching
const base = host + path; // Complete URL for the request
/**
* 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
// Request body defining search query logic
const body = {
query: {
bool: {
@ -50,13 +39,13 @@ class DatasetService {
{ wildcard: { subjects: { value: `${lowercaseTerm}*`, boost: 1 } } }, // In SOLR is "subject"!
{ wildcard: { doctype: { value: `${lowercaseTerm}*`, boost: 1 } } } // doctype
],
minimum_should_match: 1
minimum_should_match: 1 // Require at least one match
}
},
size: 10,
from: 0,
size: 10, // Limit to 10 results
from: 0, // Pagination: start from the first result
sort: [{ _score: { order: "desc" } }], // Sort by relevance (_score)
// 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"!
@ -65,37 +54,23 @@ class DatasetService {
year: { terms: { field: "year", size: 100 } }, // << ".keyword" HAS TO BE REMOVED. OTHERWISE BUCKETS ARE NOT OBTAINED FOR THIS
doctype: { terms: { field: "doctype", size: 50 } } // << ".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: {},
doctype: {}
title: {}, // Highlight matching terms in title
author: {}, // Highlight matching terms in author
subjects: {}, // Highlight matching terms in subjects
doctype: {} // Highlight matching terms in document type
}
}
};
// Make API call to OpenSearch and return the result
/**
* 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
// 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)
@ -104,7 +79,7 @@ class DatasetService {
}
// // For the autocomplete search. Method to perform a search based on a term
// public searchTerm_SOLR(term: string, solrCore: string, solrHost: string): Observable<Dataset[]> {
// public searchTermSOLR(term: string, solrCore: string, solrHost: string): Observable<Dataset[]> {
// // SOLR endpoint
// const host = "https://" + solrHost;
// const path = "/solr/" + solrCore + "/select?";
@ -123,7 +98,6 @@ class DatasetService {
// "doctype",
// ].toString();
// const qfFields = "title^3 author^2 subject^1";
// const q_params = {
@ -146,193 +120,33 @@ class DatasetService {
// 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(
/**
* Perform faceted search with OpenSearch API using filters and suggestions
* @param {Suggestion | string} suggestion - Search term or suggestion
* @param {ActiveFilterCategories} activeFilterCategories - Active filters to apply
* @param {string} openCore - The OpenSearch core to search in
* @param {string} openHost - The OpenSearch host URL
* @param {string} start - Optional: starting page
* @returns {Observable<OpenSearchResponse>} - Observable emitting search results
*/
public facetedSearch(
suggestion: Suggestion | string,
activeFilterCategories: ActiveFilterCategories,
openCore: string,
openHost: string,
start?: string, // Starting page
): Observable<OpenSearchResponse> {
// console.log("FACETEDSEARCH");
// OpenSearch endpoint
const host = openHost;
const path = "/" + openCore + "/_search";
const base = host + path;
const lowercaseTerm = typeof suggestion === 'string' ? suggestion.toLowerCase() : suggestion.value;
// console.log("facetedsearchOPEN > suggestion entered:");
// console.log(suggestion);
// console.log("typeof:", typeof suggestion);
/**
* The query construction depends on whether the suggestion is a string or a Suggestion object. */
* 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'
? {
@ -350,7 +164,7 @@ class DatasetService {
minimum_should_match: 1
}
}
// When suggestion is a suggestion object
// When suggestion is a suggestion object:
: {
match: {
[suggestion.type]: {
@ -360,28 +174,7 @@ class DatasetService {
}
};
// CONTABO ====================================================
// // Constructing Filters Based on Active Filter Categories
// const filters = Object.entries(activeFilterCategories).map(([category, values]) => ({
// terms: { [`${category}.keyword`]: values }
// }));
// ================================================================
// // 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();
// Build filters based on the active filter categories
const filters = Object.entries(activeFilterCategories).map(([category, values]) => {
if (category === "language" || category === "year" || category === "doctype") {
return values.map(value => ({ term: { [category]: value } }));
@ -390,22 +183,8 @@ class DatasetService {
}
}).flat();
// console.log(activeFilterCategories);
console.log("mainQuery:", mainQuery);
console.log("filters:", filters);
// Request body for the faceted search
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: [
@ -415,49 +194,24 @@ class DatasetService {
}
},
// // 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: [{ _source: { server_date_published: { order: "desc" } } }],
sort: [{ server_date_published: { order: "desc" } }],
sort: [{ server_date_published: { order: "desc" } }], // Sort by publication date
// sort: [{ _score: { order: "desc" } }], // Sort by _score in descending order
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.
/**
* 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.
*/
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
doctype: { terms: { field: "doctype", size: 50 } } // ".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: {},
@ -468,17 +222,15 @@ class DatasetService {
}
};
// console.log("body:", body);
// API call and return observable of search results
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(
// public facetedSearchSOLR(
// suggestion: Suggestion | string,
// activeFilterCategories: ActiveFilterCategories,
// solrCore: string,
@ -609,8 +361,8 @@ class DatasetService {
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)));
return dataset;
}
@ -619,16 +371,16 @@ class DatasetService {
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)));
return dataset;
}
// Method to prepare dataset object
// Prepare dataset object by deserializing it and adding a URL
private prepareDataset(datasetObj: DbDataset): DbDataset {
const dataset = deserialize<DbDataset>(DbDataset, JSON.stringify(datasetObj));
dataset.url = document.documentURI;
return dataset;
}
}

View File

@ -1,17 +1,18 @@
// Import necessary modules, components, and models from Vue and the project
import { Component, Vue, Prop } from "vue-facing-decorator";
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 models and services
// 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, OpenSearchResponse, HitHighlight } from "@/models/headers";
import { FacetFields, FacetItem, FacetResults, FacetInstance, OpenSearchResponse, HitHighlight } from "@/models/headers";
import { FacetItem, FacetResults, OpenSearchResponse } from "@/models/headers";
import { ActiveFilterCategories } from "@/models/solr";
// import { SOLR_HOST, SOLR_CORE } from "@/constants";
import { IPagination } from "@/models/pagination";
@ -19,7 +20,7 @@ import PaginationComponent from "@/components/PaginationComponent.vue";
import { OPEN_HOST, OPEN_CORE } from "@/constants";
// Decorate the component and define its name and components
// Define the Vue component, its name, and child components
@Component({
name: "SearchViewComponent",
components: {
@ -31,51 +32,51 @@ import { OPEN_HOST, OPEN_CORE } from "@/constants";
},
})
// Define the SearchViewComponent class
// Export the default class for the component
export default class SearchViewComponent extends Vue {
// Define props passed from the parent component
@Prop()
display!: string;
display!: string; // Search display string
@Prop()
type!: string;
type!: string; // Search type
results: Array<Dataset> = [];
// facets: FacetFields = new FacetFields();
facets: FacetResults = new FacetResults();
searchTerm: string | Suggestion = "";
// activeFilterCategories: Object = {};
activeFilterCategories: ActiveFilterCategories = new ActiveFilterCategories(); // = new Array<ActiveFilterCategory>();
pagination: IPagination = {
// Declare variables used in the component
results: Array<Dataset> = []; // Array to hold search results
facets: FacetResults = new FacetResults(); // Object to hold facet results
searchTerm: string | Suggestion = ""; // The search term input
activeFilterCategories: ActiveFilterCategories = new ActiveFilterCategories(); // Active filter categories for search
pagination: IPagination = { // Pagination data for the results
total: 0,
perPage: 10,
currentPage: 1,
// lastPage: 0,
data: [],
};
loaded = false;
numFound!: number;
loaded = false; // Boolean to track whether data has been loaded
numFound!: number; // Number of results found
// private solr: SolrSettings = {
// core: SOLR_CORE, //"rdr_data", // SOLR.core;
// host: SOLR_HOST, //"tethys.at",
// };
// Define settings for the OpenSearch API (core and host information)
private open: OpenSettings = {
core: OPEN_CORE, //"rdr_data", // SOLR.core;
host: OPEN_HOST, //"tethys.at",
core: OPEN_CORE, //
host: OPEN_HOST, //
};
private error = "";
// Computed property to get search term as string
get stringSearchTerm(): string {
// console.log("stringSearchTerm:", this.searchTerm);
// If searchTerm is a string, return it directly
if (typeof this.searchTerm === "string") {
return this.searchTerm;
// If searchTerm is a Suggestion, return its value and type alias
} else if (this.searchTerm instanceof Suggestion) {
return this.searchTerm.value + " (" + this.getTypeAlias(this.searchTerm.type) + ")";
// return this.searchTerm.value + " (" + this.searchTerm.type + ")";
// Default to empty string
} else {
return "";
}
@ -109,9 +110,6 @@ export default class SearchViewComponent extends Vue {
return false;
}
}
// 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 {
@ -124,7 +122,6 @@ export default class SearchViewComponent extends Vue {
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" | "Doctype" | null = this.getEnumKeyByEnumValue(SearchType, this.type);
@ -150,64 +147,30 @@ export default class SearchViewComponent extends Vue {
this.activeFilterCategories = new ActiveFilterCategories();
this.facets = new FacetResults();
this.searchTerm = suggestion;
// 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({
// DatasetService.facetedSearchSOLR(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),
DatasetService.facetedSearch(suggestion, this.activeFilterCategories, this.open.core, this.open.host, undefined).subscribe({
next: (res: OpenSearchResponse) => this.dataHandler(res),
error: (error: string) => this.errorHandler(error),
});
}
// Handle the search results
private dataHandlerOPEN(res: OpenSearchResponse, filterItem?: FacetItem): void {
private dataHandler(res: OpenSearchResponse, filterItem?: FacetItem): void {
this.results = res.hits.hits.map(hit => hit._source);
this.numFound = res.hits.total.value;
// 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);
// 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);
// }
// }
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);
// if (res.aggregations) {
// const facet_fields = res.aggregations;
// 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;
@ -244,7 +207,7 @@ export default class SearchViewComponent extends Vue {
}
// // Method to handle search response
// private dataHandler(res: SolrResponse, filterItem?: FacetItem): void {
// private dataHandlerSOLR(res: SolrResponse, filterItem?: FacetItem): void {
// // console.log("dataHandlerSOLR (docs, numFound):");
// // console.log(res.response.docs);
// // console.log(res.response.numFound);
@ -315,13 +278,13 @@ export default class SearchViewComponent extends Vue {
const start = page * this.pagination.perPage - this.pagination.perPage;
// // Trigger new search with updated pagination parameters
// DatasetService.facetedSearch(this.searchTerm, this.activeFilterCategories, this.solr.core, this.solr.host, start.toString()).subscribe(
// DatasetService.facetedSearchSOLR(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),
DatasetService.facetedSearch(this.searchTerm, this.activeFilterCategories, this.open.core, this.open.host, start.toString()).subscribe({
next: (res: OpenSearchResponse) => this.dataHandler(res),
error: (error: string) => this.errorHandler(error),
});
}
@ -332,37 +295,32 @@ export default class SearchViewComponent extends Vue {
// 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);
// Trigger new search with updated filter
// DatasetService.facetedSearch(this.searchTerm, this.activeFilterCategories, this.solr.core, this.solr.host, undefined).subscribe(
// DatasetService.facetedSearchSOLR(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),
// Trigger new search with updated filter
DatasetService.facetedSearch(this.searchTerm, this.activeFilterCategories, this.open.core, this.open.host, undefined).subscribe({
next: (res: OpenSearchResponse) => this.dataHandler(res, facetItem),
error: (error: string) => this.errorHandler(error),
});
}
}
// // // Method to clear facet category filter
// onClearFacetCategory(categoryName: string): void {
// onClearFacetCategorySOLR(categoryName: string): void {
// console.log("onClearFacetCategory");
// delete this.activeFilterCategories[categoryName];
@ -416,12 +374,12 @@ export default class SearchViewComponent extends Vue {
// }
// Method to clear facet category filter
onClearFacetCategoryOPEN(categoryName: string): void {
console.log("onClearFacetCategory");
onClearFacetCategory(categoryName: string): void {
// console.log("onClearFacetCategory");
delete this.activeFilterCategories[categoryName];
// Trigger new search with updated filter
DatasetService.facetedSearchOPEN(this.searchTerm, this.activeFilterCategories, this.open.core, this.open.host, undefined).subscribe({
DatasetService.facetedSearch(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;

View File

@ -105,7 +105,7 @@
<active-facet-category
v-bind:filterItems="values"
v-bind:categoryName="key"
@clear-facet-category="onClearFacetCategoryOPEN"
@clear-facet-category="onClearFacetCategory"
></active-facet-category>
</span>
</div>