JHipster - Elasticsearch examples for search field - elasticsearch

Having an example entity like
entity Vehicle {
id Long,
manufacturer String,
model String
}
and using ElasticSearch, how do queries in the search input field have to look like in the front end provided by the JHipster application?
A search might involve only one column or a combination of the given columns.
Let's say:
id = 1
manufacturer = Ferrari
manufacturer = Ferrari AND model = Model 1
or involving other query keywords like LIKE, etc.
How to specify those queries into the search input field?

Related

how to get Unique records from elastic search engine based on a field

I have an elastic search index that stores the list of restaurants in an area. I'm using spring elastic search to query the restaurant based on a given geo-location (lat/long) within 10 miles distance. I have a requirement where I only need to show a restaurant chain once, I'm seeing multiple records in my search result for the restaurant chains because they have the same name but different addresses. I only need to show the nearest restaurant chain restaurant along with the other unique restaurants. Is there a single query that can do that? Below is my code [removed some stuff for brevity!]
public SearchHits<Results> search(List<String> items){
final NativeSearchQueryBuilder searchQuery = new NativeSearchQueryBuilder();
BoolQueryBuilder termsQuery = boolQuery();
termsQuery.should(termsQuery(entry.getKey(), items));
boolQuery.must(termsQuery);
// ...I do additional logic here
searchQuery.withQuery(boolQuery);
// apply the terms aggregation searchQuery.addAggregation(terms(CATEGORIES_KEY).field(CATEGORY).size(BUCKET_SIZE));
Query query = searchQuery.build();
SearchHits<Results> searchHits = elasticsearcTemplate.search(query, Results.class);
return searchHits;
}
I was going thru the documentation of elasticsearch, it turns out...there is a simple fix for that :) I can use Collapse The collapse feature removes the duplicate data based on a field. So I only needed to add this line:
searchQuery.withCollapseField("restaurant_name");
// restaurant_name is what I want unique values on

Is there a way to compare each item to a aggreated value?

I'm new to graphQL and Hasura. I'm trying(in Hasura) to let me users provide custom aggregation (ideally in the form of a normal graphQL query) and have then each item the results compared against the aggreation.
Here's a example. Assume I have this schema:
USERTABLE:
userID
Name
Age
City
Country
Gender
HairColor
INCOMETABLE:
userID
Income
I created a relationship in hasura and I can query the data but my users want to do custom scoring of users' income level. For example, one user may want to query the data broken down by country and gender.
For the first example the result maybe:
{Country : Canada
{ gender : female
{ userID: 1,
Name: Nancy Smith,..
#data below is on aggregated results
rank: 1
%fromAverage: 35%
}...
Where I'm struggling is the data showing the users info relative to the aggregated data.
for Rank, I get the order by sorting but I'm not sure how to display the relative ranking and for the %fromAverage, I'm not sure how to do it at all.
Is there a way to do this in Hasura? I suspected that actions might be able to do this but I'm not sure.
You can use track a Postgres view. Your view would have as many fields as you'd like calculated in SQL and tracked as a separate "table" on your graphql api.
I am giving examples below based on a simplification where you have just table called contacts with just a single field called: id which is an auto-integer. I am just adding the id of the current contact to the avg(id) (a useless endeavor to be sure; just to illustrate...). Obviously you can customize the logic to your liking.
A simple implementation of a view would look like this (make sure to hit 'track this' in hasura:
CREATE OR REPLACE VIEW contact_with_custom AS
SELECT id, (SELECT AVG(ID) FROM contacts) + id as custom FROM contacts;
See Extend with views
Another option is to use a computed field. This is just a postgres function that takes a row as an argument and returns some data and it just adds a new field to your existing 'table' in the Graphql API that is the return value of said function. (you don't 'track this' function; once created in the SQL section of Hasura, you add it as a 'computed field' under 'Modify' for the relevant table) Important to note that this option does not allow you to filter by this computed function, whereas in a view, all fields are filterable.
In the same schema mentioned above, a function for a computed field would look like this:
CREATE OR REPLACE FUNCTION custom(contact contacts)
RETURNS Numeric AS $$
SELECT (SELECT AVG(ID) from contacts ) + contact.id
$$ LANGUAGE sql STABLE;
Then you select this function for your computed field, naming it whatever you'd like...
See Computed fields

Elastic Search multi match

I'm new to ElasticSearch. Now I have a requirement that need to return all result which contains the keyword.
public Class People(){
public string UserId {get; set;}
public string FirstName {get; set;}
public string LastName {get; set;}
}
I want to filter all People if one of three fileds contains the keyword, similar to like "%keyword%".
For example,I have a People
var people = new People() {
UserId = "lastname.middlename.firstname",
FirstName = "firstname",
LastName = "lastname"
}
How I could get this Peoplle by searching the keyword ddl, How to setup the index and how to query.
I have tried to query with NEST like below
var keyword = "ddl"
var result = await _client.SearchAsync<People>(s =>
s.Query(q => q.MultiMatch(m => m.Fields(f => f.Field(ff => ff.UserId).Field(ff => ff.FirstName).Field(ff => ff.LastName)).Query(keyword)))
);
It won't work. It only work when I changed the keyword to firstname or lastname or lastname.middlename.firstname
Is there any way to meet the requirement?
The short answer is that you would want to configure an analyzer for each of the target fields that tokenizes terms into trigrams, probably using the ngram token filter with min_gram and max_gram set to 3. This analysis will generate a ddl token for middlename that would then match your query.
The longer answer is that you'll want to have a read about Analysis, and how to write and test analyzers with the .NET client. You may want to go through the example repository that builds a Nuget search application. It's a fairly involved walkthrough that goes through a number of concepts, including analysis.
To search on parts of your fields, you should use an ngram tokenizer in your mapping.
It will tokenize your fields using windows of different size.
This should solve your problem, but you need to take care of several points :
It is likely that you will want to use this analyzer only at index time. Using this tokenizer both at indexation and search is likely to generate a LOT of irrelevant results.
Use a minimum window size (min_gram parameter) not to low. In your case 3 will work.
The size of your index can substantially grow.
Another solution, simpler to implement but usually not efficient is to use wildcards queries in query string. It is very similar to the LIKE operator in SQL.

Query by Example Spring Data

I have domain object Person with date fields:
public class Person {
#Id
private Long id;
private Date date
Build example like this:
Person person = new Person();
person.setSomeOtherFields("some fields");
Example<Person> example = Example.of(person);
How i can create example query with date range (search entity contains date greater or equal from some date and less or equal some another date)?
The Spring Data JPA query-by-example technique uses Examples and ExampleMatchers to convert entity instances into the underlying query. The current official documentation clarifies that only exact matching is available for non-string attributes. Since your requirement involves a java.util.Date field, you can only have exact matching with the query-by-example technique.
You could write your own ExampleMatcher that returns query clauses according to your needs.

Extbase Mapping with non-TYPO3-table

I have too classes and two non-TYPO3-tables. I defined a non-TYPO3-table as a table without uid, pid, etc. columns.
My two classes:
class Tx_Abc_Domain_Model_Location extends Tx_Extbase_DomainObject_AbstractEntity
class Tx_Abc_Domain_Model_Facility extends Tx_Extbase_DomainObject_AbstractEntity
My two tables (with columns):
locations
zipcode
city
facility_id
facilities
facility_id
name
I've mapped the attributes like this:
config.tx_extbase.persistence.classes {
Tx_Abc_Domain_Model_Location.mapping {
tableName = locations
columns {
zipcode.mapOnProperty = zipcode
city.mapOnProperty = city
facility_id.mapOnProperty = facility
}
}
Tx_Abc_Domain_Model_Facility.mapping {
tableName = facilities
columns {
facility_id.mapOnProperty = uid
name.mapOnProperty = name
}
}
}
My problem:
The facility attribute of my location model got the type Tx_Abc_Domain_Model_Facility and when I'm looking for a location via the LocationRepository it builds me a location model which contains a facility model.
The problem appears, when I the search I am doing returns several results. i.e. the location with the zipcode 12345 has two different facilities (and the table locations got two rows with different facility_ids), then I would expect to get two location models and each of it got the right facility model.
But instead I get the two location models, which have all same facility model inside. They've got all the facility of the first found location.
Even if I change the type of the facility attribute to integer, there are the wrong ids. But if I enable raw query result in repository I get the correct ids.
I get also the correct ids or models, when I add to both tables an uid-column.
Is there no possibility to map tables without uid column with Extbase models?
Thanks.
Okay, the answer to my last question is: Yes, there is no possibility to map tables without uid column with Extbase models.
There is an existing ticket on forge: http://forge.typo3.org/issues/25984
The reason seems to be the hardcoded $row['uid'] in mapSingleRow() method in Tx_Extbase_Persistence_Mapper_DataMapper class.
If it's not alot of tables you have to map, a work-around could be to create views for those tables to just map the uid.
I.e.:
CREATE VIEW tx_abc_domain_model_facility AS
SELECT facility_id AS uid, facilities.* FROM facilities;

Resources