Solr: Using custom functions in the Data Import Handler - plugins

I have successfully written a custom function and hooked it into my Solr engine. However, I am having problems passing parameters into that function from within the data-import.xml import definition file.
I have tried to methods, one which passes in a field from the current entity query, and the other approach which tries to use a variable from the last query...no seem to work.
Attempt 1: Pass in columns from current query:
<entity name="doc" query="SELECT id, date, ${dataimporter.functions.myfunc(id,date)} AS custom_value FROM Documents" />
This doesn't work as id and date seem to be passed in as literals, not the column values.
Attempt 2:
<entity name="doc" query="SELECT id, date FROM Documents">
<entity name="special" query="SELECT ${dataimporter.functions.myfunc(${doc.id}, ${doc.date})} AS custom_value" >
<field name="custom_value" column="custom_value" />
</entity>
</entity>
This doesn't work because it gets confused from the variable within the variable.
Any suggestions on how to make this work?

Try
<entity name="doc" query="SELECT id, date, ${dataimporter.functions.myfunc(doc.id,doc.date)} AS custom_value FROM Documents" />

An other way to generate custom_value is using transformer tag
in transformer_row you can add more column to the row or write custom function to transform if you want.

Related

Apache Solr DataImport succeed, but no result from query

I'm new at solr and trying to index database with solr 6.5.1 + postgresql.
Finally it looks successful to index the database.
DataImport screen shows
Indexing completed. Added/Updated: 0 documents. Deleted 0 documents. (Duration: 21m 13s)
Requests: 1 , Fetched: 19,736,915 15,504/s, Skipped: 0 , Processed: 0
Started: about an hour ago
However nothing is showing on Query screen when I pressed "Execute Query" button.
{
"responseHeader":{
"status":0,
"QTime":0,
"params":{
"q":"*:*",
"indent":"on",
"wt":"json",
"_":"1497333923963"}},
"response":{"numFound":0,"start":0,"docs":[]
}}
my database configuration (db-data-config.xml) is like as below.
<dataConfig>
<dataSource driver="org.postgresql.Driver" url="jdbc:postgresql://xxx.xx.xxx.xx:5432/xxxxx" user="xxxxx" password="xxx" />
<document>
<entity name="pubmed" query="select pmid, article_title, abstract from pubmed_xml">
<field column="pmid" name="pmid" />
<field column="article_title" name="article_title" />
<field column="abstract" name="abstract" />
</entity>
</document>
</dataConfig>
Could you guys give me some tips for fixing this issue ?
Thank you in advance.
If you check your schema.xml file, you'll see an entry as follows: <uniqueKey>id</uniqueKey>. This defines the solr field id to be the unique field which is mandatory for all documents in the index. In case you want to use a different field, change the uniqueKey entry and ensure that that particular field (pmid in your case) is defined in the schema.
Anyway, I found the solution to fix it.
I changed the name 'pmid' to 'id' like this.
and it works fine.
It seems that 'id' is used as indexing key inside solr configuration.
please let me know whoever knows the reason.
thank you.

codefluent custom stored procedure

I have a custom stored procedure with in parameters that return fields of different tables how I can map this custom stored to an entity? I only want to use like a read only values for a report I don't want to save or something like that I try to add the extra fields to the most similar entity but when I execute the method in code the extra fields are null
Solution 1: Using a view
A view allows to aggregate data from different entities.
<Article>
<Id />
<Name />
<Lines typeName="LineCollection" />
<cf:method name="LoadArticlesByCommand" body="load(string commandName) from ArticleByCommand where CommandName = #commandName" />
<cf:view name="ArticleByCommand" autoLightweight="true">
<ArticleName expression="Name"/>
<ArticleQty expression="Lines.Quantity" />
<CommandName expression="Lines.Command.Name" />
</cf:view>
</Article>
<Command>
<Id />
<Name />
<Lines typeName="LineCollection" />
</Command>
<Line setType="List">
<Article typeName="Article" key="true" />
<Command typeName="Command" key="true" />
<Quantity typeName="int" />
</Line>
http://blog.codefluententities.com/2014/04/22/views-auto-lightweight-and-the-modeler/
https://www.softfluent.com/documentation/Views_PersistentViews.html
Solution 2: Using a lightweight entity
Instead of creating a view, you can can create a lightweight entity that contains only the properties used by the stored procedure.
<cf:entity name="Person" lightweight="true">
<cf:property name="FirstName" typeName="string" />
<cf:property name="lastName" typeName="string" />
<cf:method name="ComputeBalance"
body="load () raw"
rawBody="SELECT 'John' AS FirstName, 'Doe' AS LastName" />
</cf:entity>
Solution 3: Custom mapping
For more specific values or types, a custom method can be provided to map the database values to .NET types. This custom method will be called with a DataReader as parameter, meaning that a developer could do whatever he wants.
<cf:entity name="Sample">
<cf:method name="LoadPair" body="raw" rawBody="SELECT 1234,5678"
returnTypeName="CodeFluent.Runtime.Utilities.Pair<System.Int32,System.Int32>"
cfom:methodName="On{0}" />
<cf:snippet>
private static CodeFluent.Runtime.Utilities.Pair<int,int> OnLoadPair(System.Data.IDataReader reader)
{
return new Pair<int, int>(reader.GetInt32(0), reader.GetInt32(1));
}
</cf:snippet>
</cf:entity>
You can also use OnAfterReadRecord or OnBeforeReadRecord rules
If it is not essential that you map the results of the custom stored procedure to an entity than another option is to use the built in support for DataSets.
http://blog.codefluententities.com/2011/06/22/dataset-support-in-codefluent-entities/
<cf:method name="LoadAllCities" body="raw" returnTypeName="System.Data.DataSet">
SELECT $Address::City$ FROM $Address$
</cf:method>
.
DataSet ds = Address.LoadAllCities();
foreach (DataTable table in ds.Tables)
{
foreach (DataRow row in table.Rows)
{
Console.WriteLine("City: " + row[0]);
}
}
Upon re-reading you're question I am providing another answer.
In response to the part where you said "I try to add the extra fields to the most similar entity but when I execute the method in code the extra fields are null". The following steps should be able to solve that problem.
Execute one of the automatically created stored procedure in SQL Management Studio.
Execute the stored procedure you manually created.
Verify that the fieldnames returned by both stored procedures match.
I think the above will solve your immediate problem but I still don't like the solution. The reason is that you said you picked the most similar entity. I think that is going to cause problems in the future especially if the stored procedure is not being mapped to all of the entities properties.
I would recommend either lightweight entity, view or DataSet.

ODK Dynamic select from database, how to handle empty list

I have an ODK form that is configured to get a list of data from the database and use that list of data for the select.
Problem is that I am not able to display an error for when the query from the database returns an empty string, instead, ODK form crashes while loading. I have tried this,
<instance id="books">
<list>
<g:if test="${Book.list()}">
<g:each in="${Book.list()}" var="book">
<book>
<id>${book.id}</id>
<name>${book.name?.encodeAsHTML()}</name>
</book>
</g:each>
</g:if>
<g:else>
<book>
<id></id>
<name></name>
</book>
</g:else>
</list>
</instance>
which creates an xml with an empty id and empty name. This makes sure that the ODK doesn't crash when it loads.
But since I don't want the user the select an empty book option, I added a constraint in the bind nodeset section,
<bind nodeset="/form/book" type="string" required="true()" constraint=". != ''" jr:constraintMsg="Book must be not be empty"/>
So now when the user tries to get past the book selection section the ODK form doesn't allow it, but instead of throwing the constraint message that I supplied it throws this error
don't know xml value! perhaps selection was stored as index only and has not yet been linked up to a formdef?

Recommended way to add a new entity to sylius core bundle?

Currently using:
base install of sylius-standard, for an ecommerce website.
Here is what I would like to accomplish :
Basically we know there is an User Entity which resides in
vendor/sylius/sylius/src/Sylius/Component/Core/Model/User.php
This Entity is actually extending the FOS\UserBundle\Model\User and it also has a linked UserInterface which is implementing FOS\UserBundle\Model\UserInterface.
My goal is to create another entity UserData which can be linked via the Doctrine OneToMany field relation to the above sylius User Entity which is basically the table sylius_user.
So effectively User Entity linked to UserData Entity via oneToMany ( For each user there can be multiple UserData entity instances.)
Sylius documentation (http://sylius.readthedocs.org) does not have anything related to adding an entity - If I am mistaken, please guide me to the correct links.
I have read overriding models at - > sylius models override also have gone through another sort of related question on stackoverflow How to create a new model with Sylius via SyliusResourceBundle but it is not clear as he is using the SyliusResourceBundle while I want to extend the SyliusCoreBundle (not sure if we can extend it in the first place or not)
How do I achieve this in the sylius framework ?
I solved the problems by reading segregated posts, so putting in here the solution for the community (please let me know if this is not the recommended way and the correct way if not):
My goal was to create a oneToMany doctrine relationship between
Sylius\Component\Core\Model\User
And
Acme\Bundle\Entity\UserData
which I had created. Basically for every user there could be multiple userdata instances pointing back to that user.
To do this, at first I followed the docs at sylius documentation
to override the sylius user class which is infact an extended class of fosuserbundle.
At some stage I kept getting the error [Doctrine\DBAL\Schema\SchemaException]
The table with name 'astrohealing_dev.sylius_user' already exists.
Based on Winzou's suggestion : To fix this error I changed the user class locations in sylius.yml (Sylius/Bundle/CoreBundle/Resources/config/app/sylius.yml) which is part of the core bundle and declared my own class as the user model like this :
This resolved the sylius_user table exists error
But then I got another error :
[Symfony\Component\Config\Definition\Exception\ForbiddenOverwriteException]
Configuration path "sylius_core.driver" cannot be overwritten. You have to define all options for this path, and any of its sub
-paths in one configuration section.
Next I commented out drive : doctrine/orm line for the relevant entry in
app/config/config.yml
sylius_core:
# driver: doctrine/orm
classes:
user:
model: Acme\Bundle\Entity\User
sylius_resource:
resources:
sylius.userdata:
driver: doctrine/orm
classes:
model: Acme\Bundle\Entity\UserData
The above few lines also show :
The override for sylius_core with my new User class
The new resource - which is bascially just the userdata class
Now for the Doctrine Mapping (User.orm.xml):
<?xml version="1.0" encoding="UTF-8"?>
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
<entity name="Acme\Bundle\Entity\User" table="sylius_user">
<one-to-many
field="userdata"
target-entity="Acme\Bundle\Entity\UserData"
mapped-by="userid" />
</entity>
</doctrine-mapping>
And the mapping for UserData (UserData.orm.xml)
<?xml version="1.0" encoding="UTF-8" ?>
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
<entity name="Acme\Bundle\Entity\UserData" table="sylius_userdata">
<id name="id" type="integer">
<generator strategy="AUTO" />
</id>
<many-to-one
field="userid"
target-entity="Acme\Bundle\Entity\User"
inversed-by="userdata"
join-column="userid">
<join-column name="user_id" referenced-column-name="id" nullable="false" />
</many-to-one>
<field name="name" type="string" length="150" />
<field name="datetime" type="datetime" />
</entity>
</doctrine-mapping>

Decimal output parameter rounded to integer in EF5.0

We are using existing database stored procedure similar to the one below that returns decimal output,
CREATE PROCEDURE spTest(#a int, #b decimal(18,2) output)
as
BEGIN
SELECT #b=23.22
SELECT * FROM <TABLE> where id = #a
END
When I call the stored procedure in in C# app (code below) I get the result for the output parameter as 23 instead of 23.22
ObjectParameter b = new ObjectParameter("b", typeof(System.Decimal))
var result = myentities.context.spTest(1234, b)
This exactly the same issue posted by Imre Horvath (http://social.msdn.microsoft.com/Forums/en-US/14bdde82-c084-44dd-ad83-c1305cb966d2/decimal-output-parameter-rounded-to-integer) but the difference is we are using SQL Server 2008 and entity framework 5.0. After reading the suggestion from his post I have opened the edmx file in xml editor and noticed the following for the output parameter #b as below,
<Parameter Name="b" Type="decimal" Mode="InOut"/>;
I changed it to
<Parameter Name="b" Type="decimal" Mode="InOut" Precision="18" Scale="2"/>;
and run the application and I got the result as expected (23.22)
This is a work around but not a solution as you know that changes will be lost when we update the stored procedure in the entity framework designer. In our database we have lots of stored procedure that has decimal(18,2) as output parameter. I'm wondering whether this still an issue in entity framework 5.0.
Your help will be much appreciated.
Kumar
I got the same issue with you and I have resolved it after I referenced from this article http://tiku.io/questions/1120572/decimal-output-parameter-rounded-to-integer-in-ef5-0
There is 3 steps to resolve this issue:
Right click on edmx file => Open with... => XML (text) Editor.
search text <Parameter Name="b" Type="numeric" Mode="InOut" /> then replace it by <Parameter Name="b" Type="numeric" Mode="InOut" Precision="20" Scale="2" />
search text <Parameter Name="b" Mode="InOut" Type="Decimal" /> then replace it by <Parameter Name="b" Mode="InOut" Type="Decimal" Precision="20" Scale="2" />
Hope this will help you!
In EF6, I got the same problem !
But find a simple solution.
I try to set the output ObjectParameter value,
then return the decimal with scale, like 5602.86
public decimal GetQuotationAmount(string rec_id, decimal price)
{
ObjectParameter qTA_AMT = new ObjectParameter("QTA_AMT", typeof(decimal));
qTA_AMT.Value = 100000.00m;
db.GRP_Calc_QuotationAmount(rec_id, price,qTA_AMT);
return Convert.ToDecimal(qTA_AMT.Value);
}
No, this is not fixed in EF 5.0 It probably won't be fixed in 6.0 either.
UPDATE:
I have recently updated to EF 6.0, and no, the problem is still not fixed. I guess that EF 6.0 is now Open Source so you could always patch it yourself if you are into that kind of thing.